web-dev-qa-db-ja.com

Python UIウィジェット値を保存および復元するPyQt4関数?

自分でPython PyQt4モジュール関数を作成する前に...誰かがそのような関数を共有できるかどうか尋ねたかったのです。

PyQt4とqtDesignerを使用してGUIを構築している私のpythonプログラムの多くでは、QSettingsメソッドを使用して、閉じるときと起動するときにすべてのウィジェットのUI状態と値を保存および復元します。

この例は、いくつかのlineEdit、checkBox、およびradioButtonフィールドを保存および復元する方法を示しています。

UIをトラバースしてすべてのウィジェット/コントロールとその状態を見つけて保存できる関数(例:guisave())とそれらを復元できる別の関数(例:guirestore())を持っている人はいますか?

私のcloseEventは次のようになります。

#---------------------------------------------
# close by x OR call to self.close
#---------------------------------------------

def closeEvent(self, event):      # user clicked the x or pressed alt-F4...

    UI_VERSION = 1   # increment this whenever the UI changes significantly

    programname = os.path.basename(__file__)
    programbase, ext = os.path.splitext(programname)  # extract basename and ext from filename
    settings = QtCore.QSettings("company", programbase)    
    settings.setValue("geometry", self.saveGeometry())  # save window geometry
    settings.setValue("state", self.saveState(UI_VERSION))   # save settings (UI_VERSION is a constant you should increment when your UI changes significantly to prevent attempts to restore an invalid state.)

    # save ui values, so they can be restored next time
    settings.setValue("lineEditUser", self.lineEditUser.text());
    settings.setValue("lineEditPass", self.lineEditPass.text());

    settings.setValue("checkBoxReplace", self.checkBoxReplace.checkState());
    settings.setValue("checkBoxFirst", self.checkBoxFirst.checkState());

    settings.setValue("radioButton1", self.radioButton1.isChecked());

    sys.exit()  # prevents second call

MainWindowの初期化は次のようになります。

def __init__(self, parent = None):
    # initialization of the superclass
    super(QtDesignerMainWindow, self).__init__(parent)
    # setup the GUI --> function generated by pyuic4
    self.setupUi(self)

    #---------------------------------------------
    # restore gui position and restore fields
    #---------------------------------------------

    UI_VERSION = 1

    settings = QtCore.QSettings("company", programbase)    # http://pyqt.sourceforge.net/Docs/PyQt4/pyqt_qsettings.html

    self.restoreGeometry(settings.value("geometry"))
    self.restoreState(settings.value("state"),UI_VERSION) 

    self.lineEditUser.setText(str(settings.value("lineEditUser")))  # restore lineEditFile
    self.lineEditPass.setText(str(settings.value("lineEditPass")))  # restore lineEditFile

    if settings.value("checkBoxReplace") != None:
        self.checkBoxReplace.setCheckState(settings.value("checkBoxReplace"))   # restore checkbox
    if settings.value("checkBoxFirst") != None:
        self.checkBoxFirst.setCheckState(settings.value("checkBoxFirst"))   # restore checkbox

    value = settings.value("radioButton1").toBool()
    self.ui.radioButton1.setChecked(value)
16
panofish

OK、私は私が求めていたことを実行するために2つの関数を備えたモジュールを作成しました。一度理解してしまえば、それほど複雑ではありませんが、セッション間でウィジェットフィールドの値を保存する新しいpyqt guiプログラムを作成するたびに、多くの時間を節約できます。現在、lineEdit、checkBox、comboboxの各フィールドのみがコーディングされています。他の誰かが追加または改善したい場合(ラジオボタンなど)...私を含む他の人がそれを高く評価すると確信しています。

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

#===================================================================
# save "ui" controls and values to registry "setting"
# currently only handles comboboxes editlines & checkboxes
# ui = qmainwindow object
# settings = qsettings object
#===================================================================

def guisave(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)

#===================================================================
# restore "ui" controls with values stored in registry "settings"
# currently only handles comboboxes, editlines &checkboxes
# ui = QMainWindow object
# settings = QSettings object
#===================================================================

def guirestore(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
            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)   # restore checkbox

        #if isinstance(obj, QRadioButton):                

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

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() 
24
panofish

これは、元々mrによって共有された更新されたスニペットです。パノフィッシュ。これらの優れた機能は同じですが、PyQtとPython、必要に応じて小さな変更を加えたバージョンでは使用できません。Thxmr。Panofish、長寿命のオープンソースです!:)

変更点:

  • Python3およびPyQt5用に更新
  • ジオメトリの保存/復元を追加
  • QRadioButton save\restoreを追加しました
  • トライステートを回避するために、SetCheckState()がSetChecked()に置き換えられました

    def guisave(self):
    
      # Save geometry
        self.settings.setValue('size', self.size())
        self.settings.setValue('pos', self.pos())
    
        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.isChecked()
              settings.setValue(name, state)
    
          if isinstance(obj, QRadioButton):
              name = obj.objectName()
              value = obj.isChecked()  # get stored value from registry
              settings.setValue(name, value)
    
    
    def guirestore(self):
    
      # Restore geometry  
      self.resize(self.settings.value('size', QtCore.QSize(500, 500)))
      self.move(self.settings.value('pos', QtCore.QPoint(60, 60)))
    
      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 = (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 = (settings.value(name).decode('utf-8'))  # get stored value from registry
              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.setChecked(strtobool(value))  # restore checkbox
    
          if isinstance(obj, QRadioButton):
             name = obj.objectName()
             value = settings.value(name)  # get stored value from registry
             if value != None:
                 obj.setChecked(strtobool(value))
    
8
kazak

panofishと、QSlider/QSpinBoxのアップデートを追加している皆さんに感謝します。小さくてシンプルです。

guisaveで追加できます:

if isinstance(obj, QSpinBox):
    name  = obj.objectName()
    value = obj.value()             # get stored value from registry
    settings.setValue(name, value)

if isinstance(obj, QSlider):
    name  = obj.objectName()
    value = obj.value()             # get stored value from registry
    settings.setValue(name, value)

guirestoreで追加できます:

if isinstance(obj, QSlider):
    name = obj.objectName()
    value = settings.value(name)    # get stored value from registry
    if value != None:           
        obj. setValue(int(value))   # restore value from registry

if isinstance(obj, QSpinBox):
    name = obj.objectName()
    value = settings.value(name)    # get stored value from registry
    if value != None:
        obj. setValue(int(value))   # restore value from registry
4
odsa

QListWidgetのアップデートを追加しています。

Guisaveで:

if isinstance(obj, QListWidget):
    name = obj.objectName()
    settings.beginWriteArray(name)
    for i in range(obj.count()):
        settings.setArrayIndex(i)
        settings.setValue(name, obj.item(i).text())
    settings.endArray()

guirestoreで:

if isinstance(obj, QListWidget):
    name = obj.objectName()
    size = settings.beginReadArray(name)
    for i in range(size):
        settings.setArrayIndex(i)
        value = settings.value(name)  # get stored value from registry
        if value != None:
            obj.addItem(value)
    settings.endArray()
3
Daniel Ma

これらの回答が役に立ったので、それらをまとめて、重複を削除し、設定をグループ化するための名前を付けたバージョン(PySide2/Qt5用)を投稿すると思いました。

from PySide2.QtWidgets import *
import inspect

def GetHandledTypes():
    return (QComboBox, QLineEdit, QCheckBox, QRadioButton, QSpinBox, QSlider, QListWidget)

def IsHandledType(widget):
    return any(isinstance(widget, t) for t in GetHandledTypes())

#===================================================================
# save "ui" controls and values to registry "setting"
#===================================================================

def GuiSave(ui : QWidget, settings : QSettings, uiName="uiwidget"):
    namePrefix = f"{uiName}/"
    settings.setValue(namePrefix + "geometry", ui.saveGeometry())

    for name, obj in inspect.getmembers(ui):
        if not IsHandledType(obj):
            continue

        name = obj.objectName()
        value = None
        if isinstance(obj, QComboBox):
            index = obj.currentIndex()  # get current index from combobox
            value = obj.itemText(index)  # get the text for current index

        if isinstance(obj, QLineEdit):
            value = obj.text()

        if isinstance(obj, QCheckBox):
            value = obj.isChecked()

        if isinstance(obj, QRadioButton):
            value = obj.isChecked()

        if isinstance(obj, QSpinBox):
            value = obj.value()

        if isinstance(obj, QSlider):
            value = obj.value()

        if isinstance(obj, QListWidget):
            settings.beginWriteArray(name)
            for i in range(obj.count()):
                settings.setArrayIndex(i)
                settings.setValue(namePrefix + name, obj.item(i).text())
            settings.endArray()
        Elif value is not None:
            settings.setValue(namePrefix + name, value)

#===================================================================
# restore "ui" controls with values stored in registry "settings"
#===================================================================

def GuiRestore(ui : QWidget, settings : QSettings, uiName="uiwidget"):
    from distutils.util import strtobool

    namePrefix = f"{uiName}/"
    geometryValue = settings.value(namePrefix + "geometry")
    if geometryValue:
        ui.restoreGeometry(geometryValue)

    for name, obj in inspect.getmembers(ui):
        if not IsHandledType(obj):
            continue

        name = obj.objectName()
        value = None
        if not isinstance(obj, QListWidget):
            value = settings.value(namePrefix + name)
            if value is None:
                continue

        if isinstance(obj, QComboBox):
            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):
            obj.setText(value)

        if isinstance(obj, QCheckBox):
            obj.setChecked(strtobool(value))

        if isinstance(obj, QRadioButton):
            obj.setChecked(strtobool(value))

        if isinstance(obj, QSlider):
            obj.setValue(int(value))

        if isinstance(obj, QSpinBox):
            obj.setValue(int(value))

        if isinstance(obj, QListWidget):
            size = settings.beginReadArray(namePrefix + name)
            for i in range(size):
                settings.setArrayIndex(i)
                value = settings.value(namePrefix + name)
                if value is not None:
                    obj.addItem(value)
            settings.endArray()```
1
MatBailey