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
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()
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()```
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
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!
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()
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()