Python PyQt:在窗口之间传递信息

Python PyQt:在窗口之间传递信息,python,pyqt,qgis,Python,Pyqt,Qgis,以前有人问过这个问题,我想提出我的解决方案,想知道这是一种可以接受的模式,还是有更好的替代方案 使用QGIS时,我开始使用PyQt作为GUI(以前主要是tkinter),我在画布上进行选择,然后打开另一个窗口提供有关功能的信息。在画布上,我想标记所选的特征,因此需要从另一个窗口获取信息 我在下面的PyQt中做了一个最小的工作示例(需要使用Python 3.8导入PyQt5),其中我有两个窗口,一个叫做按钮,另一个叫做显示,其中显示显示按钮被按下的次数 为了进行通信,我在显示窗口中定义了一个QTi

以前有人问过这个问题,我想提出我的解决方案,想知道这是一种可以接受的模式,还是有更好的替代方案

使用QGIS时,我开始使用PyQt作为GUI(以前主要是tkinter),我在画布上进行选择,然后打开另一个窗口提供有关功能的信息。在画布上,我想标记所选的特征,因此需要从另一个窗口获取信息

我在下面的PyQt中做了一个最小的工作示例(需要使用Python 3.8导入PyQt5),其中我有两个窗口,一个叫做
按钮
,另一个叫做
显示
,其中
显示
显示按钮被按下的次数

为了进行通信,我在
显示
窗口中定义了一个
QTimer
,它轮询
按钮
窗口(在这种情况下,每250毫秒一次),以获取所需信息。问题是在PyQt中有更好的方法来实现这一点吗

import sys
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QLabel, QApplication, QPushButton
from PyQt5.QtCore import QTimer

POLL_INTERVAL = 250  # in ms
WINSIZE = (200, 50)  # w, h
BUTTON_WIN_POS = (200, 200)  # w, h
DISPLAY_WIN_POS = (450, 200)  # w, h

class ButtonWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.button_pressed_counter = 0
        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()
        button = QPushButton('Press me')
        button.clicked.connect(self.press_button)
        vbox.addWidget(button)

        self.setLayout(vbox)
        self.move(*BUTTON_WIN_POS)
        self.setWindowTitle('Button ... ')
        self.resize(*WINSIZE)
        self.show()

    def press_button(self):
        self.button_pressed_counter += 1

    @property
    def button_count(self):
        return self.button_pressed_counter

class DisplayWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.button_window = ButtonWindow()

        self.button_count = 0
        self.button_counter = QTimer()
        self.button_counter.timeout.connect(self.get_button_count)

        self.initUI()

    def initUI(self):
        vbox = QVBoxLayout()
        self.text_lbl = QLabel()
        vbox.addWidget(self.text_lbl)
        self.text_lbl.setText(f'button count: {self.button_count}')

        self.setLayout(vbox)
        self.move(*DISPLAY_WIN_POS)
        self.setWindowTitle('Display ... ')
        self.resize(*WINSIZE)
        self.show()

        self.button_counter.start(POLL_INTERVAL)

    def get_button_count(self):
        new_button_count = self.button_window.button_count
        if self.button_count == new_button_count:
            pass

        else:
            self.button_count = new_button_count
            self.text_lbl.setText(f'button count: {self.button_count}')


def main():
    app = QApplication([])
    _ = DisplayWindow()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

不,至少在这种情况下,这不是一个好的解决方案。此外,在处理交互元素时,依靠计时器“轮询”很少是一个好的解决方案:它不可靠,不允许在单击的按钮和结果之间立即响应,并且使代码变得不必要的复杂

信号和插槽的存在正是为了这个目的:一个公共接口,允许对象之间的通信;因此,在“source”类中实现一个自定义信号,并将其连接到“target”中

显然,必须删除与QTimer相关的所有内容


请注意,如果你使用另一个窗口来获得“特征”,它应该改变主界面的行为,你应该考虑使用Q对话框,并最终决定是否使用它作为模式(通常是通过<代码> Excel())/>代码>,这阻止了与其他窗口的交互,直到对话框关闭,并且(可能)返回所需的值。

不,至少在这种情况下,这不是一个好的解决方案。此外,在处理交互元素时,依靠计时器“轮询”很少是一个好的解决方案:它不可靠,不允许在单击的按钮和结果之间立即响应,并且使代码变得不必要的复杂

信号和插槽的存在正是为了这个目的:一个公共接口,允许对象之间的通信;因此,在“source”类中实现一个自定义信号,并将其连接到“target”中

显然,必须删除与QTimer相关的所有内容


请注意,如果你使用另一个窗口来获得“特征”,它应该改变主界面的行为,你应该考虑使用Q对话框,并最终决定是否使用它作为模式(通常是通过<代码> Excel())/>代码>,这阻止了与其他窗口的交互,直到对话框关闭,并且(可能)返回所需的值。

Great answet,直截了当,介绍了正确的概念,并提供了一个简单的示例:)非常好,非常感谢。我觉得会有更好的解决方案。伟大的answet,直截了当地介绍了正确的概念,还有一个简单的例子:)非常好,非常感谢。我觉得会有更好的解决办法。
class ButtonWindow(QWidget):
    pressCountChanged = pyqtSignal(int)
    # ...

    def press_button(self):
        self.button_pressed_counter += 1
        self.pressCountChanged.emit(self.button_pressed_counter)


class DisplayWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.button_window = ButtonWindow()
        self.button_window.pressCountChanged.connect(self.get_button_count)

        self.button_count = 0

        self.initUI()