【问题标题】:Loading Widgets properly while restoring from QSettings从 QSettings 恢复时正确加载小部件
【发布时间】:2020-02-02 15:54:11
【问题描述】:

我正在使用下面的代码来保存我输入的文本。例如,如果我用“blablbalbla”在我的 gui 中填写一行,关闭程序,重新打开它,该文本将在那里。但是,使用此代码会破坏我的 GUI。我假设这是因为它是从 QSettings 加载的,并且我的 QtWidgets 没有加载。如何在保持代码激活的同时加载我的 QT Widgets? :/

def restore(settings):
    finfo = QFileInfo(settings.fileName())

    if finfo.exists() and finfo.isFile():
        for w in qApp.allWidgets():
            mo = w.metaObject()
            if w.objectName() != "":
                for i in range(mo.propertyCount()):
                    name = mo.property(i).name()
                    val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))
                    w.setProperty(name, val)

def save(settings):
    for w in qApp.allWidgets():
        mo = w.metaObject()
        if w.objectName() != "":
            for i in range(mo.propertyCount()):
                name = mo.property(i).name()
                settings.setValue("{}/{}".format(w.objectName(), name), w.property(name))

class Window(QtWidgets.QMainWindow, Ui_MainWindow):
    settings = QSettings("gui.ini", QSettings.IniFormat)
    def __init__(self, cList):
        super().__init__()

        self.setupUi(self)
        restore(self.settings)


    def closeEvent(self, event):
        save(self.settings)
        QMainWindow.closeEvent(self, event)

编辑:有趣的是,如果我删除我的 .ini 文件,它第一次就可以正常工作。我收到此错误:

C:file.py:847: DeprecationWarning: an integer is required (got type InputMethodHints).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
  val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))
C:file.py:847: DeprecationWarning: an integer is required (got type Alignment).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
  val = settings.value("{}/{}".format(w.objectName(), name), w.property(name))

编辑 2:

Python 3.8.1

这是我的 UI 主窗口。我这里没有添加任何代码:

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.setEnabled(True)
        MainWindow.resize(444, 676)
        MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly)
        MainWindow.setAnimated(True)
        MainWindow.setTabShape(QtWidgets.QTabWidget.Rounded)
        self.centralwidget = QtWidgets.QWidget(MainWindow)

完整的 GUI 代码:

from __future__ import print_function


from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import QFileInfo, QSettings, Qt
from PyQt5.QtGui import QIcon, QColor, QPalette
from PyQt5.QtWidgets import (
    qApp,
    QApplication,
    QMainWindow,
    QFormLayout,
    QLineEdit,
    QTabWidget,
    QWidget,
    QAction,
)


class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(506, 455)
        MainWindow.setEnabled(True)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.layoutWidget = QtWidgets.QWidget(self.centralwidget)
        self.layoutWidget.setGeometry(QtCore.QRect(10, 10, 480, 401))
        self.layoutWidget.setObjectName("layoutWidget")
        self.formLayout = QtWidgets.QFormLayout(self.layoutWidget)
        self.formLayout.setContentsMargins(0, 0, 0, 0)
        self.formLayout.setObjectName("formLayout")
        self.label_2 = QtWidgets.QLabel(self.layoutWidget)
        self.label_2.setObjectName("label_2")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.LabelRole, self.label_2)
        self.dateEdit = QtWidgets.QDateEdit(self.layoutWidget)
        self.dateEdit.setObjectName("dateEdit")
        self.formLayout.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.dateEdit)
        self.label = QtWidgets.QLabel(self.layoutWidget)
        self.label.setObjectName("label")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label)
        self.comboBox = QtWidgets.QComboBox(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.comboBox.sizePolicy().hasHeightForWidth())
        self.comboBox.setSizePolicy(sizePolicy)
        self.comboBox.setMinimumSize(QtCore.QSize(312, 27))
        self.comboBox.setMaximumSize(QtCore.QSize(312, 27))
        self.comboBox.setObjectName("comboBox")
        self.formLayout.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.comboBox)
        self.label_3 = QtWidgets.QLabel(self.layoutWidget)
        self.label_3.setObjectName("label_3")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_3)
        self.comboBox_2 = QtWidgets.QComboBox(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.comboBox_2.sizePolicy().hasHeightForWidth())
        self.comboBox_2.setSizePolicy(sizePolicy)
        self.comboBox_2.setMinimumSize(QtCore.QSize(312, 27))
        self.comboBox_2.setMaximumSize(QtCore.QSize(312, 27))
        self.comboBox_2.setObjectName("comboBox_2")
        self.formLayout.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.comboBox_2)
        self.label_4 = QtWidgets.QLabel(self.layoutWidget)
        self.label_4.setObjectName("label_4")
        self.formLayout.setWidget(3, QtWidgets.QFormLayout.LabelRole, self.label_4)
        self.comboBox_3 = QtWidgets.QComboBox(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.comboBox_3.sizePolicy().hasHeightForWidth())
        self.comboBox_3.setSizePolicy(sizePolicy)
        self.comboBox_3.setMinimumSize(QtCore.QSize(312, 27))
        self.comboBox_3.setMaximumSize(QtCore.QSize(312, 27))
        self.comboBox_3.setObjectName("comboBox_3")
        self.formLayout.setWidget(3, QtWidgets.QFormLayout.FieldRole, self.comboBox_3)
        self.label_5 = QtWidgets.QLabel(self.layoutWidget)
        self.label_5.setObjectName("label_5")
        self.formLayout.setWidget(4, QtWidgets.QFormLayout.LabelRole, self.label_5)
        self.comboBox_4 = QtWidgets.QComboBox(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.comboBox_4.sizePolicy().hasHeightForWidth())
        self.comboBox_4.setSizePolicy(sizePolicy)
        self.comboBox_4.setMinimumSize(QtCore.QSize(312, 27))
        self.comboBox_4.setMaximumSize(QtCore.QSize(312, 27))
        self.comboBox_4.setObjectName("comboBox_4")
        self.formLayout.setWidget(4, QtWidgets.QFormLayout.FieldRole, self.comboBox_4)
        self.label_6 = QtWidgets.QLabel(self.layoutWidget)
        self.label_6.setObjectName("label_6")
        self.formLayout.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_6)
        self.comboBox_5 = QtWidgets.QComboBox(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.comboBox_5.sizePolicy().hasHeightForWidth())
        self.comboBox_5.setSizePolicy(sizePolicy)
        self.comboBox_5.setMinimumSize(QtCore.QSize(312, 27))
        self.comboBox_5.setMaximumSize(QtCore.QSize(312, 27))
        self.comboBox_5.setObjectName("comboBox_5")
        self.formLayout.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.comboBox_5)
        self.label_11 = QtWidgets.QLabel(self.layoutWidget)
        self.label_11.setObjectName("label_11")
        self.formLayout.setWidget(6, QtWidgets.QFormLayout.LabelRole, self.label_11)
        self.plainTextEdit = QtWidgets.QPlainTextEdit(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.plainTextEdit.sizePolicy().hasHeightForWidth()
        )
        self.plainTextEdit.setSizePolicy(sizePolicy)
        self.plainTextEdit.setMinimumSize(QtCore.QSize(312, 30))
        self.plainTextEdit.setMaximumSize(QtCore.QSize(312, 30))
        self.plainTextEdit.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit.setSizeAdjustPolicy(
            QtWidgets.QAbstractScrollArea.AdjustIgnored
        )
        self.plainTextEdit.setObjectName("plainTextEdit")
        self.formLayout.setWidget(
            6, QtWidgets.QFormLayout.FieldRole, self.plainTextEdit
        )
        self.label_8 = QtWidgets.QLabel(self.layoutWidget)
        self.label_8.setObjectName("label_8")
        self.formLayout.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_8)
        self.plainTextEdit_2 = QtWidgets.QPlainTextEdit(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.plainTextEdit_2.sizePolicy().hasHeightForWidth()
        )
        self.plainTextEdit_2.setSizePolicy(sizePolicy)
        self.plainTextEdit_2.setMinimumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_2.setMaximumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_2.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_2.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_2.setSizeAdjustPolicy(
            QtWidgets.QAbstractScrollArea.AdjustIgnored
        )
        self.plainTextEdit_2.setObjectName("plainTextEdit_2")
        self.formLayout.setWidget(
            7, QtWidgets.QFormLayout.FieldRole, self.plainTextEdit_2
        )
        self.label_9 = QtWidgets.QLabel(self.layoutWidget)
        self.label_9.setObjectName("label_9")
        self.formLayout.setWidget(8, QtWidgets.QFormLayout.LabelRole, self.label_9)
        self.plainTextEdit_3 = QtWidgets.QPlainTextEdit(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.plainTextEdit_3.sizePolicy().hasHeightForWidth()
        )
        self.plainTextEdit_3.setSizePolicy(sizePolicy)
        self.plainTextEdit_3.setMinimumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_3.setMaximumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_3.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_3.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_3.setSizeAdjustPolicy(
            QtWidgets.QAbstractScrollArea.AdjustIgnored
        )
        self.plainTextEdit_3.setObjectName("plainTextEdit_3")
        self.formLayout.setWidget(
            8, QtWidgets.QFormLayout.FieldRole, self.plainTextEdit_3
        )
        self.label_10 = QtWidgets.QLabel(self.layoutWidget)
        self.label_10.setObjectName("label_10")
        self.formLayout.setWidget(9, QtWidgets.QFormLayout.LabelRole, self.label_10)
        self.plainTextEdit_4 = QtWidgets.QPlainTextEdit(self.layoutWidget)
        sizePolicy = QtWidgets.QSizePolicy(
            QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed
        )
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(
            self.plainTextEdit_4.sizePolicy().hasHeightForWidth()
        )
        self.plainTextEdit_4.setSizePolicy(sizePolicy)
        self.plainTextEdit_4.setMinimumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_4.setMaximumSize(QtCore.QSize(312, 30))
        self.plainTextEdit_4.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_4.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.plainTextEdit_4.setSizeAdjustPolicy(
            QtWidgets.QAbstractScrollArea.AdjustIgnored
        )
        self.plainTextEdit_4.setObjectName("plainTextEdit_4")
        self.formLayout.setWidget(
            9, QtWidgets.QFormLayout.FieldRole, self.plainTextEdit_4
        )
        self.pushButton = QtWidgets.QPushButton(self.layoutWidget)
        self.pushButton.setMinimumSize(QtCore.QSize(101, 24))
        self.pushButton.setMaximumSize(QtCore.QSize(101, 24))
        self.pushButton.setObjectName("pushButton")
        self.formLayout.setWidget(10, QtWidgets.QFormLayout.FieldRole, self.pushButton)
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 506, 21))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
        self.label_2.setText(_translate("MainWindow", "test"))
        self.label.setText(_translate("MainWindow", "test"))
        self.label_3.setText(_translate("MainWindow", "test"))
        self.label_4.setText(_translate("MainWindow", "test"))
        self.label_5.setText(_translate("MainWindow", "test"))
        self.label_6.setText(_translate("MainWindow", "test"))
        self.label_11.setText(_translate("MainWindow", "test"))
        self.label_8.setText(_translate("MainWindow", "test"))
        self.label_9.setText(_translate("MainWindow", "test"))
        self.label_10.setText(_translate("MainWindow", "test"))
        self.pushButton.setText(_translate("MainWindow", "Go"))


def restore(settings):
    finfo = QFileInfo(settings.fileName())

    if finfo.exists() and finfo.isFile():
        for w in qApp.allWidgets():
            mo = w.metaObject()
            if w.objectName() != "":
                for i in range(mo.propertyCount()):
                    name = mo.property(i).name()
                    val = settings.value(
                        "{}/{}".format(w.objectName(), name), w.property(name)
                    )
                    w.setProperty(name, val)


def save(settings):
    for w in qApp.allWidgets():
        mo = w.metaObject()
        if w.objectName() != "":
            for i in range(mo.propertyCount()):
                name = mo.property(i).name()
                settings.setValue(
                    "{}/{}".format(w.objectName(), name), w.property(name)
                )


class Window(QtWidgets.QMainWindow, Ui_MainWindow):
    settings = QSettings("gui.ini", QSettings.IniFormat)

    def __init__(self):
        super().__init__()

        self.setupUi(self)
        restore(self.settings)

    def closeEvent(self, event):
        save(self.settings)
        QMainWindow.closeEvent(self, event)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Window()
    w.show()
    app.setStyle("Fusion")
    palette = QtGui.QPalette()
    palette.setColor(QtGui.QPalette.Window, QColor(27, 35, 38))
    palette.setColor(QtGui.QPalette.WindowText, QColor(234, 234, 234))
    palette.setColor(QtGui.QPalette.Base, QColor(42, 50, 53))
    palette.setColor(QtGui.QPalette.AlternateBase, QColor(12, 15, 16))
    palette.setColor(QtGui.QPalette.ToolTipBase, QColor(27, 35, 38))
    palette.setColor(QtGui.QPalette.ToolTipText, Qt.white)
    palette.setColor(QtGui.QPalette.Text, QColor(234, 234, 234))
    palette.setColor(QtGui.QPalette.Button, QColor(27, 35, 38))
    palette.setColor(QtGui.QPalette.ButtonText, Qt.white)
    palette.setColor(QtGui.QPalette.BrightText, QColor(100, 215, 222))
    palette.setColor(QtGui.QPalette.Link, QColor(126, 71, 130))
    palette.setColor(QtGui.QPalette.HighlightedText, Qt.white)
    palette.setColor(QtGui.QPalette.Disabled, QPalette.Light, Qt.black)
    palette.setColor(QtGui.QPalette.Disabled, QPalette.Shadow, QColor(12, 15, 16))
    w.setPalette(palette)
    sys.exit(app.exec_())

【问题讨论】:

    标签: python python-3.x pyqt pyqt5


    【解决方案1】:

    注意:警告是由 PySide2 的不必要引入引起的,因此消除该导入将解决它(我已将其从一个版本的 OP 帖子中删除以消除不必要的导入)。


    文字为什么消失的问题是因为在“保存”功能代码中保存了所有属性,还保存了QLabel具有的空QPixmap,所以在使用“恢复”功能恢复信息时它首先建立文本,然后建立 QPixmap,所以第二个将替换第一个,所以这是功能的限制。考虑到上述情况,解决方案是添加更多过滤器,如下所示:

    def value_is_valid(val):
        if isinstance(val, QtGui.QPixmap):
            return not val.isNull()
        return True
    
    
    def restore(settings):
        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)
                        if not settings.contains(key):
                            continue
                        val = settings.value(key, type=type(last_value),)
                        if (
                            val != last_value
                            and value_is_valid(val)
                            and prop.isValid()
                            and prop.isWritable()
                        ):
                            w.setProperty(name, val)
    
    
    def save(settings):
        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 value_is_valid(val) and prop.isValid() and prop.isWritable():
                        settings.setValue(key, w.property(name))
    

    【讨论】:

    • 感谢您的意见。我添加了代码,但没有解决问题。我认为我的数据保存或加载不正确。我的 GUI 从左侧的标签和带有选项的下拉菜单变为:imgur.com/a/GIH1sq8
    • 对不起,它是 PyQt5 5.14.1。是的。它使我所有的标签都消失了,我的下拉列表中的所有值也都消失了。
    • 抱歉,我要出去几个小时。当我回来时,我会再次尝试在这里发帖,希望有人能够帮助我。感谢您的帮助。
    • 我试过了。不幸的是没有工作。我发布了我的整个 GUI 代码。如果您能看一看,我将不胜感激。第二次运行后,您会注意到文本“test”消失了。恢复它的唯一方法是删除 .ini
    • @t0m3k 为什么要使用这么多不必要的“导入”?您还使用 PySide2 和 PyQt5,因为这是错误的来源,我减少了对您问题的版本的导入,所以我建议您执行以下操作:1)删除 gui.ini 和 2)使用编辑的代码复制新代码你的问题
    猜你喜欢
    • 1970-01-01
    • 2012-01-30
    • 2020-03-13
    • 2020-08-26
    • 1970-01-01
    • 2018-11-19
    • 2017-09-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多