PyQt4:将列表保存到QSettings

3

我制作了一个列表(数组),用于计数游戏完成的次数。但是,如果有人重新启动游戏,列表的长度将重置。

据我所知,QSettings专门用于保存和存储数据。我已经阅读了文档,但没有足够的帮助。

例如,我有一个全局数组:

global finishcount
finishcount = []

如何将此应用于QSettings?这样我就可以在重新启动后附加数据而不会丢失数据。它应该像这样吗?
from PyQt4 import QtGui, QtCore
global finishcount
finishcount = []
settings = QtCore.QSettings(self)
settings.setValue(finishcount, self)

我该如何实现这个功能?或者我能否在QSettings本身中创建列表并添加内容?

在主窗口的 closeEvent 中保存设置,并在 __init__ 中读取设置。 - ekhumoro
2个回答

2
以下是一个非常简单的演示,展示了如何将整数列表读取和写入到 QSettings 中。每次打开和关闭窗口时,演示都会自动添加一个新值。
如果您正在使用 PyQt,则完全不需要使用 json。对于列表,只需提供默认值,并指定所包含的值的类型即可:
    settings.value('finishcount', [], int)

示例:

from PyQt4 import QtCore, QtGui

class Window(QtGui.QWidget):
    def __init__(self):
        super(Window, self).__init__()
        settings = QtCore.QSettings('my_org', 'my_app')
        self._finishcount = settings.value('finishcount', [], int)
        print('read settings: %s' % self._finishcount)
        # add a new value for testing
        self._finishcount.append(len(self._finishcount))

    def closeEvent(self, event):
        settings = QtCore.QSettings('my_org', 'my_app')
        settings.setValue('finishcount', self._finishcount)
        print('save settings: %s' % self._finishcount)

if __name__ == '__main__':

    import sys
    app = QtGui.QApplication(sys.argv)
    window = Window()
    window.setGeometry(600, 100, 100, 100)
    window.show()
    sys.exit(app.exec_())

NB: 对于字符串列表的特殊情况,最好使用以下方法:

    settings.value('finishcount', [], 'QStringList')

使用 str 指定类型不如不指定类型更好。否则,空列表将无法正确处理。


我发现在设置了 settings.setValue('mykey',[]) 后,程序下一次加载时 settings.value('mykey', [], str) 返回的是 '' 而不是 []。这是否是预期的行为? - Jason
@Jason 是的,我认为这有点不太好。你可以通过这样做来解决它:settings.value('mykey', [], 'QStringList') - ekhumoro

1
一般情况下,它看起来像这样。这也假设您正在使用v2版本的QVariant API;否则,从QSettings.value返回的结果将是一个QVariant,您需要将其转换为适当的Python类型。如果您正在使用最新版本的PyQt,那么您应该使用v2但如果没有,您可以通过将此代码放在文件顶部来强制执行
import sip
sip.setapi('QVariant', 2)
sip.setapi('QString', 2)

此外,即使使用 API 的 v2 版本,对于除字符串或数字之外的任何更复杂的类型,它通常并不总是按预期工作。 对于像listsdicts这样的更复杂类型,我发现最好将值序列化使用 jsonpickle 并将其保存到QSettings中,然后在检索时进行反序列化。
import json

class MyWidget(QWidget):

    def __init__(self, parent):
        super(MyWidget, self).__init__(parent)
        self.myvalue = 10
        self.mylist = [1,2,3]
        self.restoreSettings()

    def closeEvent(self, event):
        self.saveSettings()
        super(MyWidget, self).closeEvent(event)

    def saveSettings(self):
        settings = QSettings('myorg', 'myapp')
        settings.setValue('myvalue', self.myvalue)
        settings.setValue('mylist', json.dumps(self.mylist))

    def restoreSettings(self):
        settings = QSettings('myorg', 'myapp')
        self.myvalue = settings.value('myvalue', self.myvalue)
        try:
            self.mylist = json.loads(settings.value('mylist', None))
        except (ValueError, TypeError):
            pass

你能举个例子,说明哪些list或者dict没有按照预期工作吗?由于json仅支持有限的类型范围,在QSettings中无法序列化这些类型会是一个漏洞。 - ekhumoro
诚然,我正在使用PySide - 但是QSettings[1,2,3]返回为[u'1', u'2', u'3'] - Brendan Abel
啊,PyQt 添加了一个参数,允许您指定类型。所以 settings.value('mylist',type = int) 将返回正确的结果。我认为 PySide 不支持这一点,但您可以通过将列表放在元组中来解决该问题。或者,更一般地说,只需强制 Qt 编写一个 @Variant 条目,而不是字符串列表即可。 - ekhumoro
我不太理解第二段代码,我需要创建一个JSON文件来存储我的列表吗?如果是这样,由于我不熟悉JSON文件,我该如何实现呢? - ShellRox
基本上只是在保存之前将您的列表转换为字符串。然后它会在读取时将其从字符串转换回列表。 - Brendan Abel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接