【写在前面】
自学python,不同于工作上的代码编程,主要是为了好玩或者满足自己的需求。因此,我一直想自己做些APP,未来可以给小朋友做做练习,比如让她学习算术、学习成语接龙之类的。总不能让她看这样恐怖的界面吧?
因此,就自学GUI,可以制作些可视化界面工具。
另外,我在制作GUI时,发现多窗口之间的信号传递和处理特别麻烦,网上有很多C或者JAVA的帖子,或者只有 介绍如何显示多窗口,但是就是没有详细的Python介绍如何实现信号传递。因此也希望这篇文章有点用吧!
【示例代码】
示例代码一共有2份,一份是主窗口的代码 ,一份是子窗口的代码。
MainWindow.py
# coding=utf-8
# @Auther : "鹏哥贼优秀"
# @Date : 2019/8/16
# @Software : PyCharm
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
from ChildWindow import *
class Ui_MainWindow(QtWidgets.QMainWindow):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(534, 386)
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(360, 140, 101, 51))
self.pushButton.setStyleSheet("background-color: rgb(0, 255, 127);\n"
"font: 12pt \"黑体\";")
self.pushButton.setObjectName("pushButton")
self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog)
self.plainTextEdit.setGeometry(QtCore.QRect(50, 120, 271, 161))
self.plainTextEdit.setStyleSheet("font: 11pt \"宋体\";")
self.plainTextEdit.setObjectName("plainTextEdit")
self.label = QtWidgets.QLabel(Dialog)
self.label.setGeometry(QtCore.QRect(60, 85, 131, 21))
self.label.setStyleSheet("font: 12pt \"黑体\";\n"
"color: rgb(255, 0, 0);")
self.label.setObjectName("label")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "弹出子窗口"))
self.label.setText(_translate("Dialog", "显示子窗口内容"))
self.pushButton.clicked.connect(self.btn)
# 在主窗口点击按钮后,显示子窗口
def btn(self):
self.child = QtWidgets.QDialog()
self.childwindow = Ui_ChildWindow()
self.childwindow.setupUi(self.child)
# 与子窗口的信号连接
self.childwindow.my_signal.connect(self.child_click)
self.child.show()
# 定义子窗口的按钮作用
def child_click(self):
value = self.childwindow.plainTextEdit.toPlainText()
print(value)
self.childwindow.plainTextEdit.setPlainText("子窗口输入成功!")
self.plainTextEdit.setPlainText(value)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
main = QtWidgets.QMainWindow()
mainwindow = Ui_MainWindow()
mainwindow.setupUi(main)
main.show()
sys.exit(app.exec())
ChildWindow.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_ChildWindow(QtWidgets.QDialog):
# 声明信号
my_signal = QtCore.pyqtSignal(str)
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(565, 413)
self.pushButton = QtWidgets.QPushButton(Dialog)
self.pushButton.setGeometry(QtCore.QRect(400, 120, 75, 51))
self.pushButton.setStyleSheet("font: 12pt \"黑体\";\n"
"background-color: rgb(0, 255, 127);")
self.pushButton.setObjectName("pushButton")
self.plainTextEdit = QtWidgets.QPlainTextEdit(Dialog)
self.plainTextEdit.setGeometry(QtCore.QRect(90, 110, 261, 111))
self.plainTextEdit.setStyleSheet("font: 12pt \"宋体\";")
self.plainTextEdit.setObjectName("plainTextEdit")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.pushButton.setText(_translate("Dialog", "输入"))
self.pushButton.clicked.connect(self.click)
# 信号传递回主窗口并结束
def click(self):
self.my_signal.emit("1")
【效果】
【知识点】
1、多窗口实现流程:
(1)用QT Designer直接先设计好主、子窗口的界面布局及按钮制作(如何使用Qt Designer,这块知识网上 有很多,暂不介绍了)
(2)在子窗口中,定义窗口的信号,及定义好信号发送后的退出方式。
关键就是以下几句代码:
因为我定义了my_signal信号,并且要求发送str作为信号的结束。因此在click方法中,定义成了my_signal.emit("1")。表示这个信号发送了“1”给主窗口,并结束。但其实,这个地方“1”并没有什么意义,因为我只是需要多窗口之间的信号连接,不关心最后子窗口给我返回的是什么。
(3)主窗口这边就有2个功能要实现了。
一方面除了显示主窗口界面外,还要在点击按钮后显示子窗口界面,如下图:
这 段代码还 是好理解的,在点击主窗口按钮后,调用窗口显示流程代码 + 一句与子窗口信号连接的代码 。但其实这段 代码就是多窗口实现的核心代码。刚开始学习的时候,就是这段流程不 熟悉,所以一直碰壁。
说明:
其实子窗口与主窗口显示的代码流程是一样的,只是子窗口属于QDialog类,主窗口属于QMainWindow类布局。
因为信号连接的代码是表示子窗口点击了按钮后,程序应当进入child_click方法。
下面就是子窗口按钮响应的实现了。
具体功能就是根据各自需求实现了。
2、别以为 上面这样就可以了,但是 有个坑 :
如果是通过Qt Designer实现代码转换的话,类定义一般是:
class Ui_MainWindow(object):
发现没,一般是不会声明具体继承什么类,导致主、子窗口的类继承冲突(这里我对类继承也不太熟悉,不知道要怎么解释)。查过网上的一些资料,说主、子窗口的类型不能一样,即不能都为QDialog,所以要把各个类声明好,具体是继承什么类的。即如下:
class Ui_MainWindow(QtWidgets.QMainWindow):
3、聊聊多窗口数据传递的方法。
我当前想到有3个办法 可以实现多窗口信号传递。
(1)子窗口将要传递的信号,写到一个临时文件中,然后主窗口读取临时文件。这个就是文件读写的操作了,但是比较土。
(2)在主窗口中,获取到子窗口内的信号。本文采用的就是这种方法。
(3)在子窗口中,直接把主 窗口的内容进行修改。理论上应该只要继承父类就可以了 ,如下
import MainWindow class Ui_ChildWindow(MainWindow.Ui_MainWindow):
但是可能是 我使用方式有问题,无法访问父类的对象,即无法获取 到父类的Pushbutton按钮。等我本事再提高些,再回来解决这个问题。
【写在最后】
如果觉得不错,关注我公众号“鹏哥贼优秀”呀!