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

什么是多窗口交互?

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

代码示范

窗口2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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)




主窗口

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
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_())


总结

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