python - 在 Pyside2 for Python 上显示应用程序后如何刷新事件?

标签 python python-3.x pyside2

我想用 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>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Entrez ici le dossier où ce trouve le fichier .xml à utiliser&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</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_()

ma​​in.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)

ma​​in.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/

相关文章:

python - 如何在Python中处理这个JSON文件?

python - Pandas 组合两列

python - 在 PyQt5 和 PySide2 中重写 PaintEvent

python - 将选项卡扩展到整个窗口大小?

python - Django 和 threading.local() 怪癖?

python - 无法通过 Gino (异步 sqlalchemy 包装器)连接到 SQLite 数据库

python - 当我使用 json.loads 时,你是什么?

python - 将两个数字编码为 4 位二进制字符串

python - 如何在 moviepy 中创建包含多个文本的 textClip?

python - PySide2 QOpenGLWidget按键事件不起作用