首页 > 其他分享 >pyqt、pyside界面关闭后自动保存已设置参数

pyqt、pyside界面关闭后自动保存已设置参数

时间:2024-09-12 23:20:19浏览次数:14  
标签:控件 widget 界面 pyside self pyqt QLineEdit config MainWindow

超简单、低耦合! pyqt、pyside界面关闭后自动保存已设置参数

文章目录


(温馨提示:最底部领取无套路、免费打包好项目,直接运行!)

前言

在小才编写PyQt5、Pyside6界面程序时,界面上经常需要许多的QlineEditQCheckBox…等等控件,并且在程序运行之前经常要对这些控件手动输入参数,但是一旦我们程序运行完了并将界面关闭后,再重新启动,这些参数就需要重新设置,小才觉得很是麻烦。因此小才就写了一个超简单、低耦合,对已经写好的界面不需要做修改就能实现自动保存的程序!
演示:
演示

正文

初始思路

一开始的思路是在界面关闭事件closeEvent中获取界面上所有QLineEdit、QCheckBox等控件当前的值,然后保存至一个json文件中,程序启动的时候再一个一个的对应读取和设置。但是这样做就会存在几个问题:

  1. 麻烦。复杂。繁琐。有时候需求界面上有几十个输入框,输入框还有各自的命名,想想都难受啊。
  2. 项目与项目之间不通用。小才我呀不可能每写一个项目就写一次这种方式的自动保存,重复性工作太多,效率底下。
  3. 代码臃肿。

实现思路

小才想到实现依赖python中getattr()findChildren()函数。

1. getattr():用于返回一个对象的属性值。
def getattr(object, name, default=None): # known special case of getattr
    """
    getattr(object, name[, default]) -> value
    
    Get a named attribute from an object; getattr(x, 'y') is equivalent to x.y.
    When a default argument is given, it is returned when the attribute doesn't
    exist; without it, an exception is raised in that case.
    """
    pass
getattr(object, name[, default])
  • object – 对象。
  • name – 字符串,对象属性。
  • default – 默认返回值,如果不提供该参数,在没有对应属性时,将触发 AttributeError。
  • 返回值:返回对象属性值。

例:QlineEdit

  • 正常设置和取得值:
# 在主界面对象中有一个QLineEdit对象
self.lineEdit = QLineEdit(self)
# 正常设置值
self.lineEdit.setText("hello world")
# 正常获取值
a = self.lineEdit.text()
  • 使用getattr
# 在主界面对象中有一个QLineEdit对象
self.lineEdit = QLineEdit(self)
getattr(getattr(self, "lineEdit"), "setText")("hello world")
a = getattr(getattr(self, "lineEdit"), "text")()

这样我就可以使用lineEdit、text、setText属性字符串来动态的获取和设置某个属性。

2. findChildren():获得满足条件的所有子对象

PyQt5中的findChildren()是一个用于遍历QObject(如QWidget、QMainWindow等)及其所有子对象的方法。这个函数通过指定一个或多个QObjects作为查找路径,搜索并返回匹配特定类型或名称的所有子对象。

例:
如果你有一个窗口,并想找到所有的按钮,你可以这样做:

parent_widget = YourMainWindowInstance  # 替换成实际的窗口实例
buttons = parent_widget.findChildren(QPushButton)
for button in buttons:
    print(button.objectName())  # 打印每个按钮的名字

这里,QPushButton是你想要查找的类型。如果找到了匹配的对象,它们将作为一个列表返回;如果没有找到,则返回空列表。

代码实现

了解上面两个主要函数后

废话不多说直接上代码: 使用的虽然是pyside6,但是pyqt5的控件类名一致的,很容易平替。

 # 支持页面上以下控件的自动保存和回复 并可指定某些控件对象名排除自动保存
 QLineEdit: "QLineEdit",
 QComboBox: "QComboBox",
 QCheckBox: "QCheckBox",
 QRadioButton: "QRadioButton",
 QSpinBox: "QSpinBox",
 QDoubleSpinBox: "QDoubleSpinBox",
 QPlainTextEdit: "QPlainTextEdit",
 QTextEdit: "QTextEdit"

restore_screen.py

import json
import os.path

from PySide6.QtCore import QTimer
from PySide6.QtWidgets import QLineEdit, QCheckBox, QRadioButton, QSpinBox, QComboBox, QDoubleSpinBox, QTextEdit, \
    QPlainTextEdit

from check_except import check_except

'''
此模块用于恢复应用程序在上一次退出时的界面状态。
'''
class RestoreScreenModule:
    def __init__(self, main_ui):
        # 绑定主界面实例
        self.main_ui = main_ui

        # 配置文件存储路径初始化
        self.config_file_dir = "./config"
        self.config_file_name = "restore_screen.json"
        os.makedirs(self.config_file_dir, exist_ok=True)  # 创建目录(如果不存在)
        self.config_file_path = os.path.join(self.config_file_dir, self.config_file_name)

        # 定义需要保存信息的控件类型及对应获取控件值的方法
        self.save_widget_info = {
            QLineEdit: "text",
            QComboBox: "currentIndex",
            QCheckBox: "isChecked",
            QRadioButton: "isChecked",
            QSpinBox: "value",
            QDoubleSpinBox: "value",
            QTextEdit: "toPlainText",
            QPlainTextEdit: "toPlainText"
        }

        # 设置控件信息的方法字典  第一个元素:对设置的值需转换的类型,第二个元素:设置值的方法
        self.set_widget_info = {
            QLineEdit: (None, "setText"),
            QComboBox: (int, "setCurrentIndex"),
            QCheckBox: (None, "setChecked"),
            QRadioButton: (None, "setChecked"),
            QSpinBox: (int, "setValue"),
            QDoubleSpinBox: (float, "setValue"),
            QTextEdit: (None, "setPlainText"),
            QPlainTextEdit: (None, "setPlainText")
        }

        # 控件类名到字符串的映射
        self.widget_to_str_info = {
            QLineEdit: "QLineEdit",
            QComboBox: "QComboBox",
            QCheckBox: "QCheckBox",
            QRadioButton: "QRadioButton",
            QSpinBox: "QSpinBox",
            QDoubleSpinBox: "QDoubleSpinBox",
            QPlainTextEdit: "QPlainTextEdit",
            QTextEdit: "QTextEdit"
        }

        # 字符串到控件类的映射
        self.str_to_widget_info = {
            "QLineEdit": QLineEdit,
            "QComboBox": QComboBox,
            "QCheckBox": QCheckBox,
            "QRadioButton": QRadioButton,
            "QSpinBox": QSpinBox,
            "QDoubleSpinBox": QDoubleSpinBox,
            "QPlainTextEdit": QPlainTextEdit,
            "QTextEdit": QTextEdit
        }

        # 排除不需要保存状态的控件列表
        self.exclude_widget_list = [
            "lineEdit",
        ]

        # 初始化配置字典并尝试从文件中恢复上次的状态
        self.restore_last_config()

        # 设置定时器,每隔5秒保存当前界面状态
        self.timer = QTimer()
        self.timer.timeout.connect(self.save_current_screen)
        self.timer.start(5000)

    # 重置配置字典
    def reset_config_dict(self):
        self.config_dict = {}
        for key in self.str_to_widget_info.keys():
            self.config_dict[key] = {}

    # 使用装饰器处理异常
    @check_except()
    def restore_last_config(self):
        # 尝试从配置文件中读取并恢复状态
        if os.path.exists(self.config_file_path):
            with open(self.config_file_path, "r", encoding="utf-8") as f:
                self.config_dict = json.load(f)

            for key1, value1 in self.config_dict.items():
                process = self.set_widget_info.get(self.str_to_widget_info.get(key1))

                for widget_name, widget_value in value1.items():
                    if process[0] is not None:
                        widget_value = process[0](widget_value)

                    if hasattr(self.main_ui, widget_name):
                        widget = getattr(self.main_ui, widget_name)
                        getattr(widget, process[1])(widget_value)

    # 使用装饰器处理异常
    @check_except()
    def save_current_screen(self):
        # 重置配置字典
        self.reset_config_dict()

        # 遍历所有需要保存状态的控件,并记录它们的状态
        for key, value in self.save_widget_info.items():
            widget_str = self.widget_to_str_info.get(key)
            if widget_str is None:
                continue

            config_key = self.config_dict.get(widget_str)
            if config_key is None:
                continue

            for widget in self.main_ui.findChildren(key):
                widget_name = widget.objectName()
                if widget_name in self.exclude_widget_list:
                    continue

                self.config_dict[widget_str][widget_name] = getattr(widget, value)()

        # 将当前状态保存到文件中
        with open(self.config_file_path, "w", encoding="utf-8") as f:
            json.dump(self.config_dict, f, ensure_ascii=False, indent=4)

方法上的装饰器check_except是为了方便异常捕捉,小才不想因为显示报错而导致页面卡住然后退出。实现请看小才得另一篇文章python
程序运行异常与计算耗时@check_excpt装饰器
,不想看的话注释掉@check_except()即可。

使用案例

使用Qt designer简单制作一个界面包含一些常用的控件:
简单界面

界面testUI.py

# -*- coding: utf-8 -*-

################################################################################
## Form generated from reading UI file 'test.ui'
##
## Created by: Qt User Interface Compiler version 6.7.2
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################

from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
    QMetaObject, QObject, QPoint, QRect,
    QSize, QTime, QUrl, Qt)
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
    QFont, QFontDatabase, QGradient, QIcon,
    QImage, QKeySequence, QLinearGradient, QPainter,
    QPalette, QPixmap, QRadialGradient, QTransform)
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QDoubleSpinBox,
    QHBoxLayout, QLineEdit, QMainWindow, QPlainTextEdit,
    QRadioButton, QSizePolicy, QSpinBox, QTextEdit,
    QWidget)

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        if not MainWindow.objectName():
            MainWindow.setObjectName(u"MainWindow")
        MainWindow.resize(816, 322)
        self.centralwidget = QWidget(MainWindow)
        self.centralwidget.setObjectName(u"centralwidget")
        self.horizontalLayout = QHBoxLayout(self.centralwidget)
        self.horizontalLayout.setObjectName(u"horizontalLayout")
        self.spinBox = QSpinBox(self.centralwidget)
        self.spinBox.setObjectName(u"spinBox")
        self.spinBox.setMinimumSize(QSize(100, 0))
        self.spinBox.setMaximumSize(QSize(100, 16777215))

        self.horizontalLayout.addWidget(self.spinBox)

        self.doubleSpinBox = QDoubleSpinBox(self.centralwidget)
        self.doubleSpinBox.setObjectName(u"doubleSpinBox")
        self.doubleSpinBox.setMinimumSize(QSize(100, 0))
        self.doubleSpinBox.setMaximumSize(QSize(100, 16777215))

        self.horizontalLayout.addWidget(self.doubleSpinBox)

        self.comboBox = QComboBox(self.centralwidget)
        self.comboBox.addItem("")
        self.comboBox.addItem("")
        self.comboBox.addItem("")
        self.comboBox.setObjectName(u"comboBox")
        self.comboBox.setMinimumSize(QSize(100, 0))
        self.comboBox.setMaximumSize(QSize(100, 16777215))

        self.horizontalLayout.addWidget(self.comboBox)

        self.plainTextEdit = QPlainTextEdit(self.centralwidget)
        self.plainTextEdit.setObjectName(u"plainTextEdit")
        self.plainTextEdit.setMinimumSize(QSize(0, 100))
        self.plainTextEdit.setMaximumSize(QSize(16777215, 100))

        self.horizontalLayout.addWidget(self.plainTextEdit)

        self.textEdit = QTextEdit(self.centralwidget)
        self.textEdit.setObjectName(u"textEdit")
        self.textEdit.setMinimumSize(QSize(0, 100))
        self.textEdit.setMaximumSize(QSize(16777215, 100))

        self.horizontalLayout.addWidget(self.textEdit)

        self.checkBox = QCheckBox(self.centralwidget)
        self.checkBox.setObjectName(u"checkBox")

        self.horizontalLayout.addWidget(self.checkBox)

        self.radioButton = QRadioButton(self.centralwidget)
        self.radioButton.setObjectName(u"radioButton")

        self.horizontalLayout.addWidget(self.radioButton)

        self.lineEdit = QLineEdit(self.centralwidget)
        self.lineEdit.setObjectName(u"lineEdit")
        self.lineEdit.setMinimumSize(QSize(100, 0))
        self.lineEdit.setMaximumSize(QSize(100, 16777215))

        self.horizontalLayout.addWidget(self.lineEdit)

        MainWindow.setCentralWidget(self.centralwidget)

        self.retranslateUi(MainWindow)

        QMetaObject.connectSlotsByName(MainWindow)
    # setupUi

    def retranslateUi(self, MainWindow):
        MainWindow.setWindowTitle(QCoreApplication.translate("MainWindow", u"MainWindow", None))
        self.comboBox.setItemText(0, QCoreApplication.translate("MainWindow", u"1", None))
        self.comboBox.setItemText(1, QCoreApplication.translate("MainWindow", u"2", None))
        self.comboBox.setItemText(2, QCoreApplication.translate("MainWindow", u"3", None))

        self.checkBox.setText(QCoreApplication.translate("MainWindow", u"CheckBox", None))
        self.radioButton.setText(QCoreApplication.translate("MainWindow", u"RadioButton", None))
    # retranslateUi


设置主启动界面main.py

# -*- coding: utf-8 -*-
"""
@Time : 2024/9/12 21:40
@Auth : 公众号-人才兄呐
@File :main.py
@IDE :PyCharm
"""

import sys

from PySide6.QtWidgets import QMainWindow, QApplication

from restore_screen import RestoreScreenModule
from testUI import Ui_MainWindow

class MainUI(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainUI, self).__init__(parent)
        self.setupUi(self)

        # 设置自动恢复上次退出状态模块
        self.restore_screen_module = RestoreScreenModule(self)

    def closeEvent(self, event):
        # 关闭事件调用restore_screen_module模块保存当前状态
        self.restore_screen_module.save_current_screen()

if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = MainUI()
    win.show()

    sys.exit(app.exec())

感谢

“点赞+评论,让我知道你在关注我,感谢每一个支持我的人!”

“不要忘记关注我,点赞收藏,我会为你带来更多优质内容!”

“你的关注是我前进的动力,你的点赞是我创作的源泉。”

“点个赞吧!让我知道你在支持我,我会继续努力的!”

“关注我,点赞收藏,让我有更多的动力去创作更好的内容!”

“你的每一个点赞,都是我创作的动力,感谢你的关注和支持!”

“希望你喜欢我的内容,记得关注我哦!我会继续为大家带来更好的作品!”
感谢

资源获取

感谢您的支持和鼓励!

标签:控件,widget,界面,pyside,self,pyqt,QLineEdit,config,MainWindow
From: https://blog.csdn.net/hz1hz/article/details/142186773

相关文章

  • qt程序关闭界面后,进程依然没有退出
    一种关闭界面彻底退出的方式,main.cpp中加入//启用退出锁定QCoreApplication::setQuitLockEnabled(true);//在应用程序退出时终止后台进程QObject::connect(&a,&QCoreApplication::aboutToQuit,[](){QProcess::startDetached("taskkill/F/I......
  • 基于深度学习的骨龄检测识别系统(PyTorch+Pyside6+YOLOv5模型)
    骨龄是骨骼年龄的简称,需要借助于骨骼在X光摄像中的特定图像来确定。通常要拍摄左手手腕部位的X光片,医生通过X光片观察来确定骨龄。在2006年,《中华-05》骨龄标准被编入《中华人民共和国行业标准》,成为中国目前唯一的行业骨龄标准。而在《中华-05》中作者一般推荐使用RUS-CHN计......
  • 一个简约的uniapp登录界面,基于uniapp+vue3+uview-plus
    uniapp-vue3-template一个简约的uniapp登录界面,基于uniapp+vue3+uview-plus页面主要包括:用户登录,手机验证码登录,用户注册,重置密码等页面登录进去后为空白模板源码在文末界面源码uniapp登录界面源码......
  • ruoyi-vue 界面框架构造
    界面框架:我采用了flex布局,先分左右,然后右侧再分上下。步骤:1.首先实现简单的菜单1.1菜单是个菜单项数组[]1.2菜单项结构例子{id:'001',name:'历史轨迹',//菜单名称isTitle:true,//表示可以展开level:1,//level控制缩进,vue动态class使用expand:......
  • 震惊!!一男子用尽了各种方式都搜不到这个资源,于是他竟然将手伸向了......!?pyqt pyside
    震惊!!一男子用尽了各种方式都搜不到这个资源,于是他竟然将手伸向了......!?pyqtpyside随窗口自适应、可缩放、拖动QLabel需求场景实现功能和使用1.参数设置2.设置图片3.缩放4.拖动5.小惊喜(裁剪图片)完整使用案例1.使用QtDesigner设计一个简单界面2.引用制......
  • 界面控件DevExpress中文教程:如何PDF图形对象的可见性?
    DevExpress拥有.NET开发需要的所有平台控件,包含600多个UI控件、报表平台、DevExpressDashboardeXpressApp框架、适用于VisualStudio的CodeRush等一系列辅助工具。屡获大奖的软件开发平台DevExpress近期重要版本v24.1已正式发布,该版本拥有众多新产品和数十个具有高影响力的功......
  • Python Pyqt5 将ui文件转换成py文件
    命令行pyuicyour_ui_file.ui-ooutput_file.py如果是虚拟环境,则需要提前进入虚拟环境中执行pyuic命令uitopy文件的使用如果是ui文件转换过来的py文件,不要直接在此py文件中编写代码。如果你的ui文件发生变换就需要重新生成py文件,这个时候新的py文件就会覆盖历史的。正确使......
  • jsp超市管理系统设计与实现5ojjs本系统(程序+源码+数据库+调试部署+开发环境)带论文文档
    jsp超市管理系统设计与实现5ojjs本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表项目功能会员,商品分类,员工信息,热卖商品,订单信息,商品采购开题报告内容JSP超市管理系统设计与实现(5OJJS)开题内容报告一......
  • shp文件转换为CAD文件 (第三版) 这个软件的界面颜值挺高的
    上个月写了一个工具是关于shp文件转换为CAD文件,<shp文件转换为CAD文件(dxf格式)>前天写了一篇shp文件转换为CAD文件的博客(公众号),<shp文件转换为CAD文件 (改进版)>今天是周六,也没啥事做,所以我们继续来完善这个小工具吧!有个朋友反映这个小工具的存在可以改进的地方、问题,并......
  • PyQt GUI开发基础-1
    (目录)一、QFileDialog文件对话框控件方法说明getOpenFileName()获取一个打开文件的文件名getOpenFileNames()获取多个打开文件的文件名getSaveFileName()获取保存的文件名getExistingDirectory()获取一个打开的文件夹setAcceptMode()设置接收模式,取......