使用python 2.7.6/PyQt4处理设置模块中的QVariant

使用python 2.7.6/PyQt4处理设置模块中的QVariant,python,pyqt4,Python,Pyqt4,我以前在这个站点和其他平台上读过几个主题,但我的代码仍然不能按预期工作。我似乎不能把所有的拼图拼在一起,需要有人检查我的代码 我正在为QtiPlot程序编写一个插件。我正在使用Python2.7.6和PyQt4。我用QT设计器创建了插件GUI。我也是Python新手。我使用这些“旧”资源是因为我的前任使用过它们 我目前的任务是开发设置,即能够保存和恢复参数。 我在该网站上找到了一个用于此目的的模板: 我想将参数保存到Ini文件中。 然而,我有问题的QV变体。将保存表达式“PyQt4.QtCore

我以前在这个站点和其他平台上读过几个主题,但我的代码仍然不能按预期工作。我似乎不能把所有的拼图拼在一起,需要有人检查我的代码

我正在为QtiPlot程序编写一个插件。我正在使用Python2.7.6和PyQt4。我用QT设计器创建了插件GUI。我也是Python新手。我使用这些“旧”资源是因为我的前任使用过它们

我目前的任务是开发设置,即能够保存和恢复参数。 我在该网站上找到了一个用于此目的的模板:

我想将参数保存到Ini文件中。 然而,我有问题的QV变体。将保存表达式“PyQt4.QtCore.QVariant object at 0x08667FB0”,而不是我在插件中插入的字符串。我已经知道这是一个问题,因为QVariants没有正确地转换回Python对象

因此,为了手动将QVariants转换回来,我在restore函数中的QLineEdit对象的赋值中添加了短语“toString()”(注释掉的那行是以前的版本)。但是插件中我的QLineEdit块是空的,这让我很困惑。我在文档中读到,如果QVariant不包含一个预设类型(包括string),则返回一个空字符串。尽管我之前输入了一个字符串,但这种情况还是发生了

这是否意味着字符串首先没有正确保存?或者它意味着什么,我错过了什么,或者我做错了什么

我还注意到Ini文件中没有存储任何值,因此部分代码仍然存在缺陷。但我不确定这是因为save函数不起作用,还是因为Ini构造本身是错误的

此外,我尝试使用配置文件开头的SIP模块来解决我的问题(它也被注释掉了,因为它到目前为止对我不起作用)。但是,尽管我把它放在了代码的开头,我还是得到了一个错误“API'QVariant'已经设置为版本1”。我不明白SIP指令被覆盖的原因或原因。有办法解决这个问题吗

我的配置程序如下所示:

#import sip    
#sip.setapi('QVariant', 2)    
#sip.setapi('QString', 2)

import inspect    
import sys

from PyQt4.QtCore import *    
from PyQt4.QtGui import *

sys.path.append("C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages")

import PyQt4_Save_Restore_UI_Widget_Values

class app_conf(QtGui.QWidget):

    def __init__(self):

        super(self.__class__, self).__init__()

        self.version = 1.0

        QtCore.QCoreApplication.setOrganizationName("Organization")
        QtCore.QCoreApplication.setApplicationName("Application")
        QtCore.QSettings.setPath(QSettings.IniFormat, QSettings.UserScope, "C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages\\saved.ini")
        self.settings = QtCore.QSettings("C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages\\saved.ini", QSettings.IniFormat)

        from PyQt4 import uic

        self.ui = uic.loadUi(r"C:\Program Files (x86)/QtiPlot/app/03 UI Files/Config.ui")

        PyQt4_Save_Restore_UI_Widget_Values.gui_restore_settings(self.ui, self.settings)

        self.ui.closeEvent = self.closeEvent
        self.ui.show()


    def closeEvent(self, event):            
        PyQt4_Save_Restore_UI_Widget_Values.gui_save_settings(self.ui, self.settings)


window = app_conf()
#===================================================================
# Module with functions to save & restore qt widget values
# Written by: Alan Lilly 
# Website: http://panofish.net
#===================================================================

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import inspect


def gui_save_settings(ui, settings):

    #for child in ui.children():  # works like getmembers, but because it traverses the hierarachy, you would have to call guisave recursively to traverse down the tree

    for name, obj in inspect.getmembers(ui):
        #if type(obj) is QComboBox:  # this works similar to isinstance, but missed some field... not sure why?
        if isinstance(obj, QComboBox):
            name   = obj.objectName()      # get combobox name
            index  = obj.currentIndex()    # get current index from combobox
            text   = obj.itemText(index)   # get the text for current index
            settings.setValue(name, text)   # save combobox selection to registry

        if isinstance(obj, QLineEdit):
            name = obj.objectName()
            value = obj.text()
            settings.setValue(name, value)    # save ui values, so they can be restored next time

        if isinstance(obj, QCheckBox):
            name = obj.objectName()
            state = obj.checkState()
            settings.setValue(name, state)


def gui_restore_settings(ui, settings):

    for name, obj in inspect.getmembers(ui):
        if isinstance(obj, QComboBox):
            index  = obj.currentIndex()    # get current region from combobox
            #text   = obj.itemText(index)   # get the text for new selected index
            name   = obj.objectName()

            value = unicode(settings.value(name))  

            if value == "":
                continue

            index = obj.findText(value)   # get the corresponding index for specified string in combobox

            if index == -1:  # add to list if not found
                obj.insertItems(0,[value])
                index = obj.findText(value)
                obj.setCurrentIndex(index)
            else:
                obj.setCurrentIndex(index)   # preselect a combobox value by index    

        if isinstance(obj, QLineEdit):
            name = obj.objectName()
            #value = unicode(settings.value(name))  # get stored value from registry
            value = settings.value(name).toString()
            obj.setText(value)  # restore lineEditFile

        if isinstance(obj, QCheckBox):
            name = obj.objectName()
            value = settings.value(name)   # get stored value from registry
            if value != None:
                obj.setCheckState(value.toBool())   # restore checkbox


################################################################

if __name__ == "__main__":

    # execute when run directly, but not when called as a module.
    # therefore this section allows for testing this module!

    #print "running directly, not as a module!"

    sys.exit() 
我的设置模块(PyQt4_Save_Restore_UI_Widget_Values.py)如下所示:

#import sip    
#sip.setapi('QVariant', 2)    
#sip.setapi('QString', 2)

import inspect    
import sys

from PyQt4.QtCore import *    
from PyQt4.QtGui import *

sys.path.append("C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages")

import PyQt4_Save_Restore_UI_Widget_Values

class app_conf(QtGui.QWidget):

    def __init__(self):

        super(self.__class__, self).__init__()

        self.version = 1.0

        QtCore.QCoreApplication.setOrganizationName("Organization")
        QtCore.QCoreApplication.setApplicationName("Application")
        QtCore.QSettings.setPath(QSettings.IniFormat, QSettings.UserScope, "C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages\\saved.ini")
        self.settings = QtCore.QSettings("C:\\Program Files (x86)\\QtiPlot\\app\\02 Python Packages\\saved.ini", QSettings.IniFormat)

        from PyQt4 import uic

        self.ui = uic.loadUi(r"C:\Program Files (x86)/QtiPlot/app/03 UI Files/Config.ui")

        PyQt4_Save_Restore_UI_Widget_Values.gui_restore_settings(self.ui, self.settings)

        self.ui.closeEvent = self.closeEvent
        self.ui.show()


    def closeEvent(self, event):            
        PyQt4_Save_Restore_UI_Widget_Values.gui_save_settings(self.ui, self.settings)


window = app_conf()
#===================================================================
# Module with functions to save & restore qt widget values
# Written by: Alan Lilly 
# Website: http://panofish.net
#===================================================================

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import inspect


def gui_save_settings(ui, settings):

    #for child in ui.children():  # works like getmembers, but because it traverses the hierarachy, you would have to call guisave recursively to traverse down the tree

    for name, obj in inspect.getmembers(ui):
        #if type(obj) is QComboBox:  # this works similar to isinstance, but missed some field... not sure why?
        if isinstance(obj, QComboBox):
            name   = obj.objectName()      # get combobox name
            index  = obj.currentIndex()    # get current index from combobox
            text   = obj.itemText(index)   # get the text for current index
            settings.setValue(name, text)   # save combobox selection to registry

        if isinstance(obj, QLineEdit):
            name = obj.objectName()
            value = obj.text()
            settings.setValue(name, value)    # save ui values, so they can be restored next time

        if isinstance(obj, QCheckBox):
            name = obj.objectName()
            state = obj.checkState()
            settings.setValue(name, state)


def gui_restore_settings(ui, settings):

    for name, obj in inspect.getmembers(ui):
        if isinstance(obj, QComboBox):
            index  = obj.currentIndex()    # get current region from combobox
            #text   = obj.itemText(index)   # get the text for new selected index
            name   = obj.objectName()

            value = unicode(settings.value(name))  

            if value == "":
                continue

            index = obj.findText(value)   # get the corresponding index for specified string in combobox

            if index == -1:  # add to list if not found
                obj.insertItems(0,[value])
                index = obj.findText(value)
                obj.setCurrentIndex(index)
            else:
                obj.setCurrentIndex(index)   # preselect a combobox value by index    

        if isinstance(obj, QLineEdit):
            name = obj.objectName()
            #value = unicode(settings.value(name))  # get stored value from registry
            value = settings.value(name).toString()
            obj.setText(value)  # restore lineEditFile

        if isinstance(obj, QCheckBox):
            name = obj.objectName()
            value = settings.value(name)   # get stored value from registry
            if value != None:
                obj.setCheckState(value.toBool())   # restore checkbox


################################################################

if __name__ == "__main__":

    # execute when run directly, but not when called as a module.
    # therefore this section allows for testing this module!

    #print "running directly, not as a module!"

    sys.exit() 

最好的解决方案是使用
sip.setapi
。但要使其正常工作,必须在应用程序中首次导入PyQt之前调用它。因此,它需要进入主脚本,而不是配置模块:

#===================================================================
# Module with functions to save & restore qt widget values
# Written by: Alan Lilly 
# Website: http://panofish.net
#===================================================================
import sys
import sip
sip.setapi('QVariant', 2)    
sip.setapi('QString', 2)
from PyQt4.QtCore import *
from PyQt4.QtGui import *
import inspect

这将确保
QVariant
QString
始终自动转换为普通python类型-因此无需使用
unicode()
toString()
toBool()
等。

与Python2和SIP旧API一样,
toString()
将返回
QString
。对于
get
set
方法,必须使用
str
将其强制为Python字符串。关于
QCheckBox
,我使用了
toInt
方法,而不是
toBool
方法(这对我来说很好)

以下是保存和还原功能的修改版本:

def gui_save_settings(ui, settings):

    for _, obj in inspect.getmembers(ui):
        name   = obj.objectName()

        # Set QComboBox setting
        if isinstance(obj, QComboBox):
            value = str(obj.currentText()) # get current text from combobox
            settings.setValue(name, value)   # save combobox selection to registry

        # Set QLineEdit setting
        if isinstance(obj, QLineEdit):
            value = str(obj.text())
            settings.setValue(name, value)    # save ui values, so they can be restored next time

        # Set QCheckBox setting
        if isinstance(obj, QCheckBox):
            value = int(checkbox.isChecked())
            settings.setValue(name, value)

def gui_restore_settings(ui, settings):

    for _, obj in inspect.getmembers(ui):
        name   = obj.objectName()

        # Get QComboBox setting
        if isinstance(obj, QComboBox):
            value = str(settings.value(name).toString())  
            if value == "":
                continue

            index = obj.findText(value)   # get the corresponding index for specified string in combobox

            if index == -1:  # add to list if not found
                obj.addItem(value)
                index = obj.findText(value)

            obj.setCurrentIndex(index)   # preselect a combobox value by index
            continue

        # Get QLineEdit setting
        if isinstance(obj, QLineEdit):
            value = str(settings.value(name).toString())
            obj.setText(value)  # restore lineEditFile
            continue

        # Get QCheckBox setting
        if isinstance(obj, QCheckBox):
            value, res = settings.value(key).toInt() # get stored value from registry
            if res:
                obj.setCheckState(value)   # restore checkbox
            continue

谢谢你的回答!恐怕我已经试过了。我在代码的开头添加了这些行(参见注释掉的行)。我还尝试只将上面显示的两个文件加载到QtiPlot应用程序中。似乎PyQt以前已经被调用过,我不知道如何重写这个行为。也许我应该考虑使用Python 3来代替?@马林。是的,它看起来像是qtiplot预加载了PyQt4,因此您不能在正确的时间调用
setapi
。切换到Python 3可以解决这个问题,因为默认情况下它使用v2 API。然而,您的qtiplot安装似乎必须根据Python2进行编译,否则我认为您在尝试加载脚本时会看到错误。如果是这样的话,您还需要一个与Python 3兼容的qtiplot版本。如果您无法切换到Python 3,请编辑您的问题并添加
Config.ui
文件,以便其他人可以测试您的代码。谢谢您的回答!我知道我确实错过了一些东西。但是,当我尝试您的代码时,出现以下错误:语法错误:无效语法,对于行:value,res=settings.value(key).toInt())#从注册表获取存储值。为什么在这行中分配了两个参数?@Maryn根据
toInt
返回一个元组。编辑:有一个额外的括号,我修正了。再次感谢!现在我没有任何错误,但仍然没有保存任何值。我使用一个INI文件,并在其中存储了一些默认值。只要我使用这个文件,默认值就会恢复。当我停止使用INI文件时,我再次只存储“PyQt4.QtCore.QVariant object at…”字符串。我怀疑这可能是因为我没有正确设置我的应用程序?这些值是否可以存储到当前配置中的INI文件中?因为我只从QtiPlot加载代码,所以是否需要QtGUI.QApplication分配(如“main”文件)?还有什么原因呢?@Maryn确实,我没有使用和你相同的构造函数。我使用
QtCore.QSettings(“组织”、“应用程序”)
并让Qt处理目标设置文件。您可以尝试此构造函数,然后使用
setDefaultFormat(Format Format)
ti指定您的文件格式。再次感谢!我试图使用您的构造函数,但这并没有改变所描述的行为。我的意思是,当我将你的构造函数与“QtCore.QSettings.Ini格式”一起使用时,那么这些值应该被写入一个Ini文件,对吗?我不应该在应用程序文件夹中找到此文件吗?因为我在那里看不到任何新文件,因此无法检查这些值是否存储在这样的文件中。我还是不明白为什么它不起作用。我想我赚了一点