使用 QSettings 保存 QRadioButtons 的状态不能在 PyQt5 中正确保存值

Saving states of QRadioButtons using QSettings not persisting values correctly in PyQt5

我对使用 QSettings 将我的单选按钮状态从一个应用程序会话保存到另一个使用 PyQt5 的结果感到困惑。 (OS = Ubuntu Linux 18.04)

这些是产生莫名其妙结果的步骤:

  1. 运行 应用;看到两个单选按钮都被选中;两个按钮都会触发,就好像鼠标被选中一样
  2. 取消选择顶部单选按钮
  3. 关闭应用;查看 'correct' 单选按钮选中状态的保存
  4. 运行 应用;两个单选按钮都被选中,即使在只选择一个按钮的情况下保存了不同的状态
  5. 取消选择顶部单选按钮
  6. 关闭应用;查看 'correct' 单选按钮选中状态的保存
  7. 在代码中,第18行,将QSettings('LoneProgrammer2', 'qsettingsTest1')改为QSettings('ChangeThis', 'qsettingsTest1');保存代码
  8. 运行 应用; !!正确保存的值反映在单选按钮选择中!!
  9. 关闭应用; 10 运行 应用程序,现在有两个单选按钮再次被选中!

谁能解释一下这是怎么回事?我只想让 QSettings 正常工作。

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_())

读取设置值时最好指明类型,因为可能会造成混淆(最有可能的值是 return 使用 bool 时转换为 True 的字符串“true”和“false”,因为它们是真的)。另一方面,为了增加可读性,最好创建专门的方法。

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_())