I’m baffled by the results of using QSettings to save the state of my radio buttons from one app session to another using PyQt5. (OS = Ubuntu Linux 18.04)
These are the steps to produce baffling results:
- Run the app; see both radio buttons selected; both buttons fire as if mouse selected
- Deselect the top radio button
- Close the app; see the ‘correct’ saving of the radio button checked states
- Run the app; both radio buttons are selected even though different states were saved where only one button is selected
- Deselect the top radio button
- Close the app; see the ‘correct’ saving of the radio button checked states
- In the code, in line 18, change
QSettings('LoneProgrammer2', 'qsettingsTest1')
toQSettings('ChangeThis', 'qsettingsTest1')
; save the code - Run the app; !!The correct saved values are reflected by the radio button selection!!
- Close the app; 10 Run the app and now there are two radio buttons selected again!
Can anyone please explain what’s going on here? I just want the QSettings to work.
import sys from PyQt5.QtCore import QSettings from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QDialogButtonBox, QGroupBox, QHBoxLayout, QRadioButton class MyApp(QWidget): def __init__(self): super().__init__() self.oAutoPromoteRadioBtn = QRadioButton("Automatically Promote to Queen") self.oAutoPromoteRadioBtn.toggled.connect(self.on_selected) self.oUsePopupRadioBtn = QRadioButton("Promote Pawn Using Popup Window") self.oUsePopupRadioBtn.toggled.connect(self.on_selected) self.oUsePopupRadioBtn.setChecked(True) self.settings = QSettings('LoneProgrammer2', 'qsettingsTest1') # companyname, appname self.settings.beginGroup("Promotion Dialog") self.oAutoPromoteRadioBtn.setChecked( bool(self.settings.value('auto-promote radio button checked state'))) self.oUsePopupRadioBtn.setChecked( bool(self.settings.value('promote using popup radio button checked state'))) self.settings.endGroup() print('AT APP OPENING:') print('self.oAutoPromoteRadioBtn.isChecked() = ', self.oAutoPromoteRadioBtn.isChecked()) print('self.oUsePopupRadioBtn.isChecked() = ', self.oUsePopupRadioBtn.isChecked()) oVertLayoutForRadioButtons = QVBoxLayout() oVertLayoutForRadioButtons.addWidget(self.oAutoPromoteRadioBtn) oVertLayoutForRadioButtons.addWidget(self.oUsePopupRadioBtn) self.groupbox = QGroupBox("Select pawn promotion method:") self.groupbox.setFixedWidth(300) self.groupbox.setFixedHeight(95) self.groupbox.setLayout(oVertLayoutForRadioButtons) self.oVertLayout = QVBoxLayout() self.oVertLayout.addWidget(self.groupbox) self.setLayout(self.oVertLayout) def on_selected(self): radio_button = self.sender() if radio_button.isChecked(): if radio_button.text() == 'Automatically Promote to Queen': print('set to auto-promote to queen') elif radio_button.text() == 'Promote Pawn Using Popup Window': print('set to promote pawn to queen using popup window') def closeEvent(self, event): # save the vars from this session self.settings.beginGroup("Promotion Dialog") self.settings.setValue('auto-promote radio button checked state', self.oAutoPromoteRadioBtn.isChecked()) self.settings.setValue('promote using popup radio button checked state', self.oUsePopupRadioBtn.isChecked()) self.settings.endGroup() print() print('AT APP CLOSE:') print('self.oAutoPromoteRadioBtn.isChecked() = ', self.oAutoPromoteRadioBtn.isChecked()) print('self.oUsePopupRadioBtn.isChecked() = ', self.oUsePopupRadioBtn.isChecked()) if __name__ == "__main__": app = QApplication(sys.argv) demo = MyApp() demo.show() sys.exit(app.exec_())
Advertisement
Answer
When reading settings values it is good to indicate the type as there may be confusion (most likely value will return the strings “true” and “false” that are converted to True when using bool since they are truly). On the other hand to add readability it is better to create specialized methods.
from functools import cached_property import sys from PyQt5.QtCore import QSettings from PyQt5.QtWidgets import ( QApplication, QWidget, QVBoxLayout, QDialogButtonBox, QGroupBox, QHBoxLayout, QRadioButton, ) class MyApp(QWidget): def __init__(self): super().__init__() self.oAutoPromoteRadioBtn = QRadioButton("Automatically Promote to Queen") self.oAutoPromoteRadioBtn.toggled.connect(self.on_selected) self.oUsePopupRadioBtn = QRadioButton("Promote Pawn Using Popup Window") self.oUsePopupRadioBtn.toggled.connect(self.on_selected) self.settings = QSettings( "LoneProgrammer2", "qsettingsTest1" ) # companyname, appname oVertLayoutForRadioButtons = QVBoxLayout() oVertLayoutForRadioButtons.addWidget(self.oAutoPromoteRadioBtn) oVertLayoutForRadioButtons.addWidget(self.oUsePopupRadioBtn) self.groupbox = QGroupBox("Select pawn promotion method:") self.groupbox.setFixedSize(300, 95) self.groupbox.setLayout(oVertLayoutForRadioButtons) self.oVertLayout = QVBoxLayout(self) self.oVertLayout.addWidget(self.groupbox) self.read_settings() def on_selected(self): radio_button = self.sender() if radio_button.isChecked(): if radio_button.text() == "Automatically Promote to Queen": print("set to auto-promote to queen") elif radio_button.text() == "Promote Pawn Using Popup Window": print("set to promote pawn to queen using popup window") @cached_property def settings(self): return QSettings("LoneProgrammer2", "qsettingsTest1") @property def mapping_settings(self): return { "Promotion Dialog": [ ("auto-promote radio button checked state", self.oAutoPromoteRadioBtn), ( "promote using popup radio button checked state", self.oUsePopupRadioBtn, ), ] } def read_settings(self): for group_key, values in self.mapping_settings.items(): self.settings.beginGroup(group_key) for (key, checkbox) in values: value = self.settings.value(key, type=bool) checkbox.setChecked(value) self.settings.endGroup() def write_settings(self): for group_key, values in self.mapping_settings.items(): self.settings.beginGroup(group_key) for (key, checkbox) in values: self.settings.setValue(key, checkbox.isChecked()) self.settings.endGroup() def closeEvent(self, event): super().closeEvent(event) self.write_settings() if __name__ == "__main__": app = QApplication(sys.argv) demo = MyApp() demo.show() sys.exit(app.exec_())