python - 由于 QtDesigner 中提升的小部件,检测 PyQt5 脚本的重新加载?
问题描述
很多时候,我需要在 QtDesigner 中设计的 PyQt5 GUI 中完成一些任务,这些任务足够小,我想将所有代码保存在一个 .py 文件中。因此,考虑这个 PyQt5 示例:
test3.py
:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui, uic
mod_name = vars(sys.modules[__name__])['__package__'] # SO:1389044
code_exec_as = 'module named {}'.format(mod_name) if mod_name else 'script'
cmdline = "{} {}".format( sys.executable, " ".join(sys.argv) )
try: # SO:6038898
reloading
except NameError:
reloading = False # means the module is being imported
else:
reloading = True # means the module is being reloaded
print("Starting: code executed as {}; reloading {}; command line '{}'".format(code_exec_as, reloading, cmdline))
class MyCustomButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
print("MyCustomButton init!")
class MyMainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
uic.loadUi("test3.ui", self)
self.show()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MyMainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
test3.ui
:
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>232</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item>
<widget class="MyCustomButton" name="pushButton_2">
<property name="text">
<string>CustomPushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>382</width>
<height>21</height>
</rect>
</property>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<customwidgets>
<customwidget>
<class>MyCustomButton</class>
<extends>QPushButton</extends>
<header>test3</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>
当我从命令行运行它时,我得到:
$ python3 test3.py
Starting: code executed as script; reloading False; command line 'C:/msys64/mingw64/bin/python3.exe test3.py'
Starting: code executed as script; reloading False; command line 'C:/msys64/mingw64/bin/python3.exe test3.py'
MyCustomButton init!
请注意,“开始:...”打印输出已运行两次:显然:
- 第一次是由于脚本被正常调用
- 第二次是由于
pushButton_2
在.ui
被提升为一个MyCustomButton
类,该类被列为定义在 中test3.py
,因此需要重新加载文件以便MyCustomButton
读取类定义
我可以从脚本内部(更具体地说,从导入之后但在任何类定义和__main__
调用之前的代码部分)以某种方式检测脚本正在运行的时间吗?
正如你所看到的,我已经尝试了一些东西test3.py
,基于:
...但是这些方法为脚本的两次“运行”提供了相同的输出,因此我无法使用它们来区分脚本是在第一次运行还是第二次运行。
解决方案
好的,我想我明白了:看看如何列出导入的模块?- 然后打印模块并进行比较:事实证明,脚本的第一次运行,模块较少sys.modules
- 更具体地说,在脚本的第二次运行中,第一次运行中不存在类,最重要PyQt5.uic.Loader
的是存在于第二次运行中,并且test3
(Python 脚本本身的名称/类,如在 QtDesigner 文件中使用的那样)存在。因此,可以使用这两个类别中的任何一个来进行区分。
因此,我将脚本更改为:
import sys
from PyQt5 import QtCore, QtWidgets, QtGui, uic
mod_name = vars(sys.modules[__name__])['__package__'] # SO:1389044
code_exec_as = 'module named {}'.format(mod_name) if mod_name else 'script'
cmdline = "{} {}".format( sys.executable, " ".join(sys.argv) )
try: # SO:6038898
reloading
except NameError:
reloading = False # means the module is being imported
else:
reloading = True # means the module is being reloaded
first_time_run = not( 'PyQt5.uic.Loader' in sys.modules.keys() )
print("Starting: code executed as {}; reloading {}; command line '{}'; num modules {}; first_time_run {}".format(code_exec_as, reloading, cmdline, len(sys.modules.keys()), first_time_run))
#print("..in sys.modules.keys():\n {}".format( "\n ".join( sorted(sys.modules.keys()) ) ))
class MyCustomButton(QtWidgets.QPushButton):
def __init__(self, parent=None):
super().__init__(parent)
print("MyCustomButton init!")
class MyMainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MyMainWindow, self).__init__()
uic.loadUi("test3.ui", self)
self.show()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MyMainWindow()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
...现在打印输出是:
$ python3 test3.py
Starting: code executed as script; reloading False; command line 'C:/msys64/mingw64/bin/python3.exe test3.py'; num modules 113; first_time_run True
Starting: code executed as script; reloading False; command line 'C:/msys64/mingw64/bin/python3.exe test3.py'; num modules 117; first_time_run False
MyCustomButton init!
...这向我证实,第一次运行被正确检测到。
推荐阅读
- sql - Postregsql 根据列值将检索到的一条记录转换为两条记录
- javascript - 如何将括号内的逗号分隔字符串转换为Javascript中的数组?
- angular - 组件不是已知元素
- linux - 在 Amazon linux bootstrap 上安装 Linux 服务
- javascript - eval 的替代数学替换
- kubernetes - 使用 Terraform 和节点组向 EKS 节点添加角色
- vuetify.js - Vuetify v-model 和 v-btn 点击事件
- amazon-web-services - 为 GCP 模拟类似于“sts 承担角色”的行为,以在本地环境中设置全局身份验证
- powershell - 测试连接powershell
- php - 如何在 Laravel 中将降价文本传递给降价刀片?