2016-09-17 87 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

相關問題