2016-09-17 25 views
2

我以前在这个网站和其他平台上读过几个主题,但是我的代码仍然不能按需要工作。我似乎无法将所有拼图拼凑在一起,需要有人来查看我的代码。在设置模块中使用python 2.7.6/PyQt4处理QVariants

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

我目前的任务是开发设置,即能够保存和恢复参数。 我在此网站上找到了一个用于此目的的模板:Python PyQt4 functions to save and restore UI widget values?

我想将参数保存到Ini文件中。 但是我有问题的QVariants。而不是我插入插件中的字符串,表达式“PyQt4.QtCore.QVariant对象在0x08667FB0”正在保存。我已经知道这是一个问题,因为QVariants没有被正确地转换回Python对象。因此,为了手动将QVariants转换回来,我在恢复功能中注释了QLineEdit-Objects的值赋值(注释掉的是以前的版本),我在短语“toString()”中添加了“toString()”这个词组。但是然后我的QLineEdit-Blocks插件是空的,这让我感到困惑。我在文档中读到,如果QVariant不包含预设类型之一(包括字符串),则返回空字符串。但是这种情况发生,虽然我之前输入了一个字符

这是否意味着字符串没有正确保存在第一位?否则它意味着什么,我错过了什么或者我做错了什么?

我也注意到没有值存储在Ini文件中,因此部分代码也是bug。但我不确定这是由于保存功能不起作用或因为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() 

我的设置模块(PyQt4_Save_Restore_UI_Widget_Values.py)看起来是这样的:

#=================================================================== 
# 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() 

回答

2

与在Python 2和SIP旧API中一样,toString()将返回QString。对于getset方法,您必须强制它使用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 
+0

感谢您的回答!我看到我确实错过了一些东西。但是,当我尝试你的代码时,我得到以下错误:语法错误:语法无效,对于行:值,res = settings.value(key).toInt())#从注册表中获取存储值。为什么在这一行中分配了两个参数? – Maryn

+0

@Maryn根据[documentation](http://pyqt.sourceforge.net/Docs/PyQt4/qvariant.html#toInt)'toInt'返回一个元组。编辑:有一个额外的括号,我修正了它。 – Frodon

+0

再次感谢!现在我没有任何错误,但仍然没有值被保存。我使用INI文件并在那里存储了一些默认值。当我使用这个文件时,默认值被恢复。当我停止使用INI文件时,我再次只将“PyQt4.QtCore.QVariant对象存储在......”字符串中。我怀疑这可能是因为我没有正确设置我的应用程序?值可以存储到当前配置中的INI文件中吗?是否需要QtGUI.QApplication赋值(如“__main__”文件),因为我只从QtiPlot加载我的代码?还有什么可能是原因? – Maryn

1

最好的解决方案是使用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 

这将确保QVariantQString总是自动转换为普通Python类型 - 因此没有必要使用unicode()toString()toBool()等。

+0

感谢您的回答!恐怕这是我已经尝试过的。我在代码的头部添加了这些行(参见注释掉的行)。我也尝试只将上面显示的两个文件加载到QtiPlot应用程序中。看来PyQt已经被调用过了,我不知道如何覆盖这个行为。也许我应该考虑使用Python 3呢? – Maryn

+0

@Maryn。是的,它看起来像QtiPilot预加载PyQt4,所以你不能在正确的时间调用'setapi'。切换到Python 3可以解决这个问题,因为它默认使用v2 API。但是,您的QtiPilot安装似乎必须针对Python 2进行编译,否则我认为您会在尝试加载脚本时看到错误。如果是这样的话,你还需要一个Python 3兼容版本的QtiPilot。如果您无法切换到Python 3,请编辑您的问题并添加'Config.ui'文件,以便其他人可以测试您的代码。 – ekhumoro

相关问题