python - 如何使用 pyQt 和 appScheduler 更改视图?
问题描述
我是python新手。我正在编写桌面应用程序,它应该每 x 分钟提醒用户一次练习。当计数器到达时间应用程序应更改视图以查看视频。
在应用程序中,我使用 Python 3.7、appScheduler、event-notifier、 pyQt 5和Designer。
整个应用程序使用一个窗口。我QStackedWidget
用来改变视图之间。
为了实现我的目标,我appScheduler
在我的主控制器动作中运行。在 x 次之后,它会触发应该更改视图的操作。
EventDispatcher().getDispatcher().raise_event("onSettingsUpdate", view=view)
听众:
# ...
scheduler.getScheduler().add_job(self.changeView, 'interval', [view], minutes=time, id="exercise_block_scn_3", replace_existing=True, )
# ...
def changeView(self, view):
view.page_main.setCurrentWidget(view.view_video)
当我尝试运行应用程序时出现错误:
'job_state': pickle.dumps(job.__getstate__(), self.pickle_protocol)
TypeError:无法腌制“QWidget”对象
我搜索了 StackOverflow 以了解这个问题。我发现,当我尝试将视图设置为函数参数时,它使用指针对象。AppScheduler 使用主应用程序以外的其他线程,它会产生问题。AppScheduler 无法从第一个威胁访问内存。
我正在寻找解决这个问题的好方法。一种解决方案是覆盖视图对象并将其更改为停止使用指针。当我使用 desinger 生成文件时,我认为这不是一个好的解决方法。
你有想法如何以很好的方式解决它吗?
为了获得更好的图片,这里是 git repo 的链接: https ://github.com/TheGeniesis/PAK
PR 与我试图解决描述的问题的最后更改 https://github.com/TheGeniesis/PAK/pull/23/files
相关更改在这里:
编辑:
这是最简单的例子:
主视图.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'untitled.ui'
#
# Created by: PyQt5 UI code generator 5.14.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.stackedWidget = QtWidgets.QStackedWidget(self.centralwidget)
self.stackedWidget.setGeometry(QtCore.QRect(210, 30, 441, 471))
self.stackedWidget.setObjectName("stackedWidget")
self.view_main = QtWidgets.QWidget()
self.view_main.setObjectName("view_main")
self.label = QtWidgets.QLabel(self.view_main)
self.label.setGeometry(QtCore.QRect(90, 80, 67, 17))
self.label.setObjectName("label")
self.stackedWidget.addWidget(self.view_main)
self.view_wideo = QtWidgets.QWidget()
self.view_wideo.setObjectName("view_wideo")
self.label_2 = QtWidgets.QLabel(self.view_wideo)
self.label_2.setGeometry(QtCore.QRect(220, 110, 67, 17))
self.label_2.setObjectName("label_2")
self.stackedWidget.addWidget(self.view_wideo)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
self.stackedWidget.setCurrentIndex(1)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.label.setText(_translate("MainWindow", "Main"))
self.label_2.setText(_translate("MainWindow", "Video"))
if __name__ == "__main__":
import sys
from scheduler import Foo
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
foo = Foo()
foo.bar(ui)
sys.exit(app.exec_())
调度程序.py:
from MainView import Ui_MainWindow
from apscheduler.schedulers.qt import QtScheduler
scheduler = QtScheduler({
'apscheduler.jobstores.default': {
'type': 'sqlalchemy',
'url': 'sqlite:///jobs.sqlite'
},
'apscheduler.executors.default': {
'class': 'apscheduler.executors.pool:ThreadPoolExecutor',
'max_workers': '20'
},
'apscheduler.executors.processpool': {
'type': 'processpool',
'max_workers': '5'
},
'apscheduler.job_defaults.coalesce': 'false',
'apscheduler.job_defaults.max_instances': '3',
'apscheduler.timezone': 'UTC',
})
scheduler.start()
def changeView(view: Ui_MainWindow):
print("run")
view.stackedWidget.setCurrentWidget(view.view_wideo)
class Foo:
def bar(self, view):
time = 0.1
print("asdasd")
scheduler.add_job(changeView, 'interval', [view], seconds=time, id="exercise_block_scn_1", replace_existing=True, )
解决方案
由于您的类没有任何内部状态,并且如果这是导致问题的类,您可以试试这个:
class ExerciseTimeListener:
__view: Ui_MainWindow
def changeView(self, view):
view.page_main.setCurrentWidget(view.view_video)
def __getstate__(self):
return dict()
def __getstate__(self, state):
pass
编辑:问题是QObject
作为函数的参数给出的。所以想法是改变那个论点,但仍然能够检索视图。
您可以将视图名称作为字符串给出,并在主体函数中调用 agetView(view_name)
来检索此视图。Foo
实例化类时,名称和视图之间的关系可以使用全局字典来完成。
考虑从调用者脚本注册视图MainView.py
:
if __name__ == "__main__":
import sys
from scheduler import Foo
from scheduler import viewDict
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
# Register the view
viewDict[ui.objectName()] = ui
foo = Foo()
foo.bar(ui)
sys.exit(app.exec_())
这将是scheduler.py
:
viewDict = {}
def getView(view_name):
return viewDict.get(view_name)
def changeView(view_name: str):
print("run")
view = getView(view_name)
# Check if the requested view is registered
if view:
view.stackedWidget.setCurrentWidget(view.view_wideo)
else:
print("No view called {}".format(view_name))
class Foo:
def bar(self, view):
time = 0.1
print("asdasd")
scheduler.add_job(changeView, 'interval', [view.objectName()], seconds=time, id="exercise_block_scn_1", replace_existing=True, )
推荐阅读
- aurelia - Aurelia 非 html-only 自定义元素 notrendering
- winforms - 如何将我的表单应用程序发布到 Internet?
- jenkins - 詹金斯管道sh returnStatus抛出异常
- database - B-Tree 与 T-Tree - 对于较低的工作负载,哪个更好?
- c# - 为什么 Expression.Call 抛出参数错误
- c# - 从 WebApi 调用 html 页面,URI 无效:无法确定 URI 的格式
- vue.js - 需要帮助在 VUE 中向父组件发送值
- r - 如何在R中堆叠字符列表的元素
- javascript - 在不使用数据库的情况下与 JavaScript 关联
- python - Conda 安装图形工具在 win-64 上失败