#!/usr/bin/env python # -*- coding: utf-8 -*- ''' TheCodeInn PyQt4 Tutorial PyQt Calender App Author: Peter Goldsborough Website: http://thecodeinn.blogspot.com last edited: August 2013 ''' import sys, pickle from PyQt4 import QtGui, QtCore #some global variables dateStr = "" # will hold the date name = "" # will hold the name of an added event gridVar = 3 # will be used to extend the grid layout sender = "" # will hold the sender button's text s = "" # will hold the sender button itself e = open("events.txt","rb") #this try - except clause is there to prevent loading errors if events.txt is empty try: events = pickle.loads(e.read()) except: events = {} e.close() class Edit(QtGui.QDialog): def __init__(self,parent = None): QtGui.QDialog.__init__(self, parent) #this is the dialog that opens up if a specific event is clicked self.initUI() def initUI(self): global sender self.change = QtGui.QLabel("Change: ",self) self.change.move(5,7) self.line = QtGui.QLineEdit(self) self.line.move(65,5) self.line.setText(sender) self.delt = QtGui.QPushButton("Delete",self) self.delt.move(80,50) self.ok = QtGui.QPushButton("OK",self) self.ok.move(40,100) self.cancel = QtGui.QPushButton("Cancel",self) self.cancel.move(120,100) self.setGeometry(300,300,240,130) self.setWindowTitle("Edit event") self.setStyleSheet("font-size:14px;") class Main(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.initUI() def initUI(self): self.widget = QtGui.QWidget(self) self.cal = QtGui.QCalendarWidget(self) self.cal.setGridVisible(True) self.cal.clicked[QtCore.QDate].connect(self.showDate) self.cal.setStyleSheet("font-size:15px") self.upc = QtGui.QLabel(self) self.upc.setStyleSheet("font-size:16px;") self.Upcoming() date = self.cal.selectedDate().toString() self.lbl = QtGui.QLabel(date,self) self.lbl.setStyleSheet("font-size:16px;") self.add = QtGui.QPushButton("+ Add",self) self.add.clicked.connect(self.AddEvent) self.grid = QtGui.QGridLayout() self.spacer = QtGui.QSpacerItem(20, 30, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Fixed) self.grid.addWidget(self.cal,0,0,1,2) self.grid.addItem(self.spacer,2,0) self.grid.addWidget(self.upc,1,0) self.grid.addWidget(self.lbl,3,0) self.grid.addWidget(self.add,3,1) self.widget.setLayout(self.grid) #---------Window settings -------------------------------- self.setGeometry(300,300,400,400) self.setWindowTitle("PyCal") self.setCentralWidget(self.widget) #---------Slot functions -------------------------------- def Upcoming(self): #this function takes care of displaying a list of upcoming events count = 0 length = 0 upcoming = "Upcoming events: " if events: #if events is not empty for i in events.values(): #for every list of events for j in i: # for every event in these lists length += 1 while count < 2: #set it to a higher number if you want more items displayed for i in events.values(): for j in i: if length < 2: upcoming += j #if there is only one event, we append it to the string and immediately exit the while loop, without this it'd display an event twice if there was only one count = 2 else: upcoming += j+", " count += 1 else: upcoming += "None" #if there are no events, we display "None" self.upc.setText(upcoming) def Edit(self): # this function is called when an event is clicked, opening a QDialog that lets you edit the name or delete it global sender global s global events s = self.sender() #get the information from the sending button so we know which one it is, since they're generically created sender = s.text() edit = Edit(self) #modularly open the Edit QDialog edit.show() def Ok(): #if the name is changed, we save the new name and delete the old one events[dateStr].remove(s.text()) events[dateStr].append(edit.line.text()) e = open("events.txt","wb") pickle.dump(events,e) e.close() s.setText(edit.line.text()) self.Upcoming() edit.close() def Delete(): #if it is deleted, we have to delete it from the layout, this is done by that for loop down there for i in reversed(range(self.grid.count())): #the reversed is there since it'd mess up the layout otherwise try: if self.grid.itemAt(i).widget().text() == sender: self.grid.itemAt(i).widget().setParent(None) except: #you may wonder why I have a try - except clause here if I'm not doing anything when there's an exception, well, that's because the spacer #is a QItem, and that would mess up the self.grid.itemAt(i).widget() up there, since the spacer is an item, not a widget pass if len(events[dateStr]) > 1: #if there are more than one values for that day, we just remove this event events[dateStr].remove(sender) else: #if this was the day's last event we just deleted, it's good to delete the whole list, empty lists suck del events[dateStr] e = open("events.txt","wb") pickle.dump(events,e) e.close() self.Upcoming() #update the upcoming events edit.close() edit.delt.clicked.connect(Delete) edit.cancel.clicked.connect(lambda cancel: edit.close()) edit.ok.clicked.connect(Ok) def showDate(self, date): global dateStr global events global gridVar #from here eventStr = "" gridVar = 3 for i in reversed(range(self.grid.count())): try: self.grid.itemAt(i).widget().setParent(None) except: pass self.grid.addWidget(self.cal,0,0,1,2) self.grid.addItem(self.spacer,2,0) self.grid.addWidget(self.upc,1,0) self.grid.addWidget(self.lbl,3,0) self.grid.addWidget(self.add,3,1) self.setGeometry(300,300,400,400) #to here, we just reset the whole layout to the default - no events yet dateStr = date.toString() if dateStr in events: #now we get funky, so if the date is in the events dictionary for i in events[dateStr]: #we create a button for every event b = QtGui.QPushButton(i,self) b.setStyleSheet("border-radius:5px;font-size:16px;") b.clicked.connect(self.Edit) ''' If you wonder why the buttons aren't displayed like buttons, but like labels, yet still work like buttons (clickable), that's because I set the border radius to 1px up there in the StyleSheet. QPushButton doesn't seem to support border-radius modification so it just displays the button flat .. neat trick if you want a clickable qlabel! ''' self.grid.addWidget(b,gridVar,1) #extend the layout self.grid.addWidget(self.add,gridVar+1,1) gridVar +=1 self.lbl.setText(dateStr) def AddEvent(self): global dateStr global events global date name, ok = QtGui.QInputDialog.getText(self,"Add event", #here we call an input dialog to get the event's name "Name: ") if dateStr not in events: #if the date isn't in the events list yet, we create a new dictionary item events[dateStr] = [name] else: #if it is, we append it to the date's events list events[dateStr].append(name) e = open("events.txt","wb") pickle.dump(events,e) e.close() self.showDate(self.cal.selectedDate()) self.Upcoming() def main(): app = QtGui.QApplication(sys.argv) main= Main() main.show() print("I \N{black heart suit} Python") sys.exit(app.exec_()) if __name__ == "__main__": main()
Hope you like the easter egg in my program :)
No comments :
Post a Comment