PySide:作为 class 变量的 QSettings 具有不一致的行为

PySide: QSettings as class variable has inconsistent behavior

我们为 Maya 2015 编写了许多 PySide 脚本,并使用 QSettings 保存设置。通常我们在 "readSettings" 和 "writeSettings" 函数中创建 QSettings 对象。今天我尝试将 QSettings 对象设为 class 变量。但这引起了一些奇怪的影响。通常返回为 <type 'unicode'> 的某些值开始返回为 <type 'bool'>,但并非所有时间都如此!

这是我写的一个测试脚本来说明问题:

import shiboken

from PySide import QtGui, QtCore
from maya import OpenMayaUI

#------------------------------------------------------------------------------
def getMayaMainWindow():
    parentWindow = OpenMayaUI.MQtUtil.mainWindow()
    if parentWindow:
        return shiboken.wrapInstance(long(parentWindow), QtGui.QWidget)

#------------------------------------------------------------------------------
class TestQSettingsWin(QtGui.QMainWindow):
    def __init__(self, parent=getMayaMainWindow()):
        super(TestQSettingsWin, self).__init__(parent)

        self.setWindowTitle('Test QSettings')
        self.setObjectName('testAllMMessagesWindow')

        self.centralWidget = QtGui.QWidget()
        self.setCentralWidget(self.centralWidget)
        self.mainLayout = QtGui.QVBoxLayout(self.centralWidget)
        self.checkBox = QtGui.QCheckBox('check box')
        self.mainLayout.addWidget(self.checkBox)

        self.readSettings()

    def closeEvent(self, event):
        self.writeSettings()

    def getQSettingsLocation(self):
        raise NotImplementedError('Subclasses of TestQSettingsWin need to '
                                  'implement "getQSettingsLocation"".')

    def readSettings(self):
        setting = self.getQSettingsLocation()
        self.restoreGeometry(setting.value('geometry'))
        self.restoreState(setting.value('windowState'))
        print type(setting.value('checkBox'))

    def writeSettings(self):
        setting = self.getQSettingsLocation()
        setting.setValue('geometry', self.saveGeometry())
        setting.setValue('windowState', self.saveState())
        setting.setValue('checkBox', self.checkBox.isChecked())

#------------------------------------------------------------------------------
class TestQSettingsClassVar(TestQSettingsWin):
    savedSettings = QtCore.QSettings(QtCore.QSettings.IniFormat,
                                     QtCore.QSettings.UserScope,
                                     "Test",
                                     "TestQSettings1")
    def getQSettingsLocation(self):
        return self.savedSettings

#------------------------------------------------------------------------------
class TestQSettingsDefScope(TestQSettingsWin):
    def getQSettingsLocation(self):
        setting = QtCore.QSettings(QtCore.QSettings.IniFormat,
                                   QtCore.QSettings.UserScope,
                                   "Test",
                                   "TestQSettings3")
        return setting

#------------------------------------------------------------------------------
def showTestWindows():
    test1 = TestQSettingsClassVar()
    test1.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
    test1.show()
    test2 = TestQSettingsDefScope()
    test2.setAttribute(QtCore.Qt.WA_DeleteOnClose, True)
    test2.show()

下面是 运行 它在交互式会话中的结果:

>>> import testQSettings
>>> testQSettings.showTestWindows()
<type 'NoneType'>
<type 'NoneType'>
>>> testQSettings.showTestWindows()
<type 'bool'>
<type 'unicode'>
>>> testQSettings.showTestWindows()
<type 'bool'>
<type 'unicode'>
>>> reload(testQSettings)
# Result: <module 'testQSettings' from 'C:/Users/becca/Documents/maya/2015-x64/scripts\testQSettings.pyc'> # 
>>> testQSettings.showTestWindows()
<type 'unicode'>
<type 'unicode'>
>>> testQSettings.showTestWindows()
<type 'bool'>
<type 'unicode'>
>>> testQSettings.showTestWindows()
<type 'bool'>
<type 'unicode'>

如您所见,在需要时始终如一地创建 QSettings 对象 returns 数据值的 <type 'unicode'> 结果。但是创建 QSettings 对象作为 class 变量 returns 一个 <type 'bool'> 结果 except 当模块被重新加载时,然后它 returns一个<type 'unicode'>.

谁能解释一下这种奇怪的行为?有没有规定我不应该将 QSettings 对象设为 class 变量?

设置对象在将其写入磁盘之前必须将各种不同类型的值序列化为字节。这通常在删除设置对象时完成(或者,如果事件循环是 运行,未保存的数据可能会定期刷新到磁盘)。

一直未保存的数据还没有刷新到磁盘,每当你调用settings.value(),它会return它的unserialized值原始类型。

您可以通过调用 settings.sync() 自行强制刷新数据,但我强烈建议您不要尝试这样做。每当您想读取或写入值时,您都应该始终创建一个新的 QSettings 对象,并确保在使用后将其删除。这应该足以保证一致性。