Python PyQt4 functions to save and restore UI widget values?

前端 未结 7 816
悲哀的现实
悲哀的现实 2020-12-04 13:50

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 hav

相关标签:
7条回答
  • 2020-12-04 14:22

    I'm adding update for QListWidget.

    In guisave:

    if isinstance(obj, QListWidget):
        name = obj.objectName()
        settings.beginWriteArray(name)
        for i in range(obj.count()):
            settings.setArrayIndex(i)
            settings.setValue(name, obj.item(i).text())
        settings.endArray()
    

    in guirestore:

    if isinstance(obj, QListWidget):
        name = obj.objectName()
        size = settings.beginReadArray(name)
        for i in range(size):
            settings.setArrayIndex(i)
            value = settings.value(name)  # get stored value from registry
            if value != None:
                obj.addItem(value)
        settings.endArray()
    
    0 讨论(0)
  • 2020-12-04 14:23

    I found these answers useful, so I thought I'd put them together and post a version (for PySide2/Qt5) with some duplication removed and a name provided to group the settings under.

    from PySide2.QtWidgets import *
    import inspect
    
    def GetHandledTypes():
        return (QComboBox, QLineEdit, QCheckBox, QRadioButton, QSpinBox, QSlider, QListWidget)
    
    def IsHandledType(widget):
        return any(isinstance(widget, t) for t in GetHandledTypes())
    
    #===================================================================
    # save "ui" controls and values to registry "setting"
    #===================================================================
    
    def GuiSave(ui : QWidget, settings : QSettings, uiName="uiwidget"):
        namePrefix = f"{uiName}/"
        settings.setValue(namePrefix + "geometry", ui.saveGeometry())
    
        for name, obj in inspect.getmembers(ui):
            if not IsHandledType(obj):
                continue
    
            name = obj.objectName()
            value = None
            if isinstance(obj, QComboBox):
                index = obj.currentIndex()  # get current index from combobox
                value = obj.itemText(index)  # get the text for current index
    
            if isinstance(obj, QLineEdit):
                value = obj.text()
    
            if isinstance(obj, QCheckBox):
                value = obj.isChecked()
    
            if isinstance(obj, QRadioButton):
                value = obj.isChecked()
    
            if isinstance(obj, QSpinBox):
                value = obj.value()
    
            if isinstance(obj, QSlider):
                value = obj.value()
    
            if isinstance(obj, QListWidget):
                settings.beginWriteArray(name)
                for i in range(obj.count()):
                    settings.setArrayIndex(i)
                    settings.setValue(namePrefix + name, obj.item(i).text())
                settings.endArray()
            elif value is not None:
                settings.setValue(namePrefix + name, value)
    
    #===================================================================
    # restore "ui" controls with values stored in registry "settings"
    #===================================================================
    
    def GuiRestore(ui : QWidget, settings : QSettings, uiName="uiwidget"):
        from distutils.util import strtobool
    
        namePrefix = f"{uiName}/"
        geometryValue = settings.value(namePrefix + "geometry")
        if geometryValue:
            ui.restoreGeometry(geometryValue)
    
        for name, obj in inspect.getmembers(ui):
            if not IsHandledType(obj):
                continue
    
            name = obj.objectName()
            value = None
            if not isinstance(obj, QListWidget):
                value = settings.value(namePrefix + name)
                if value is None:
                    continue
    
            if isinstance(obj, QComboBox):
                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):
                obj.setText(value)
    
            if isinstance(obj, QCheckBox):
                obj.setChecked(strtobool(value))
    
            if isinstance(obj, QRadioButton):
                obj.setChecked(strtobool(value))
    
            if isinstance(obj, QSlider):
                obj.setValue(int(value))
    
            if isinstance(obj, QSpinBox):
                obj.setValue(int(value))
    
            if isinstance(obj, QListWidget):
                size = settings.beginReadArray(namePrefix + name)
                for i in range(size):
                    settings.setArrayIndex(i)
                    value = settings.value(namePrefix + name)
                    if value is not None:
                        obj.addItem(value)
                settings.endArray()```
    
    0 讨论(0)
  • 2020-12-04 14:24

    thank you Panofish and everyone i am adding some update for QSlider/QSpinBox. it's small and simple.

    at guisave you can add :

    if isinstance(obj, QSpinBox):
        name  = obj.objectName()
        value = obj.value()             # get stored value from registry
        settings.setValue(name, value)
    
    if isinstance(obj, QSlider):
        name  = obj.objectName()
        value = obj.value()             # get stored value from registry
        settings.setValue(name, value)
    

    at guirestore you can add :

    if isinstance(obj, QSlider):
        name = obj.objectName()
        value = settings.value(name)    # get stored value from registry
        if value != None:           
            obj. setValue(int(value))   # restore value from registry
    
    if isinstance(obj, QSpinBox):
        name = obj.objectName()
        value = settings.value(name)    # get stored value from registry
        if value != None:
            obj. setValue(int(value))   # restore value from registry
    
    0 讨论(0)
  • 2020-12-04 14:25

    I'm a novice programmer so I'm not sure where I was going wrong and please excuse my lack of proper terminology/ technical understanding but my application has multiple QWidget classes for different app 'states' that load/ unload different UI's(and related functions) per state - all in and out of a single main 'QMainWindow'

    this is using @beesleep class implementation but it looks like the code in question is the same for all the above examples

    I was having issues with -

    def _is_handled_type(cls, widget):
        return any(isinstance(widget, t) for t in cls._get_handled_types())
    
    
    for name, obj in inspect.getmembers(self)
        # print(name) <------------------------------
        if not self._is_handled_type...
    

    The methods of self "QMainWindow" are returned instead of all active child widgets.

    .

    My fix was this. I deleted - ***this part is not necessary, the code is just no longer used

    @classmethod
    def _is_handled_type(cls, widget):
        return any(isinstance(widget, t) fort in cls._get_handled_types())
    

    Then changed in _gui_save() and _gui_restore() -

    for name, obj in inspect.getmembers(self):
        if not self._is_handled_type(obj):
            continue
        if name in self._names_to_avoid: # _gui_restore()
            continue                     # _gui_restore()
            name = obj.objectName()
            value = None
    

    To -

    for child in self._get_handled_types():
    
        for obj in self.findChildren(child):
    
            if obj:
    
                name = obj.objectName()
                if name in self._names_to_avoid: # _gui_restore()
                    continue                     # _gui_restore()
                value = None
    

    The last step is that you have to assign a name to each object that you want to save

    self.q_list = QListWidget()
    self.q_list.setObjectName("List")
    ...
    self.q_text = QLineEdit('enter text')
    self.q_text.setObjectName("Text")
    

    .

    for child in self._get_handled_types():
        for obj in self.findChildren(child):
            if obj:
                name = obj.objectName()
    
                print(name, obj) <-------------
    

    Returns

    Text <PyQt5.QtWidgets.QLineEdit object at 0x0000023DD43E2708>
    List <PyQt5.QtWidgets.QListWidget object at 0x0000023DD42530D8>
    

    final note... if you want to see where the settings file is being saved then add - print(self.settings.fileName()) under the init

    cheers!

    0 讨论(0)
  • 2020-12-04 14:27

    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() 
    
    0 讨论(0)
  • 2020-12-04 14:37

    Here is another version of this great code, that includes QTabWidget, and wrap everything into a class for easier use:

    qt_utils.py:

    from PyQt5 import QtGui
    from PyQt5.QtWidgets import QComboBox, QCheckBox, QLineEdit,\
        QRadioButton, QSpinBox, QSlider, QListWidget, QTabWidget
    from PyQt5.QtCore import QSettings
    from distutils.util import strtobool
    
    import inspect
    
    
    class QMainWindow(QtGui.QMainWindow):
        companie_name = 'CompanieName'
        software_name = 'SoftwareName'
        settings_ui_name = 'defaultUiwidget'
        settings_ui_user_name = 'user'
        _names_to_avoid = {}
    
        def __init__(self, parent=None):
            super(QMainWindow, self).__init__(parent)
            self.settings = QSettings(self.companie_name, self.software_name)
    
        def closeEvent(self, e):
            self._gui_save()
    
        @classmethod
        def _get_handled_types(cls):
            return QComboBox, QLineEdit, QCheckBox, QRadioButton, QSpinBox, QSlider, QListWidget, QTabWidget
    
        @classmethod
        def _is_handled_type(cls, widget):
            return any(isinstance(widget, t) for t in cls._get_handled_types())
    
        def _gui_save(self):
            """
            save "ui" controls and values to registry "setting"
            :return:
            """
            name_prefix = f"{self.settings_ui_name}/"
            self.settings.setValue(name_prefix + "geometry", self.saveGeometry())
    
            for name, obj in inspect.getmembers(self):
                if not self._is_handled_type(obj):
                    continue
    
                name = obj.objectName()
                value = None
                if isinstance(obj, QComboBox):
                    index = obj.currentIndex()  # get current index from combobox
                    value = obj.itemText(index)  # get the text for current index
    
                elif isinstance(obj, QTabWidget):
                    value = obj.currentIndex()
    
                elif isinstance(obj, QLineEdit):
                    value = obj.text()
    
                elif isinstance(obj, QCheckBox):
                    value = obj.isChecked()
    
                elif isinstance(obj, QRadioButton):
                    value = obj.isChecked()
    
                elif isinstance(obj, QSpinBox):
                    value = obj.value()
    
                elif isinstance(obj, QSlider):
                    value = obj.value()
    
                elif isinstance(obj, QListWidget):
                    self.settings.beginWriteArray(name)
                    for i in range(obj.count()):
                        self.settings.setArrayIndex(i)
                        self.settings.setValue(name_prefix + name, obj.item(i).text())
                    self.settings.endArray()
    
                if value is not None:
                    self.settings.setValue(name_prefix + name, value)
    
        def _gui_restore(self):
            """
            restore "ui" controls with values stored in registry "settings"
            :return:
            """
    
            name_prefix = f"{self.settings_ui_name}/"
            geometry_value = self.settings.value(name_prefix + "geometry")
            if geometry_value:
                self.restoreGeometry(geometry_value)
    
            for name, obj in inspect.getmembers(self):
                if not self._is_handled_type(obj):
                    continue
                if name in self._names_to_avoid:
                    continue
    
                name = obj.objectName()
                value = None
                if not isinstance(obj, QListWidget):
                    value = self.settings.value(name_prefix + name)
                    if value is None:
                        continue
    
                if isinstance(obj, QComboBox):
                    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
    
                elif isinstance(obj, QTabWidget):
                    try:
                        value = int(value)
                    except ValueError:
                        value = 0
                    obj.setCurrentIndex(value)
    
                elif isinstance(obj, QLineEdit):
                    obj.setText(value)
    
                elif isinstance(obj, QCheckBox):
                    obj.setChecked(strtobool(value))
    
                elif isinstance(obj, QRadioButton):
                    obj.setChecked(strtobool(value))
    
                elif isinstance(obj, QSlider):
                    obj.setValue(int(value))
    
                elif isinstance(obj, QSpinBox):
                    obj.setValue(int(value))
    
                elif isinstance(obj, QListWidget):
                    size = self.settings.beginReadArray(name_prefix + name)
                    for i in range(size):
                        self.settings.setArrayIndex(i)
                        value = self.settings.value(name_prefix + name)
                        if value is not None:
                            obj.addItem(value)
                    self.settings.endArray()
    
        def _add_setting(self, name, value):
            name_prefix = f"{self.settings_ui_user_name}/"
            self.settings.setValue(name_prefix + name, value)
    
        def _get_setting(self, name):
            name_prefix = f"{self.settings_ui_user_name}/"
            return self.settings.value(name_prefix + name)
    

    Here is an example of use:

    import qt_utils
    
    
    class MyMaine(qt_utils.QMainWindow, Ui_MainWindow):
        companie_name = 'Name'
        software_name = 'softName'
        _names_to_avoid = {'my_widget_name_not_to_save'}
    
        def __init__(self, parent=None):
            super(MyMaine, self).__init__(parent)
    
            self.setupUi(self)
    
            self._gui_restore()
    
    0 讨论(0)
提交回复
热议问题