【问题标题】:Detect reload of PyQt5 script, due to promoted widget in QtDesigner?由于 QtDesigner 中提升的小部件,检测 PyQt5 脚本的重新加载?
【发布时间】:2020-09-14 09:28:08
【问题描述】:

通常,我需要在 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!

请注意,“Starting: ...”打印输出已经运行了两次:显然:

  • 第一次是由于脚本正常调用
  • 第二次是由于.ui中的pushButton_2被提升为MyCustomButton类,该类被列为在test3.py中定义,因此需要重新加载该文件,以便MyCustomButton类定义被读取

我能否从脚本内部(更具体地说,从导入之后但在任何类定义和 __main__ 调用之前的代码部分)以某种方式检测脚本正在运行的时间?

如你所见,我已经在test3.py 中尝试过一些东西,基于:

...但是这些方法为脚本的两次“运行”提供了相同的输出,因此我无法使用它们来区分脚本是在第一次运行还是在第二次运行。

【问题讨论】:

  • 为什么需要“检测”重新加载?
  • 谢谢@musicamante - 这是因为我有一些导入在我的一些遵循这种模式的脚本中进行了一些硬件初始化,我宁愿在脚本运行时只运行一次该代码。

标签: python pyqt5 qt-designer


【解决方案1】:

好的,我想我明白了:查看How to list imported modules? - 然后打印模块并进行比较:结果是,第一次运行脚本,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!

...这向我确认,第一次运行被正确检测到。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-12
    • 1970-01-01
    • 2020-11-16
    • 2011-10-08
    • 2021-09-20
    • 2021-10-21
    • 1970-01-01
    相关资源
    最近更新 更多