在PyQt5中如何实现多窗口交互, 以及一些注意事项.

什么是多窗口交互?

就是多个窗口进行 数据交互. 有两种方法,一种是强耦合的直接两个窗口一起使用, 不通过信号与槽. 另一种就是通过 信号与槽进行数据交互, 这里仅介绍第二种.

代码示范

窗口2

from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

class NewDateDialog(QDialog):
    # 自定义一个信号
    Signal_OneParameter = pyqtSignal(str)
    def __init__(self,parent=None):
        # super().__init__()
        # 因为QT5 和 python 3的兼容问题, 如果不这样使用,PyQT5 里拿不到父类,导致窗口就会闪现
        super(NewDateDialog, self).__init__(parent)
        self.setWindowTitle("子窗口用来发射信号")
        self.resize(600, 600)
        #  要使用self, 不然在会显示不了日历挂件
        layout = QVBoxLayout(self)
        self.label = QLabel()
        self.label.setText("前者发送内置信号\n后者发送自定义信号")
        # QDateTimeEdit 可编辑时间框
        self.datetime_inner = QDateTimeEdit()
        # 显示日历挂件
        self.datetime_inner.setCalendarPopup(True)
        self.datetime_inner.setDateTime(QDateTime.currentDateTime())

        self.datetime_emit_by_you = QDateTimeEdit()
        self.datetime_emit_by_you.setCalendarPopup(True)
        self.datetime_emit_by_you.setDateTime(QDateTime.currentDateTime())

        layout.addWidget(self.label)
        layout.addWidget(self.datetime_inner)
        layout.addWidget(self.datetime_emit_by_you)

        buttons = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel, Qt.Horizontal, self)
        buttons.accepted.connect(self.accept)
        buttons.rejected.connect(self.reject)

        layout.addWidget(buttons)
        # 绑定了信号的触发
        self.datetime_emit_by_you.dateTimeChanged.connect(self.emit_signal)

    # 触发自定义的信号
    def emit_signal(self):
        date_str = self.datetime_emit_by_you.dateTime().toString()
        self.Signal_OneParameter.emit(date_str)




主窗口

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

from NewDateDiaolog import NewDateDialog

class MoreWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(500 , 500)
        self.setWindowTitle("多窗口交互2,使用信号与槽")

        self.open_btn = QPushButton("获取时间")
        self.lineEdit_inner = QLineEdit(self)
        self.lineEdit_emit = QLineEdit(self)
        self.open_btn.clicked.connect(self.openDialog)

        self.lineEdit_inner.setText("接收子窗口内置信号的时间")
        self.lineEdit_emit.setText('接收子窗口自定义信号的时间')

        grid_layout = QGridLayout()
        grid_layout.addWidget(self.lineEdit_inner)
        grid_layout.addWidget(self.lineEdit_emit)
        grid_layout.addWidget(self.open_btn)
        self.setLayout(grid_layout)

    def openDialog(self):
        # 没有这个self ,就会窗口闪现就没了
        dialog = NewDateDialog(self)
        # 连接子窗口的内置信号与主窗口的槽函数
        dialog.datetime_inner.dateTimeChanged.connect(self.deal_inner_slot)
        #  连接子窗口的自定义信号与主窗口的槽函数
        dialog.Signal_OneParameter.connect(self.deal_emit_slot)
        dialog.show()

    def deal_inner_slot(self, date):
        # print("卡卡")
        # print(date)
        self.lineEdit_inner.setText(date.toString())

    def deal_emit_slot(self, dateStr):
        # print("嬉戏")
        # print(dateStr)
        self.lineEdit_emit.setText(dateStr)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    form = MoreWindow()
    form.show()
    sys.exit(app.exec_())

总结

这个案例, 让我发现一个问题, 就是 PyQt5 里面不少类, 估计对于python3.0 的继承新语法, super().init() 会导致窗口二出现一下子就消失了.

因此, 在 PyQT5项目中, 最好还是使用旧的 资源叠加写法

案例二

今天, 发现还有一个注意细节, 补充一下

代码 示范

窗口1

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys


class WindowOne(QDialog):
    signal_time = pyqtSignal(str)
    def __init__(self, parent):
        super(WindowOne, self).__init__(parent)
        self.setWindowTitle("窗口1")
        self.resize(500, 500)
        layout = QVBoxLayout(self)
        btn = QPushButton("按下就有今天的时间")
        layout.addWidget(btn)
        btn.clicked.connect(self.getTime)
        self.setLayout(layout)

    def getTime(self):
        date_time = QDateTime.currentDateTime()
        # 触发信号
        self.signal_time.emit(date_time.toString())
        print(date_time)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WindowOne(None)
    win.show()
    sys.exit(app.exec_())

窗口2

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from windowone import WindowOne
import sys

class WindowTwo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("主窗口")
        layout = QHBoxLayout(self)
        self.lineEdit = QLineEdit()
        self.button = QPushButton("打开新窗口")
        self.button.clicked.connect(self.openNewWindow)
        layout.addWidget(self.lineEdit)
        layout.addWidget(self.button)

        self.setLayout(layout)

    def openNewWindow(self):
        newWindow = WindowOne(self)

        newWindow.signal_time.connect(self.setLineEdit)
        # newWindow.show()
        #  show 也行, exec_() 也行, 但是一定要将信号绑定再运行窗口,不然拿不到信号返回值
        newWindow.exec_()
    def setLineEdit(self, data_str):
        print("执行了没有")
        self.lineEdit.setText(data_str)



if __name__ == '__main__':
    app = QApplication(sys.argv)
    win = WindowTwo()
    win.show()
    sys.exit(app.exec_())


总结

在打开新窗口的时候, 要在新窗口出现之前, 给信号绑定槽, 如果顺序弄反了, 就绑定失败了.