Showing posts with label Qt Application Example. Show all posts
Showing posts with label Qt Application Example. Show all posts

Thursday, January 26, 2012

Qt 4.8 Application Example - Part 1

This is a walk through of a conversion from C++ to PyQt4 of the Qt Developer Network Application Example.  The original example isn't broken up into parts the way the tutorials were; it is broken up here to make the conversion easier to follow.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
    
    The Application example shows how to implement a standard GUI application 
    with menus, toolbars, and a status bar. The example itself is a simple text 
    editor program built around QPlainTextEdit.
    
    NOTES:
    =====
    This is based on an 'example' vs a tutorial however I'm splitting
    up the steps to make them easier to process.
    
    This first pass handles setting up the application class based on 
    the examples C++ 'include' file: mainwindow.h. Empty slots and methods are 
    defined creating skeleton code. 
    
    The basic logic for building the application is laid out in the '__init__()' 
    method.
    
    Class attributes will be created as the slots/methods are implemented.
    
last modified: 2012-01-25 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application-mainwindow-h.html
'''
import sys
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit)
from PyQt4.QtCore import (pyqtSlot)

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initiase base class
        super(MainWindow, self).__init__(parent)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        pass

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        pass

    @pyqtSlot()
    def _open(self):
        pass

    @pyqtSlot()
    def _save(self):
        pass

    @pyqtSlot()
    def _saveAs(self):
        pass

    @pyqtSlot()
    def _about(self):
        pass

    @pyqtSlot()
    def _documentWasModified(self):
        pass

    # private methods ---------------------------------------------------------
    def _createActions(self):
        pass

    def _createMenus(self):
        pass

    def _createToolBars(self):
        pass

    def _createStatusBar(self):
        pass

    def _readSettings(self):
        pass

    def _writeSettings(self):
        pass

    def _maybeSave(self):
        pass

    def _loadFile(self, fname):
        pass

    def _saveFile(self, fname):
        pass

    def _setCurrentFile(self, fname):
        pass

    def _strippedName(self, fullFName):
        pass

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")

    mw = MainWindow()
    mw.setWindowTitle("Application Example")
    mw.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Qt 4.8 Application Example - Part 2

In this step the application interface doesn't look as if anything has changed; however, the resource icons and application.qrc files have been saved and compiled using the pyrcc4 utility (see comments at the head of the code for step by step instructions) and the createActions() method has been implemented.


#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
    
    Before we can implement 'createActions()': 
    
    1. save the application icons to an 'images' directory within 
       your source file directory
    2. save the 'application.qrc' file in your source directory
    3. compile the 'application.qrc' file using the 'pyrcc4'
       utility that installs with PyQt4:
           pyrcc4 -py3 -o qrc_app.py application.qrc
    4. import the newly created 'qrc_app' file
    5. implement 'createActions()'
    
    BEHAVIOUR:
    =========
    It looks as if nothing has changed but you want to
    make sure everything complies ok.
    
    NOTES:
    =====
    Had to move the creation of the 'self._textEdit' widget to
    the beginning of the '__init__' method to make it available
    during later method calls. 
    
last modified: 2012-01-25 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
    http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/resources.html
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application-application-qrc.html
'''
import sys
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit, QAction, QIcon, QKeySequence)
from PyQt4.QtCore import (pyqtSlot)
import qrc_app

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initialise base class
        super(MainWindow, self).__init__(parent)

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        pass

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        pass

    @pyqtSlot()
    def _open(self):
        pass

    @pyqtSlot()
    def _save(self):
        pass

    @pyqtSlot()
    def _saveAs(self):
        pass

    @pyqtSlot()
    def _about(self):
        pass

    @pyqtSlot()
    def _documentWasModified(self):
        pass

    # private methods ---------------------------------------------------------
    def _createActions(self):
        self._newAct = QAction(QIcon(":/images/new.png"), self.tr("&New"), self)
        self._newAct.setShortcuts(QKeySequence.New)
        self._newAct.setStatusTip((self.tr("Create a new file.")))
        self._newAct.triggered.connect(self._newFile)

        self._openAct = QAction(QIcon(":/images/open.png"), self.tr("&Open"), self)
        self._openAct.setShortcuts(QKeySequence.Open)
        self._openAct.setStatusTip((self.tr("Open a file.")))
        self._openAct.triggered.connect(self._open)

        self._saveAct = QAction(QIcon(":/images/save.png"), self.tr("&Save"), self)
        self._saveAct.setShortcuts(QKeySequence.Save)
        self._saveAct.setStatusTip((self.tr("Save the document to disk.")))
        self._saveAct.triggered.connect(self._save)

        self._saveAsAct = QAction(self.tr("Save &As..."), self)
        self._saveAsAct.setShortcuts(QKeySequence.SaveAs)
        self._saveAsAct.setStatusTip((self.tr("Save the document under a new name.")))
        self._saveAsAct.triggered.connect(self._saveAs)

        self._exitAct = QAction(self.tr("E&xit"), self)
        self._exitAct.setShortcuts(QKeySequence.Quit)
        self._exitAct.setStatusTip((self.tr("Exit the application.")))
        self._exitAct.triggered.connect(self.close)

        self._aboutAct = QAction(self.tr("&About"), self)
        self._aboutAct.setStatusTip((self.tr("Show the application's About box.")))
        self._aboutAct.triggered.connect(self._about)

        self._aboutQtAct = QAction(self.tr("About &Qt"), self)
        self._aboutQtAct.setStatusTip((self.tr("Show the Qt library's About box.")))
        self._aboutQtAct.triggered.connect(QApplication.instance().aboutQt)

        # actions that connect to the 'textEdit' widget
        self._cutAct = QAction(QIcon(":/images/cut.png"), self.tr("Cu&t"), self)
        self._cutAct.setShortcuts(QKeySequence.Cut)
        self._cutAct.setStatusTip((self.tr("Cut the current selection's content to the clipboard.")))
        self._cutAct.triggered.connect(self._textEdit.cut)

        self._copyAct = QAction(QIcon(":/images/copy.png"), self.tr("&Copy"), self)
        self._copyAct.setShortcuts(QKeySequence.Copy)
        self._copyAct.setStatusTip((self.tr("Copy the current selection's content to the clipboard.")))
        self._copyAct.triggered.connect(self._textEdit.copy)

        self._pasteAct = QAction(QIcon(":/images/paste.png"), self.tr("&Paste"), self)
        self._pasteAct.setShortcuts(QKeySequence.Paste)
        self._pasteAct.setStatusTip((self.tr("Paste the clipboard contents into the current selection.")))
        self._pasteAct.triggered.connect(self._textEdit.paste)

        # set action visibility
        self._cutAct.setEnabled(False)
        self._copyAct.setEnabled((False))
        self._textEdit.copyAvailable.connect(self._cutAct.setEnabled)
        self._textEdit.copyAvailable.connect(self._copyAct.setEnabled)


    def _createMenus(self):
        pass

    def _createToolBars(self):
        pass

    def _createStatusBar(self):
        pass

    def _readSettings(self):
        pass

    def _writeSettings(self):
        pass

    def _maybeSave(self):
        pass

    def _loadFile(self, fname):
        pass

    def _saveFile(self, fname):
        pass

    def _setCurrentFile(self, fname):
        pass

    def _strippedName(self, fullFName):
        pass

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")

    mw = MainWindow()
    mw.setWindowTitle("Application Example")
    mw.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Qt 4.8 Application Example - Part 3

In the following code, the createMenus(), createToolBars() and createStatusBar() methods are implemented, using the actions created in Part 2.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
    
        Implement createMenus(), createToolBars(), createStatusBar()
    
    BEHAVIOUR:
    =========
    The menus and toolbar icons are now available.
    Move the mouse over them to see their tooltips displayed
    in the window status bar.
    
    NOTES:
    =====
    The menus and toolbar share the QAction objects created
    earlier.
    
last modified: 2012-01-25 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
'''
import sys
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit, QAction, QIcon, QKeySequence)
from PyQt4.QtCore import (pyqtSlot)
import qrc_app

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initialise base class
        super(MainWindow, self).__init__(parent)

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        pass

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        pass

    @pyqtSlot()
    def _open(self):
        pass

    @pyqtSlot()
    def _save(self):
        pass

    @pyqtSlot()
    def _saveAs(self):
        pass

    @pyqtSlot()
    def _about(self):
        pass

    @pyqtSlot()
    def _documentWasModified(self):
        pass

    # private methods ---------------------------------------------------------
    def _createActions(self):
        self._newAct = QAction(QIcon(":/images/new.png"), self.tr("&New"), self)
        self._newAct.setShortcuts(QKeySequence.New)
        self._newAct.setStatusTip((self.tr("Create a new file.")))
        self._newAct.triggered.connect(self._newFile)

        self._openAct = QAction(QIcon(":/images/open.png"), self.tr("&Open"), self)
        self._openAct.setShortcuts(QKeySequence.Open)
        self._openAct.setStatusTip((self.tr("Open a file.")))
        self._openAct.triggered.connect(self._open)

        self._saveAct = QAction(QIcon(":/images/save.png"), self.tr("&Save"), self)
        self._saveAct.setShortcuts(QKeySequence.Save)
        self._saveAct.setStatusTip((self.tr("Save the document to disk.")))
        self._saveAct.triggered.connect(self._save)

        self._saveAsAct = QAction(self.tr("Save &As..."), self)
        self._saveAsAct.setShortcuts(QKeySequence.SaveAs)
        self._saveAsAct.setStatusTip((self.tr("Save the document under a new name.")))
        self._saveAsAct.triggered.connect(self._saveAs)

        self._exitAct = QAction(self.tr("E&xit"), self)
        self._exitAct.setShortcuts(QKeySequence.Quit)
        self._exitAct.setStatusTip((self.tr("Exit the application.")))
        self._exitAct.triggered.connect(self.close)

        self._aboutAct = QAction(self.tr("&About"), self)
        self._aboutAct.setStatusTip((self.tr("Show the application's About box.")))
        self._aboutAct.triggered.connect(self._about)

        self._aboutQtAct = QAction(self.tr("About &Qt"), self)
        self._aboutQtAct.setStatusTip((self.tr("Show the Qt library's About box.")))
        self._aboutQtAct.triggered.connect(QApplication.instance().aboutQt)

        # actions that connect to the 'textEdit' widget
        self._cutAct = QAction(QIcon(":/images/cut.png"), self.tr("Cu&t"), self)
        self._cutAct.setShortcuts(QKeySequence.Cut)
        self._cutAct.setStatusTip((self.tr("Cut the current selection's content to the clipboard.")))
        self._cutAct.triggered.connect(self._textEdit.cut)

        self._copyAct = QAction(QIcon(":/images/copy.png"), self.tr("&Copy"), self)
        self._copyAct.setShortcuts(QKeySequence.Copy)
        self._copyAct.setStatusTip((self.tr("Copy the current selection's content to the clipboard.")))
        self._copyAct.triggered.connect(self._textEdit.copy)

        self._pasteAct = QAction(QIcon(":/images/paste.png"), self.tr("&Paste"), self)
        self._pasteAct.setShortcuts(QKeySequence.Paste)
        self._pasteAct.setStatusTip((self.tr("Paste the clipboard contents into the current selection.")))
        self._pasteAct.triggered.connect(self._textEdit.paste)

        # set action visibility
        self._cutAct.setEnabled(False)
        self._copyAct.setEnabled((False))
        self._textEdit.copyAvailable.connect(self._cutAct.setEnabled)
        self._textEdit.copyAvailable.connect(self._copyAct.setEnabled)

    def _createMenus(self):
        fileMenu = self.menuBar().addMenu(self.tr("&File"))
        fileMenu.addAction(self._newAct)
        fileMenu.addAction(self._openAct)
        fileMenu.addAction(self._saveAct)
        fileMenu.addAction(self._saveAsAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self._exitAct)

        editMenu = self.menuBar().addMenu(self.tr("&Edit"))
        editMenu.addAction(self._cutAct)
        editMenu.addAction(self._copyAct)
        editMenu.addAction(self._pasteAct)

        self.menuBar().addSeparator()

        helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        helpMenu.addAction(self._aboutAct)
        helpMenu.addAction(self._aboutQtAct)


    def _createToolBars(self):
        fileToolBar = self.addToolBar(self.tr("File"))
        fileToolBar.addAction(self._newAct)
        fileToolBar.addAction(self._openAct)
        fileToolBar.addAction(self._saveAct)

        editToolBar = self.addToolBar(self.tr("Edit"))
        editToolBar.addAction(self._cutAct)
        editToolBar.addAction(self._copyAct)
        editToolBar.addAction(self._pasteAct)

    def _createStatusBar(self):
        self.statusBar().showMessage(self.tr("Ready"))

    def _readSettings(self):
        pass

    def _writeSettings(self):
        pass

    def _maybeSave(self):
        pass

    def _loadFile(self, fname):
        pass

    def _saveFile(self, fname):
        pass

    def _setCurrentFile(self, fname):
        pass

    def _strippedName(self, fullFName):
        pass

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")

    mw = MainWindow()
    mw.setWindowTitle("Application Example")
    mw.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

Qt 4.8 Application Example - Part 4

In the following code a number of related methods have been implemented: _readSettings(), _writeSettings(), _setCurrentFileName(), closeEvent(), _save(), _saveAs() , _maybeSave(), _saveFile()

There were a few problems; for one, Where were the settings being written? Turns out the default under Windows is the Windows Registry; I re-wrote the code to create the settings as an .ini file.

Another problem was the handing of the Window title and what happens to it when the document is modified?  It is not working correctly, but I did eventually figure it out ... in Part 5.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
     
        Implement the last two methods called by '__init__()':
            _readSettings()
            _setCurrentFileName()
     
        Implement closeEvent(),  _maybeSave(), _save(), _saveAs(), 
            _saveFile(), _writeSettings()
     
    BEHAVIOUR:
    =========
    On starting the application, saved settings are restored.
     
    When the application is closed, if there are any pending
    changes to the document, the user is prompted to save them.
     
    The application position and size are saved and the 
    application exits.
     
    NOTES:
    =====
    Re-wrote the way 'settings' were being handled. The
    default in Windows is to update the Windows register. Prefer
    to use an .ini file. Key change is code added to __init__()
    where a 'settings' attribute is created using the QSettings
    default method after setting the QSettings format to IniFormat.
    The default call takes the application name and organization
    from values defined in main(). Note that the application version
    is ignored. On Windows, the .ini file is named "Application Example.ini"
    in path:
        user/appdata/local/my business  [may show up in 'roaming' 
    
    The implemented methods are connected:
        closeEvent() calls maybeSave() 
        which calls save() which may call saveAs()
        both save() and saveAs() call saveFile()
        
    There is a problem with the window title, it is not
    being set. 
    
    There is also a problem on exiting, asked to save
    even though the document hasn't been modified.
         
last modified: 2012-01-25 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
'''
import sys, os
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit, QAction,
                         QIcon, QKeySequence, QFileDialog, QMessageBox)
from PyQt4.QtCore import (pyqtSlot, QSettings, QPoint, QSize)
import qrc_app

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initialise base class
        super(MainWindow, self).__init__(parent)

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # create application settings object
        QSettings.setDefaultFormat(QSettings.IniFormat)
        self._settings = QSettings()

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        if self._maybeSave():
            self._writeSettings()
            evt.accept()
        else:
            evt.ignore()

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        pass

    @pyqtSlot()
    def _open(self):
        pass

    @pyqtSlot()
    def _save(self):
        if not self._curFile:
            return self._saveAs()
        else:
            return self._saveFile(self._curFile)

    @pyqtSlot()
    def _saveAs(self):
        fname = QFileDialog.getSaveFileName(self)
        if not fname:
            return False

        return self._saveFile(fname)

    @pyqtSlot()
    def _about(self):
        pass

    @pyqtSlot()
    def _documentWasModified(self):
        pass

    # private methods ---------------------------------------------------------
    def _createActions(self):
        self._newAct = QAction(QIcon(":/images/new.png"), self.tr("&New"), self)
        self._newAct.setShortcuts(QKeySequence.New)
        self._newAct.setStatusTip((self.tr("Create a new file.")))
        self._newAct.triggered.connect(self._newFile)

        self._openAct = QAction(QIcon(":/images/open.png"), self.tr("&Open"), self)
        self._openAct.setShortcuts(QKeySequence.Open)
        self._openAct.setStatusTip((self.tr("Open a file.")))
        self._openAct.triggered.connect(self._open)

        self._saveAct = QAction(QIcon(":/images/save.png"), self.tr("&Save"), self)
        self._saveAct.setShortcuts(QKeySequence.Save)
        self._saveAct.setStatusTip((self.tr("Save the document to disk.")))
        self._saveAct.triggered.connect(self._save)

        self._saveAsAct = QAction(self.tr("Save &As..."), self)
        self._saveAsAct.setShortcuts(QKeySequence.SaveAs)
        self._saveAsAct.setStatusTip((self.tr("Save the document under a new name.")))
        self._saveAsAct.triggered.connect(self._saveAs)

        self._exitAct = QAction(self.tr("E&xit"), self)
        self._exitAct.setShortcuts(QKeySequence.Quit)
        self._exitAct.setStatusTip((self.tr("Exit the application.")))
        self._exitAct.triggered.connect(self.close)

        self._aboutAct = QAction(self.tr("&About"), self)
        self._aboutAct.setStatusTip((self.tr("Show the application's About box.")))
        self._aboutAct.triggered.connect(self._about)

        self._aboutQtAct = QAction(self.tr("About &Qt"), self)
        self._aboutQtAct.setStatusTip((self.tr("Show the Qt library's About box.")))
        self._aboutQtAct.triggered.connect(QApplication.instance().aboutQt)

        # actions that connect to the 'textEdit' widget
        self._cutAct = QAction(QIcon(":/images/cut.png"), self.tr("Cu&t"), self)
        self._cutAct.setShortcuts(QKeySequence.Cut)
        self._cutAct.setStatusTip((self.tr("Cut the current selection's content to the clipboard.")))
        self._cutAct.triggered.connect(self._textEdit.cut)

        self._copyAct = QAction(QIcon(":/images/copy.png"), self.tr("&Copy"), self)
        self._copyAct.setShortcuts(QKeySequence.Copy)
        self._copyAct.setStatusTip((self.tr("Copy the current selection's content to the clipboard.")))
        self._copyAct.triggered.connect(self._textEdit.copy)

        self._pasteAct = QAction(QIcon(":/images/paste.png"), self.tr("&Paste"), self)
        self._pasteAct.setShortcuts(QKeySequence.Paste)
        self._pasteAct.setStatusTip((self.tr("Paste the clipboard contents into the current selection.")))
        self._pasteAct.triggered.connect(self._textEdit.paste)

        # set action visibility
        self._cutAct.setEnabled(False)
        self._copyAct.setEnabled((False))
        self._textEdit.copyAvailable.connect(self._cutAct.setEnabled)
        self._textEdit.copyAvailable.connect(self._copyAct.setEnabled)

    def _createMenus(self):
        fileMenu = self.menuBar().addMenu(self.tr("&File"))
        fileMenu.addAction(self._newAct)
        fileMenu.addAction(self._openAct)
        fileMenu.addAction(self._saveAct)
        fileMenu.addAction(self._saveAsAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self._exitAct)

        editMenu = self.menuBar().addMenu(self.tr("&Edit"))
        editMenu.addAction(self._cutAct)
        editMenu.addAction(self._copyAct)
        editMenu.addAction(self._pasteAct)

        self.menuBar().addSeparator()

        helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        helpMenu.addAction(self._aboutAct)
        helpMenu.addAction(self._aboutQtAct)


    def _createToolBars(self):
        fileToolBar = self.addToolBar(self.tr("File"))
        fileToolBar.addAction(self._newAct)
        fileToolBar.addAction(self._openAct)
        fileToolBar.addAction(self._saveAct)

        editToolBar = self.addToolBar(self.tr("Edit"))
        editToolBar.addAction(self._cutAct)
        editToolBar.addAction(self._copyAct)
        editToolBar.addAction(self._pasteAct)

    def _createStatusBar(self):
        self.statusBar().showMessage(self.tr("Ready"))

    def _readSettings(self):
        pos = self._settings.value("pos", QPoint(200, 200))
        size = self._settings.value("size", QSize(400, 400))
        self.resize(size)
        self.move(pos)

    def _writeSettings(self):
        self._settings.setValue("pos", self.pos())
        self._settings.setValue("size", self.size())

    def _maybeSave(self):
        if self._textEdit.document().isModified:
            ret = QMessageBox.warning(
                        self,
                        self.tr("Application"),
                        self.tr("The document has been modified.\n"
                                "Do you want to save your changes?"),
                        QMessageBox.Save | QMessageBox.Discard |
                        QMessageBox.Cancel)
            if ret == QMessageBox.Save:
                return self._save()
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def _loadFile(self, fname):
        pass

    def _saveFile(self, fname):

        with open(fname, 'w') as f:
            f.write(self._textEdit.toPlainText())

        self._setCurrentFile(fname)
        self.statusBar().showMessage(self.tr("File saved."))
        return True

    def _setCurrentFile(self, fname):
        self._curFile = fname
        self._textEdit.document().setModified(False)
        self.setWindowModified(False)

        shownName = self._curFile
        if not self._curFile:
            shownName = "untitled.txt"
        self.setWindowFilePath(shownName)

    def _strippedName(self, fullFname):
        pass

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")
    app.setApplicationVersion("1.0")

    mw = MainWindow()
    mw.show()

    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

Qt 4.8 Application Example - Part 5

Finally figured out what was going on with the Window title; the string used in setting the title has to include a parameter [*], also need to use setWindowTitle(), not _setWindowFilePath(). Re-wrote _setCurrentFileName() and_strippedName(); implemented the remaining methods/slots and we're done.



#!/usr/bin/env python3
# -*- coding: utf-8 -*-

'''
    PyQt4 conversion of Qt Application Example
    
        Implement the remaining actions:
            _newFile(), _open(), _about(), _loadFile(), 
            _documentWasModified(), _strippedName()
    
        Re-write _setCurrentFile()
    
    BEHAVIOUR:
    =========
    When the open document is modified an asterisk appears
    by the file name in the Window title.
    
    When a new document is loaded, the Window title is updated
    to reflect the file name.
    
    All the Edit functions work.
    
    NOTES:
    =====
    _setCurrentFile() was re-written to use _setWindowTitle()
    rather than _setWindowFilePath(). 
    
    Used Python os.path rather than QFileInfo to get the file 
    name from the full path.
        
last modified: 2012-01-27 jg
ref: 
    http://developer.qt.nokia.com/doc/qt-4.8/mainwindows-application.html
'''
import sys, os
from PyQt4.QtGui import (QApplication, QMainWindow, QPlainTextEdit, QAction,
                         QIcon, QKeySequence, QFileDialog, QMessageBox)
from PyQt4.QtCore import (pyqtSlot, QSettings, QPoint, QSize)
import qrc_app

class MainWindow(QMainWindow):      # subclass QMainWindow

    def __init__(self, parent=None):    # initialise base class
        super(MainWindow, self).__init__(parent)

        # create central widget        
        self._textEdit = QPlainTextEdit()
        self.setCentralWidget(self._textEdit)

        # create GUI
        self._createActions()
        self._createMenus()
        self._createToolBars()
        self._createStatusBar()

        # connect signals/slots for event handling
        self._textEdit.document().contentsChanged.connect(self._documentWasModified)

        # create application settings object
        QSettings.setDefaultFormat(QSettings.IniFormat)
        self._settings = QSettings()

        # establish initial conditions
        self._readSettings()
        self._setCurrentFile('')
        self.setUnifiedTitleAndToolBarOnMac(True)
        self._newFile()                 # force the window title

    # overridden methods ------------------------------------------------------
    def closeEvent(self, evt):
        if self._maybeSave():
            self._writeSettings()
            evt.accept()
        else:
            evt.ignore()

    # private slots -----------------------------------------------------------
    @pyqtSlot()
    def _newFile(self):
        if self._maybeSave():
            self._textEdit.clear()
            self._setCurrentFile('untitled.txt')

    @pyqtSlot()
    def _open(self):
        if self._maybeSave():
            fname = QFileDialog.getOpenFileName(self)
            if fname:
                self._loadFile(fname)

    @pyqtSlot()
    def _save(self):
        if not self._curFile:
            return self._saveAs()
        else:
            return self._saveFile(self._curFile)

    @pyqtSlot()
    def _saveAs(self):
        fname = QFileDialog.getSaveFileName(self)
        if not fname:
            return False

        return self._saveFile(fname)

    @pyqtSlot()
    def _about(self):
        QMessageBox.about(self,
            self.tr("About Application"),
            self.tr("The Application example demonstrates\n"
                    "how to write modern GUI applications using Qt\n"
                    "with a menubar, toolbars, and a status bar."))

    @pyqtSlot()
    def _documentWasModified(self):
        self.setWindowModified(self._textEdit.document().isModified())

    # private methods ---------------------------------------------------------
    def _createActions(self):
        self._newAct = QAction(QIcon(":/images/new.png"), self.tr("&New"), self)
        self._newAct.setShortcuts(QKeySequence.New)
        self._newAct.setStatusTip((self.tr("Create a new file.")))
        self._newAct.triggered.connect(self._newFile)

        self._openAct = QAction(QIcon(":/images/open.png"), self.tr("&Open"), self)
        self._openAct.setShortcuts(QKeySequence.Open)
        self._openAct.setStatusTip((self.tr("Open a file.")))
        self._openAct.triggered.connect(self._open)

        self._saveAct = QAction(QIcon(":/images/save.png"), self.tr("&Save"), self)
        self._saveAct.setShortcuts(QKeySequence.Save)
        self._saveAct.setStatusTip((self.tr("Save the document to disk.")))
        self._saveAct.triggered.connect(self._save)

        self._saveAsAct = QAction(self.tr("Save &As..."), self)
        self._saveAsAct.setShortcuts(QKeySequence.SaveAs)
        self._saveAsAct.setStatusTip((self.tr("Save the document under a new name.")))
        self._saveAsAct.triggered.connect(self._saveAs)

        self._exitAct = QAction(self.tr("E&xit"), self)
        self._exitAct.setShortcuts(QKeySequence.Quit)
        self._exitAct.setStatusTip((self.tr("Exit the application.")))
        self._exitAct.triggered.connect(self.close)

        self._aboutAct = QAction(self.tr("&About"), self)
        self._aboutAct.setStatusTip((self.tr("Show the application's About box.")))
        self._aboutAct.triggered.connect(self._about)

        self._aboutQtAct = QAction(self.tr("About &Qt"), self)
        self._aboutQtAct.setStatusTip((self.tr("Show the Qt library's About box.")))
        self._aboutQtAct.triggered.connect(QApplication.instance().aboutQt)

        # actions that connect to the 'textEdit' widget
        self._cutAct = QAction(QIcon(":/images/cut.png"), self.tr("Cu&t"), self)
        self._cutAct.setShortcuts(QKeySequence.Cut)
        self._cutAct.setStatusTip((self.tr("Cut the current selection's content to the clipboard.")))
        self._cutAct.triggered.connect(self._textEdit.cut)

        self._copyAct = QAction(QIcon(":/images/copy.png"), self.tr("&Copy"), self)
        self._copyAct.setShortcuts(QKeySequence.Copy)
        self._copyAct.setStatusTip((self.tr("Copy the current selection's content to the clipboard.")))
        self._copyAct.triggered.connect(self._textEdit.copy)

        self._pasteAct = QAction(QIcon(":/images/paste.png"), self.tr("&Paste"), self)
        self._pasteAct.setShortcuts(QKeySequence.Paste)
        self._pasteAct.setStatusTip((self.tr("Paste the clipboard contents into the current selection.")))
        self._pasteAct.triggered.connect(self._textEdit.paste)

        # set action visibility
        self._cutAct.setEnabled(False)
        self._copyAct.setEnabled((False))
        self._textEdit.copyAvailable.connect(self._cutAct.setEnabled)
        self._textEdit.copyAvailable.connect(self._copyAct.setEnabled)

    def _createMenus(self):
        fileMenu = self.menuBar().addMenu(self.tr("&File"))
        fileMenu.addAction(self._newAct)
        fileMenu.addAction(self._openAct)
        fileMenu.addAction(self._saveAct)
        fileMenu.addAction(self._saveAsAct)
        fileMenu.addSeparator()
        fileMenu.addAction(self._exitAct)

        editMenu = self.menuBar().addMenu(self.tr("&Edit"))
        editMenu.addAction(self._cutAct)
        editMenu.addAction(self._copyAct)
        editMenu.addAction(self._pasteAct)

        self.menuBar().addSeparator()

        helpMenu = self.menuBar().addMenu(self.tr("&Help"))
        helpMenu.addAction(self._aboutAct)
        helpMenu.addAction(self._aboutQtAct)


    def _createToolBars(self):
        fileToolBar = self.addToolBar(self.tr("File"))
        fileToolBar.addAction(self._newAct)
        fileToolBar.addAction(self._openAct)
        fileToolBar.addAction(self._saveAct)

        editToolBar = self.addToolBar(self.tr("Edit"))
        editToolBar.addAction(self._cutAct)
        editToolBar.addAction(self._copyAct)
        editToolBar.addAction(self._pasteAct)

    def _createStatusBar(self):
        self.statusBar().showMessage(self.tr("Ready"))

    def _readSettings(self):
        pos = self._settings.value("pos", QPoint(200, 200))
        size = self._settings.value("size", QSize(400, 400))
        self.resize(size)
        self.move(pos)

    def _writeSettings(self):
        self._settings.setValue("pos", self.pos())
        self._settings.setValue("size", self.size())

    def _maybeSave(self):
        if self._textEdit.document().isModified():
            ret = QMessageBox.warning(
                        self,
                        self.tr("Application"),
                        self.tr("The document has been modified.\n"
                                "Do you want to save your changes?"),
                        QMessageBox.Save | QMessageBox.Discard |
                        QMessageBox.Cancel)
            if ret == QMessageBox.Save:
                return self._save()
            elif ret == QMessageBox.Cancel:
                return False

        return True

    def _loadFile(self, fname):
        with open(fname, 'r') as f:
            txt = f.read()
            self._textEdit.setPlainText(txt)

        self._setCurrentFile(fname)
        self.statusBar().showMessage(self.tr("File loaded."))

    def _saveFile(self, fname):

        with open(fname, 'w') as f:
            f.write(self._textEdit.toPlainText())

        self._setCurrentFile(fname)
        self.statusBar().showMessage(self.tr("File saved."))
        return True

    def _setCurrentFile(self, fname):

        self._curFile = fname
        self._textEdit.document().setModified(False)
        self.setWindowModified(False)

        self.setWindowTitle(self.tr("{0} [*] - Application Example".format(
                                self._strippedName(self._curFile))))

    def _strippedName(self, fullFname):
        return os.path.basename(fullFname)

# main ========================================================================
def main():
    app = QApplication(sys.argv)
    app.setOrganizationName("My Business")
    app.setApplicationName("Application Example")
    app.setApplicationVersion("1.0")

    mw = MainWindow()
    mw.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main()