When I last touched Python, I wrote a snippet to steal the latest comic off xkcd.com. Like most of the things that I do (this only applies to individual projects, not teamwork), there are long breaks until I make any progress. Probably it’s because I multi-task too much. At the same time, I never run out of things to do. Recently I’ve been blessed with a couple hours of fre etime, and so I’ve touched Python again, and decided it was time to learn some GUI.
Which toolkit? The Qt one of course (pronouned ‘cute’)! Powerful, cross-platform, native to KDE. Here’s my first (well first mentionable) GUI application coded with Python and the PyQt4 bindings. (Last mentionable GUI stuff was with VB6 – Yes, I did do application programming when I was 9 years old, childish programs they were, but mentionable).
The application is a simple text editor which supports opening/saving files, and warns you if you’ve made changes but haven’t saved yet. Yes, the process of making it was from a tutorial, though each step was figured out myself. Basically the tutorial says “Ok, now we’ll add a save button”, then I search the Python and PyQt4 documentation to figure out how, then cross reference my code with the tutorial. Here’s a screenshot:

For the geeky, here is the code:
import sys
from PyQt4 import QtCore, QtGui
from editor import Ui_notepad
class StartQT4(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_notepad()
self.ui.setupUi(self)
# Connect signals
QtCore.QObject.connect(self.ui.button_open,QtCore.SIGNAL("clicked()"), self.file_dialog)
QtCore.QObject.connect(self.ui.button_save,QtCore.SIGNAL("clicked()"), self.file_save)
QtCore.QObject.connect(self.ui.editor_window,QtCore.SIGNAL("textChanged()"), self.enable_save)
def file_dialog(self):
response = False
if self.ui.button_save.isEnabled() and self.filename:
message = QtGui.QMessageBox(self)
message.setIcon(QtGui.QMessageBox.Question)
message.addButton('Save', QtGui.QMessageBox.AcceptRole)
message.addButton('Discard', QtGui.QMessageBox.DestructiveRole)
message.addButton('Cancel', QtGui.QMessageBox.RejectRole)
message.setText('Do you want to save changes?')
message.setDetailedText('Unsaved changes in file: ' + str(self.filename))
message.setWindowTitle('Notepad')
message.exec_()
response = message.clickedButton().text()
if response == 'Save':
self.file_save()
self.ui.button_save.setEnabled(False)
elif response == 'Discard':
self.ui.button_save.setEnabled(False)
if response != 'Cancel':
fd = QtGui.QFileDialog(self)
self.filename = fd.getOpenFileName()
from os.path import isfile
if isfile(self.filename):
plik = open(self.filename).read()
self.ui.editor_window.setText(plik)
self.ui.button_save.setEnabled(False)
def file_save(self):
fd = QtGui.QFileDialog(self)
self.filename = fd.getSaveFileName()
from os.path import isfile
if isfile(self.filename):
plik = open(self.filename, 'w').write(self.ui.editor_window.toPlainText())
self.ui.button_save.setEnabled(False)
def enable_save(self):
self.ui.button_save.setEnabled(True)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = StartQT4()
myapp.show()
sys.exit(app.exec_())
Tada. You will also need another file called editor.py (click to download) in the same directory from which the UI information will be grabbed from.
Ok, next Python project will be more advanced, which’ll be a graphical game of solitaire featuring custom widgets and drag and drop functionality. Oooh. Tough.

