pythonpyqt4

Python PyQt4 functions to save and restore UI widget values?


Before I attempt to write my own Python PyQt4 module functions... I wanted to ask if anyone has such a function to share.

In many of my python programs where I have a GUI built using PyQt4 and qtDesigner, I use the QSettings method to save and restore UI states and values of all widgets during close and startup.

This example shows how I save and restore some lineEdit, checkBox, and radioButton fields.

Does anyone have a function that can traverse the UI and find ALL widgets/controls and their states and save them (e.g. guisave()) and another function that can restore them (e.g. guirestore())?

My closeEvent looks something like this:

#---------------------------------------------
# close by x OR call to self.close
#---------------------------------------------

def closeEvent(self, event):      # user clicked the x or pressed alt-F4...

    UI_VERSION = 1   # increment this whenever the UI changes significantly

    programname = os.path.basename(__file__)
    programbase, ext = os.path.splitext(programname)  # extract basename and ext from filename
    settings = QtCore.QSettings("company", programbase)    
    settings.setValue("geometry", self.saveGeometry())  # save window geometry
    settings.setValue("state", self.saveState(UI_VERSION))   # save settings (UI_VERSION is a constant you should increment when your UI changes significantly to prevent attempts to restore an invalid state.)

    # save ui values, so they can be restored next time
    settings.setValue("lineEditUser", self.lineEditUser.text());
    settings.setValue("lineEditPass", self.lineEditPass.text());

    settings.setValue("checkBoxReplace", self.checkBoxReplace.checkState());
    settings.setValue("checkBoxFirst", self.checkBoxFirst.checkState());

    settings.setValue("radioButton1", self.radioButton1.isChecked());

    sys.exit()  # prevents second call

My MainWindow init looks something like this:

def __init__(self, parent = None):
    # initialization of the superclass
    super(QtDesignerMainWindow, self).__init__(parent)
    # setup the GUI --> function generated by pyuic4
    self.setupUi(self)

    #---------------------------------------------
    # restore gui position and restore fields
    #---------------------------------------------

    UI_VERSION = 1

    settings = QtCore.QSettings("company", programbase)    # http://pyqt.sourceforge.net/Docs/PyQt4/pyqt_qsettings.html

    self.restoreGeometry(settings.value("geometry"))
    self.restoreState(settings.value("state"),UI_VERSION) 

    self.lineEditUser.setText(str(settings.value("lineEditUser")))  # restore lineEditFile
    self.lineEditPass.setText(str(settings.value("lineEditPass")))  # restore lineEditFile

    if settings.value("checkBoxReplace") != None:
        self.checkBoxReplace.setCheckState(settings.value("checkBoxReplace"))   # restore checkbox
    if settings.value("checkBoxFirst") != None:
        self.checkBoxFirst.setCheckState(settings.value("checkBoxFirst"))   # restore checkbox

    value = settings.value("radioButton1").toBool()
    self.ui.radioButton1.setChecked(value)

Solution

  • OK, I wrote a module with 2 functions to do what I was asking for. Not really that complicated, once I figured it out, but it sure does save a lot of time whenever you create new pyqt gui programs where you want to save widget field values between sessions. I currently only have lineEdit, checkBox and combobox fields coded. If anyone else wants to add or improve (e.g. radio buttons...etc) ... I'm sure others, including myself, will appreciate it.

    #===================================================================
    # Module with functions to save & restore qt widget values
    # Written by: Alan Lilly 
    # Website: http://panofish.net
    #===================================================================
    
    import sys
    from PyQt4.QtCore import *
    from PyQt4.QtGui import *
    import inspect
    
    #===================================================================
    # save "ui" controls and values to registry "setting"
    # currently only handles comboboxes editlines & checkboxes
    # ui = qmainwindow object
    # settings = qsettings object
    #===================================================================
    
    def guisave(ui, settings):
    
        #for child in ui.children():  # works like getmembers, but because it traverses the hierarachy, you would have to call guisave recursively to traverse down the tree
    
        for name, obj in inspect.getmembers(ui):
            #if type(obj) is QComboBox:  # this works similar to isinstance, but missed some field... not sure why?
            if isinstance(obj, QComboBox):
                name   = obj.objectName()      # get combobox name
                index  = obj.currentIndex()    # get current index from combobox
                text   = obj.itemText(index)   # get the text for current index
                settings.setValue(name, text)   # save combobox selection to registry
    
            if isinstance(obj, QLineEdit):
                name = obj.objectName()
                value = obj.text()
                settings.setValue(name, value)    # save ui values, so they can be restored next time
    
            if isinstance(obj, QCheckBox):
                name = obj.objectName()
                state = obj.checkState()
                settings.setValue(name, state)
    
    #===================================================================
    # restore "ui" controls with values stored in registry "settings"
    # currently only handles comboboxes, editlines &checkboxes
    # ui = QMainWindow object
    # settings = QSettings object
    #===================================================================
    
    def guirestore(ui, settings):
    
        for name, obj in inspect.getmembers(ui):
            if isinstance(obj, QComboBox):
                index  = obj.currentIndex()    # get current region from combobox
                #text   = obj.itemText(index)   # get the text for new selected index
                name   = obj.objectName()
    
                value = unicode(settings.value(name))  
    
                if value == "":
                    continue
    
                index = obj.findText(value)   # get the corresponding index for specified string in combobox
    
                if index == -1:  # add to list if not found
                    obj.insertItems(0,[value])
                    index = obj.findText(value)
                    obj.setCurrentIndex(index)
                else:
                    obj.setCurrentIndex(index)   # preselect a combobox value by index    
    
            if isinstance(obj, QLineEdit):
                name = obj.objectName()
                value = unicode(settings.value(name))  # get stored value from registry
                obj.setText(value)  # restore lineEditFile
    
            if isinstance(obj, QCheckBox):
                name = obj.objectName()
                value = settings.value(name)   # get stored value from registry
                if value != None:
                    obj.setCheckState(value)   # restore checkbox
    
            #if isinstance(obj, QRadioButton):                
    
    ################################################################
    
    if __name__ == "__main__":
    
        # execute when run directly, but not when called as a module.
        # therefore this section allows for testing this module!
    
        #print "running directly, not as a module!"
    
        sys.exit()