Skip to content

Instantly share code, notes, and snippets.

@Zythyr
Created October 3, 2020 05:13
Show Gist options
  • Save Zythyr/930ed8ac09a830717a459349e942a86a to your computer and use it in GitHub Desktop.
Save Zythyr/930ed8ac09a830717a459349e942a86a to your computer and use it in GitHub Desktop.
PyQt5 - Issue with using QSettings to save and restore widget settings
import os, sys, time, traceback
from PyQt5 import QtWidgets, uic, QtCore, QtGui
from PyQt5.QtCore import QFileInfo, QSettings
from PyQt5.QtWidgets import qApp
from ui_mainwindow import Ui_MainWindow
def settings_value_is_valid(val):
# https://stackoverflow.com/a/60028282/4988010
if isinstance(val, QtGui.QPixmap):
return not val.isNull()
return True
def settings_restore(settings):
# https://stackoverflow.com/a/60028282/4988010
finfo = QtCore.QFileInfo(settings.fileName())
if finfo.exists() and finfo.isFile():
for w in QtWidgets.qApp.allWidgets():
if w.objectName():
mo = w.metaObject()
for i in range(mo.propertyCount()):
prop = mo.property(i)
name = prop.name()
last_value = w.property(name)
key = "{}/{}".format(w.objectName(), name)
# print(prop, name, last_value, key)
if not settings.contains(key):
continue
val = settings.value(key, type=type(last_value),)
if (
val != last_value
and settings_value_is_valid(val)
and prop.isValid()
and prop.isWritable()
):
w.setProperty(name, val)
def settings_save(settings):
# https://stackoverflow.com/a/60028282/4988010
for w in QtWidgets.qApp.allWidgets():
if w.objectName():
mo = w.metaObject()
for i in range(mo.propertyCount()):
prop = mo.property(i)
name = prop.name()
key = "{}/{}".format(w.objectName(), name)
val = w.property(name)
if settings_value_is_valid(val) and prop.isValid() and prop.isWritable():
settings.setValue(key, w.property(name))
class MyApp(QtWidgets.QMainWindow):
def __init__(self):
super(MyApp, self).__init__()
self.settings = QSettings("./temp/gui_settings.ini", QSettings.IniFormat)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
self.ui.action_config_save_current_values.triggered.connect(self.config_widgets_save_settings)
self.ui.action_config_load_config_file.triggered.connect(self.config_widgets_load_settings)
self.ui.action_config_reset_to_factory_default.triggered.connect(self.config_widgets_reset_settings)
def config_widgets_save_settings(self):
# Save settings
# self.logger.info('Saving current values of the widgets into a config file.')
settings_save(self.settings)
def config_widgets_load_settings(self):
# self.logger.info('Loading saved widgets settings config file.')
# Load previous usage settings
settings_restore(self.settings)
def config_widgets_reset_settings(self):
# self.logger.info('Resetting the saved widgets settings config file to default factor settings.')
self.settings.clear()
self.ui.setupUi(self)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
# print(QtWidgets.QStyleFactory.keys())
app.setStyle('Fusion')
window = MyApp()
window.show()
app.exec_()
# sys.exit(app.exec_())
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>368</width>
<height>204</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QPushButton" name="start_button">
<property name="geometry">
<rect>
<x>100</x>
<y>80</y>
<width>109</width>
<height>23</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">QPushButton::checked {background-color: #6cf090; }</string>
</property>
<property name="text">
<string>Start</string>
</property>
<property name="checkable">
<bool>false</bool>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>10</x>
<y>10</y>
<width>342</width>
<height>51</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="label_10">
<property name="text">
<string>Param A</string>
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QLabel" name="label_12">
<property name="text">
<string>Param C</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QLabel" name="label_11">
<property name="text">
<string>Param B</string>
</property>
</widget>
</item>
<item row="1" column="2">
<widget class="QDoubleSpinBox" name="param_c">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>100000000.000000000000000</double>
</property>
<property name="value">
<double>1234.000000000000000</double>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QDoubleSpinBox" name="param_a">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>1.500000000000000</double>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QDoubleSpinBox" name="param_b">
<property name="decimals">
<number>3</number>
</property>
<property name="maximum">
<double>9999.000000000000000</double>
</property>
<property name="singleStep">
<double>0.050000000000000</double>
</property>
<property name="value">
<double>0.250000000000000</double>
</property>
</widget>
</item>
<item row="0" column="3">
<widget class="QLabel" name="label_4">
<property name="text">
<string>Param D</string>
</property>
</widget>
</item>
<item row="1" column="3">
<widget class="QSpinBox" name="param_d">
<property name="maximum">
<number>999999999</number>
</property>
<property name="value">
<number>456</number>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>368</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuFile">
<property name="title">
<string>File</string>
</property>
<widget class="QMenu" name="menuWidget_defaults">
<property name="title">
<string>Widget defaults</string>
</property>
<addaction name="action_config_save_current_values"/>
<addaction name="action_config_load_config_file"/>
<addaction name="action_config_reset_to_factory_default"/>
</widget>
<addaction name="menuWidget_defaults"/>
</widget>
<addaction name="menuFile"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="action_config_save_current_values">
<property name="text">
<string>Save current values</string>
</property>
</action>
<action name="action_config_load_config_file">
<property name="text">
<string>Load config file</string>
</property>
</action>
<action name="action_config_reset_to_factory_default">
<property name="text">
<string>Reset to factory default</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(368, 204)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.start_button = QtWidgets.QPushButton(self.centralwidget)
self.start_button.setGeometry(QtCore.QRect(100, 80, 109, 23))
self.start_button.setStyleSheet("QPushButton::checked {background-color: #6cf090; }")
self.start_button.setCheckable(False)
self.start_button.setObjectName("start_button")
self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 342, 51))
self.layoutWidget.setObjectName("layoutWidget")
self.gridLayout_2 = QtWidgets.QGridLayout(self.layoutWidget)
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
self.gridLayout_2.setObjectName("gridLayout_2")
self.label_10 = QtWidgets.QLabel(self.layoutWidget)
self.label_10.setObjectName("label_10")
self.gridLayout_2.addWidget(self.label_10, 0, 0, 1, 1)
self.label_12 = QtWidgets.QLabel(self.layoutWidget)
self.label_12.setObjectName("label_12")
self.gridLayout_2.addWidget(self.label_12, 0, 2, 1, 1)
self.label_11 = QtWidgets.QLabel(self.layoutWidget)
self.label_11.setObjectName("label_11")
self.gridLayout_2.addWidget(self.label_11, 0, 1, 1, 1)
self.param_c = QtWidgets.QDoubleSpinBox(self.layoutWidget)
self.param_c.setDecimals(3)
self.param_c.setMaximum(100000000.0)
self.param_c.setProperty("value", 1234.0)
self.param_c.setObjectName("param_c")
self.gridLayout_2.addWidget(self.param_c, 1, 2, 1, 1)
self.param_a = QtWidgets.QDoubleSpinBox(self.layoutWidget)
self.param_a.setDecimals(3)
self.param_a.setMaximum(9999.0)
self.param_a.setSingleStep(0.05)
self.param_a.setProperty("value", 1.5)
self.param_a.setObjectName("param_a")
self.gridLayout_2.addWidget(self.param_a, 1, 0, 1, 1)
self.param_b = QtWidgets.QDoubleSpinBox(self.layoutWidget)
self.param_b.setDecimals(3)
self.param_b.setMaximum(9999.0)
self.param_b.setSingleStep(0.05)
self.param_b.setProperty("value", 0.25)
self.param_b.setObjectName("param_b")
self.gridLayout_2.addWidget(self.param_b, 1, 1, 1, 1)
self.label_4 = QtWidgets.QLabel(self.layoutWidget)
self.label_4.setObjectName("label_4")
self.gridLayout_2.addWidget(self.label_4, 0, 3, 1, 1)
self.param_d = QtWidgets.QSpinBox(self.layoutWidget)
self.param_d.setMaximum(999999999)
self.param_d.setProperty("value", 456)
self.param_d.setObjectName("param_d")
self.gridLayout_2.addWidget(self.param_d, 1, 3, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 368, 21))
self.menubar.setObjectName("menubar")
self.menuFile = QtWidgets.QMenu(self.menubar)
self.menuFile.setObjectName("menuFile")
self.menuWidget_defaults = QtWidgets.QMenu(self.menuFile)
self.menuWidget_defaults.setObjectName("menuWidget_defaults")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.action_config_save_current_values = QtWidgets.QAction(MainWindow)
self.action_config_save_current_values.setObjectName("action_config_save_current_values")
self.action_config_load_config_file = QtWidgets.QAction(MainWindow)
self.action_config_load_config_file.setObjectName("action_config_load_config_file")
self.action_config_reset_to_factory_default = QtWidgets.QAction(MainWindow)
self.action_config_reset_to_factory_default.setObjectName("action_config_reset_to_factory_default")
self.menuWidget_defaults.addAction(self.action_config_save_current_values)
self.menuWidget_defaults.addAction(self.action_config_load_config_file)
self.menuWidget_defaults.addAction(self.action_config_reset_to_factory_default)
self.menuFile.addAction(self.menuWidget_defaults.menuAction())
self.menubar.addAction(self.menuFile.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.start_button.setText(_translate("MainWindow", "Start"))
self.label_10.setText(_translate("MainWindow", "Param A"))
self.label_12.setText(_translate("MainWindow", "Param C"))
self.label_11.setText(_translate("MainWindow", "Param B"))
self.label_4.setText(_translate("MainWindow", "Param D"))
self.menuFile.setTitle(_translate("MainWindow", "File"))
self.menuWidget_defaults.setTitle(_translate("MainWindow", "Widget defaults"))
self.action_config_save_current_values.setText(_translate("MainWindow", "Save current values"))
self.action_config_load_config_file.setText(_translate("MainWindow", "Load config file"))
self.action_config_reset_to_factory_default.setText(_translate("MainWindow", "Reset to factory default"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment