我想用 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_()
main.py
# ...
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)
main.py
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)
关于python - 在 Pyside2 for Python 上显示应用程序后如何刷新事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56856601/