Я хочу сохранить настройки PyQt5 при закрытии приложения - PullRequest
1 голос
/ 08 февраля 2020

Я хочу сохранить настройки PyQt5 при закрытии приложения. Это связано с тем, что при следующем запуске он будет запущен с окончательными настройками. Итак, я написал такой код:

Это основной код пользовательского интерфейса.

# main_ui.py
import sys
from PyQt5.QtCore import QSettings
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QTabWidget, QVBoxLayout
from sub_ui import SubUI


class MainUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("A", "B")
        self.init_ui()

    def init_ui(self):
        tabs = QTabWidget()
        tabs.addTab(SubUI(), "SubUI")

        vlayout = QVBoxLayout()
        vlayout.addWidget(tabs)

        central_widget = QWidget()
        central_widget.setLayout(vlayout)
        self.setCentralWidget(central_widget)

        self.setWindowTitle("MainUI")
        if self.settings.contains("geometry"):
            print("LOAD: " + str(self.settings.value("geometry")))
            self.setGeometry(self.settings.value("geometry"))
        else:
            self.setGeometry(100, 100, 300, 300)
        self.show()

    def closeEvent(self, event):
        print("SAVE: " + str(self.settings.value("geometry")))
        self.settings.setValue("geometry", self.frameGeometry())


if __name__ == "__main__":
    APP = QApplication(sys.argv)
    ex = MainUI()
    sys.exit(APP.exec_())

Это код вспомогательного интерфейса.

# sub_ui.py
from PyQt5.QtCore import QSettings
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QLineEdit


class SubUI(QWidget):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("A", "B")
        self.label = QLabel("test")
        self.lineedit = QLineEdit()
        self.init_ui()
        self.load_settings()

    def __del__(self):
        self.save_settings()

    def init_ui(self):
        hlayout = QHBoxLayout()
        hlayout.addWidget(self.label)
        hlayout.addWidget(self.lineedit)
        self.setLayout(hlayout)

    def save_settings(self):
        self.settings.setValue("label", self.lineedit.text())

    def load_settings(self):
        if self.settings.contains("label"):
            self.lineedit.setText(self.settings.value("label"))

Существует два проблемы.

1. Изменено frameGeometry

Я запустил эту программу и просто закрыл, щелкнув по значку [X]. Но значение self.frameGeometry () меняется. Почему это произошло?

=== Дополнительная информация ===

Я просто трижды запустил вышеуказанную программу и выключил ее, нажав X.

LOAD: PyQt5.QtCore.QRect(1289, 370, 544, 604) 
SAVE: PyQt5.QtCore.QRect(1289, 370, 544, 604) 

LOAD: PyQt5.QtCore.QRect(1288, 339, 546, 636) 
SAVE: PyQt5.QtCore.QRect(1288, 339, 546, 636) 

LOAD: PyQt5.QtCore.QRect(1287, 308, 548, 668) 
SAVE: PyQt5.QtCore.QRect(1287, 308, 548, 668) 

Значение frameGeometry изменилось само собой.

И это является исходной проблемой моей программы.

LOAD: PyQt5.QtCore.QRect(852, 217, 1108, 1050)
SAVE: PyQt5.QtCore.QRect(851, 186, 1110, 1082)

LOAD: PyQt5.QtCore.QRect(851, 186, 1110, 1082)
SAVE: PyQt5.QtCore.QRect(850, 155, 1112, 1114)

LOAD: PyQt5.QtCore.QRect(850, 155, 1112, 1114)
SAVE: PyQt5.QtCore.QRect(849, 124, 1114, 1146)

===

Как я могу сделать значение frameGeometry непротиворечивым?

2. Не удается сохранить настройки sub_ui .

Когда эта программа закрывается, она возвращает ошибку.

RuntimeError: завернутый объект C / C ++ типа QSettings был удалено

Поэтому я не могу сохранить значения.

Как я могу делать то, что хочу?

1 Ответ

1 голос
/ 08 февраля 2020
  1. Я не воспроизводлю его на Linux. Но вы можете использовать saveGeometry() и restoreGeometry():
class MainUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("A", "B")
        self.init_ui()

    def init_ui(self):
        # ...
        self.setWindowTitle("MainUI")
        self.load_settings()
        self.show()

    def closeEvent(self, event):
        self.save_settings()
        super().closeEvent(event)

    def save_settings(self):
        self.settings.setValue("geometry", self.saveGeometry())

    def load_settings(self):
        if self.settings.contains("geometry"):
            self.restoreGeometry(self.settings.value("geometry"))
        else:
            self.setGeometry(100, 100, 300, 300)

В методе __del__ объекты, которые зависят от SubUI как дочерние виджеты, уже уничтожены, что указано в сообщении об ошибке, полученном с помощью OP.

С другой стороны, только closeEvent() метод окна (MainUI), поскольку он единственный, который закрывается, так что соответствующий метод сохранения всех данных в QSettings реализовал обобщенный метод c для сохранения данных.

main_ui.py

class MainUI(QMainWindow):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("A", "B")
        self.init_ui()

    def init_ui(self):
        # ...

    def closeEvent(self, event):
        <b>for w in self.findChildren(QWidget) + [self]:
            if hasattr(w, "save_settings") and callable(w.save_settings):
                w.save_settings()</b>
        super().closeEvent(event)

    def save_settings(self):
        self.settings.setValue("geometry", self.frameGeometry())

sub_ui.py

from PyQt5.QtCore import QSettings
from PyQt5.QtWidgets import QWidget, QHBoxLayout, QLabel, QLineEdit


class SubUI(QWidget):
    def __init__(self):
        super().__init__()
        self.settings = QSettings("A", "B")
        self.label = QLabel("test")
        self.lineedit = QLineEdit()
        self.init_ui()
        self.load_settings()

    def init_ui(self):
        hlayout = QHBoxLayout(self)
        hlayout.addWidget(self.label)
        hlayout.addWidget(self.lineedit)

    def save_settings(self):
        self.settings.setValue("label", self.lineedit.text())

    def load_settings(self):
        if self.settings.contains("label"):
            self.lineedit.setText(self.settings.value("label"))
...