python - 在 Pyside2 for Python 上显示应用程序后,我们如何刷新事件?
问题描述
我想用 Pyside2 GUI 创建一个 python 软件。我使用 Qt Designer 设计了 GUI,并生成了一个 .ui 文件,我将其加载到我的 Python 脚本中。在显示应用程序具有模块化类之后,我正在寻找一种放置“事件侦听器”的方法,我不想将所有 connect() 方法放在类 init 中。
我无法将我的类初始化和 self.show() 分开,所以我需要将这些行放在 .show() 方法之后:
self.XMLButtonFolder = QPushButton(...)
self.XMLButtonFolder.clicked.connect(self.method)
这是我的类初始化(是的,它是一个线程):
def __init__(self):
self.app = QApplication([])
loader = QUiLoader()
print("Loading mainwindow.ui file")
self.window = loader.load(QFile("mainwindow.ui"))
if self.window is not None:
print("mainwindow.ui loaded")
else:
print("Error loading mainwindow.ui")
# XML
self.XMLButtonFolder = self.window.findChild(QPushButton, "XMLButtonFolder")
self.XMLButtonFolder.clicked.connect(self.openBoxFolder_XML)
# Report
self.ReportButtonFolder = self.window.findChild(QPushButton, "ReportButtonFolder")
self.ReportButtonFolder.clicked.connect(self.openBoxFolder_Report)
# If you uncomment the following line, the eventListener() method will be correctly called ..
# self.window.findChild(QPushButton, "XMLGenerateReport").clicked.connect(self.eventListener)
self.window.show()
sys.exit(self.app.exec_())
在同一个类中,我添加了一个函数来创建新连接并从另一个按钮检测“点击”事件
def addEventListener(self, qtype, qname):
self.eventlistenerresult = False
self.__widget.findChild(self.elementtype[qtype], qname).clicked.connect(self.eventListener)
这是主程序:
myapp = Application()
myapp.addEventListener("Button", "XMLGenerateReport")
问题是我没有刷新窗口的方法,所以没有触发事件(run() 方法中的一组有效,但后面的一组没有)
我希望能够触发名为“XMLGenerateReport”的按钮的事件,即使在 .show() 之后调用了 .connect() 方法
我们怎样才能做到这一点?
可复制的示例:(是的,我知道,在这个示例中,它只能在事件中使用,但对我来说没关系) main.py:
from Window import Application
import threading
def GenerateDocument():
print("Document generated !")
class ProgramThread(threading.Thread):
def run(self):
while not myapp.getEventListenerStatus():
time.sleep(1.0)
print("checking Generate button")
GenerateDocument()
myapp = Application()
myapp.addEventListener("Button", "XMLGenerateReport")
thr = ProgramThread()
thr.start()
窗口.py:
from PySide2.QtUiTools import QUiLoader
from PySide2.QtWidgets import QApplication, QPushButton, QFileDialog, QWidget, QLineEdit
from PySide2.QtCore import QFile
from PySide2 import QtWidgets
import sys
import threading
class Application(QtWidgets.QWidget):
elementtype = {
"Button": QPushButton
}
eventlistenerresult = None
app = None
__widget = None
XMLButtonFolder = None
ReportButtonFolder = None
def __init__(self):
self.app = QApplication([])
loader = QUiLoader()
print("Loading mainwindow.ui file")
self.window = loader.load(QFile("mainwindow.ui"))
if self.window is not None:
print("mainwindow.ui loaded")
else:
print("Error loading mainwindow.ui")
# XML
self.XMLButtonFolder = self.window.findChild(QPushButton, "XMLButtonFolder")
self.XMLButtonFolder.clicked.connect(self.openBoxFolder_XML)
# Report
self.ReportButtonFolder = self.window.findChild(QPushButton, "ReportButtonFolder")
self.ReportButtonFolder.clicked.connect(self.openBoxFolder_Report)
# If you uncomment the following line, the eventListener() method will be correctly called ..
# self.window.findChild(QPushButton, "XMLGenerateReport").clicked.connect(self.eventListener)
self.window.show()
sys.exit(self.app.exec_())
def openBoxFolder_XML(self):
# Works
dialog = QtWidgets.QFileDialog(self.window)
dialog.setFileMode(QFileDialog.ExistingFile)
path, _ = dialog.getOpenFileName(self.window, 'Sélectionnez un fichier .xml', filter='XML files (*.xml)')
self.window.findChild(QLineEdit, "XMLInputFolder").setText(path)
def openBoxFolder_Report(self):
# Works
dialog = QFileDialog(self.window)
dialog.setFileMode(QFileDialog.Directory)
path, _ = dialog.getOpenFileName()
self.window.findChild(QLineEdit, "ReportInputFolder").setText(path)
def addEventListener(self, qtype, qname):
self.eventlistenerresult = False
self.window.findChild(self.elementtype[qtype], qname).clicked.connect(self.eventListener)
def eventListener(self):
# Never called
print("clicked !")
self.eventlistenerresult = True
def getEventListenerStatus(self):
return self.eventlistenerresult # Return true if the button handled by addEventListener has been pressed
主窗口.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>696</width>
<height>222</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLineEdit" name="XMLInputFolder">
<property name="geometry">
<rect>
<x>40</x>
<y>60</y>
<width>531</width>
<height>20</height>
</rect>
</property>
<property name="whatsThis">
<string><html><head/><body><p>Entrez ici le dossier où ce trouve le fichier .xml à utiliser</p></body></html></string>
</property>
</widget>
<widget class="QLabel" name="XMLInputFolderLabel">
<property name="geometry">
<rect>
<x>40</x>
<y>40</y>
<width>171</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Dossier contenant les fichiers .XML</string>
</property>
</widget>
<widget class="QPushButton" name="XMLGenerateReport">
<property name="geometry">
<rect>
<x>40</x>
<y>150</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>Generate</string>
</property>
</widget>
<widget class="QLineEdit" name="ReportInputFolder">
<property name="geometry">
<rect>
<x>40</x>
<y>110</y>
<width>531</width>
<height>20</height>
</rect>
</property>
</widget>
<widget class="QLabel" name="ReportInputFolderLabel">
<property name="geometry">
<rect>
<x>40</x>
<y>90</y>
<width>81</width>
<height>16</height>
</rect>
</property>
<property name="text">
<string>Dossier de sortie</string>
</property>
</widget>
<widget class="QPushButton" name="XMLButtonFolder">
<property name="geometry">
<rect>
<x>580</x>
<y>60</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
<widget class="QPushButton" name="ReportButtonFolder">
<property name="geometry">
<rect>
<x>580</x>
<y>110</y>
<width>75</width>
<height>23</height>
</rect>
</property>
<property name="text">
<string>...</string>
</property>
</widget>
</widget>
<widget class="QMenuBar" name="menubar">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>696</width>
<height>21</height>
</rect>
</property>
<widget class="QMenu" name="menuReport_Generation_Level_1">
<property name="title">
<string>Fichier</string>
</property>
<addaction name="actionQuitter"/>
</widget>
<addaction name="menuReport_Generation_Level_1"/>
</widget>
<widget class="QStatusBar" name="statusbar"/>
<action name="actionQuitter">
<property name="text">
<string>Quitter</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>
解决方案
您的问题是 self.app.exec_ () 不允许执行以下行,因为它允许执行事件循环,因此必须最后执行该行。在这种情况下,我们创建一个只调用该函数的 run 方法:
窗口.py
class Application(QtWidgets.QWidget):
# ...
def __init__(self):
# ...
self.ReportButtonFolder.clicked.connect(self.openBoxFolder_Report)
# If you uncomment the following line, the eventListener() method will be correctly called ..
# self.window.findChild(QPushButton, "XMLGenerateReport").clicked.connect(self.eventListener)
self.window.show()
def run(self):
return self.app.exec_()
主文件
# ...
myapp = Application()
myapp.addEventListener("Button", "XMLGenerateReport")
thr = ProgramThread()
thr.start()
sys.exit(myapp.run())
尽管您之前的代码可能会带来长期问题,因为 eventlistenerresult 是一个可以在 2 个线程中访问的变量,这很危险,因为线程可以竞争。我更喜欢使用信号。
窗口.py
import sys
from PySide2 import QtCore, QtWidgets, QtUiTools
class Application:
def __init__(self, arguments):
self.app = QtWidgets.QApplication(arguments)
loader = QtUiTools.QUiLoader()
print("Loading mainwindow.ui file")
self.window = loader.load(QtCore.QFile("mainwindow.ui"))
if self.window is not None:
print("mainwindow.ui loaded")
else:
print("Error loading mainwindow.ui")
sys.exit(-1)
self.XMLButtonFolder = self.window.findChild(
QtWidgets.QPushButton, "XMLButtonFolder"
)
self.ReportButtonFolder = self.window.findChild(
QtWidgets.QPushButton, "ReportButtonFolder"
)
self.XMLInputFolder = self.window.findChild(
QtWidgets.QLineEdit, "XMLInputFolder"
)
self.ReportInputFolder = self.window.findChild(
QtWidgets.QLineEdit, "ReportInputFolder"
)
self.XMLGenerateReport = self.window.findChild(
QtWidgets.QPushButton, "XMLGenerateReport"
)
self.ReportButtonFolder.clicked.connect(self.openBoxFolder_Report)
self.XMLButtonFolder.clicked.connect(self.openBoxFolder_XML)
# If you uncomment the following line, the eventListener() method will be correctly called ..
# self.window.findChild(QPushButton, "XMLGenerateReport").clicked.connect(self.eventListener)
self.window.show()
def run(self):
return self.app.exec_()
def openBoxFolder_XML(self):
# Works
dialog = QtWidgets.QFileDialog(self.window)
dialog.setFileMode(QFileDialog.ExistingFile)
path, _ = dialog.getOpenFileName(
self.window,
"Sélectionnez un fichier .xml",
filter="XML files (*.xml)",
)
self.XMLInputFolder.setText(path)
def openBoxFolder_Report(self):
# Works
dialog = QFileDialog(self.window)
dialog.setFileMode(QFileDialog.Directory)
path, _ = dialog.getOpenFileName()
self.ReportInputFolder.setText(path)
主文件
import sys
from PySide2 import QtCore
from Window import Application
def GenerateDocument():
print("Document generated !")
class Worker(QtCore.QObject):
@QtCore.Slot()
def task(self):
GenerateDocument()
if __name__ == "__main__":
myapp = Application(sys.argv)
thread = QtCore.QThread()
thread.start()
worker = Worker()
worker.moveToThread(thread)
myapp.XMLGenerateReport.clicked.connect(worker.task)
res = myapp.run()
thread.quit()
thread.wait()
sys.exit(res)
推荐阅读
- javascript - 将输入添加到 div
- powershell - 将多个文本文件数据添加到带有 powershell 的 csv 文件到特定列中
- streamsets - 管道未从源中获取所有行/记录
- javascript - 如何使用 reduce() 按对象属性对数组进行分组
- spring - 有交叉路径时如何处理 Spring HttpSecurity 授权请求?
- javascript - 如何在 Python 中将浮点数转换为 base36?
- java - 在其 ViewPager 中使用带有 ScrollView 的片段隐藏选项卡式活动中的工具栏
- algorithm - SOLR中基于直方图的搜索(多值字段中的位置相关性)
- php - 自定义 WooCommerce 产品字段未保存在数据库中
- html - 当我在手机上查看我的网站时,媒体查询无法正常工作