GUI程序中的控件间的关系及控件间信息传递是整个程序中至关重要的模块,今天简要总结QTdesigner中的伙伴关系、Tab顺序、信号和槽的基本内容。
1.伙伴关系
首先,我们对相关概念给出如下定义:
伙伴关系:即是控件之间的相互关联,使得可以通过一个控件控制另一个控件。
快捷键:在全局可以直接使用的键及组合,例如:选中控件使用ctrl + 1即可完成水平布局,其为快捷键。
热键:相对于快捷键有所区别。热键是只有在打开了某个窗口时,出现了下拉菜单,只有在这个菜单展开的时候才可使用“快捷键”调用相应功能。
设置控件间的伙伴关系:
tips:
1.伙伴设置是单方向的,即设置后只是单方向的控制。
2.伙伴关系一般包含两个控件,暂且称为控制控件A和被控制控件B,即可以由控件A来控制控件B,一般情况下(其他的我还没见过)控件A(即控制控件)只能是Label控件。其他的不能设置伙伴关系。控件B(即被控制控件)没有要求。
3.由于伙伴关系中的控制控件只能是Label控件,而Label控件在程序中无法选中或单击,故而通常给Label设置热键。
设置伙伴关系在加入了控件后---点击菜单栏上的快捷按钮---即可进入编辑界面。(或者:Edit -> 编辑伙伴 也可进入界面。)
在进入编辑界面后,鼠标悬停Label标签会变红,左键选中不放将其箭头拖至想控制的另一个控件,松手再单击左键以确定,即可完成伙伴编辑。
删除伙伴关系:单击连接线即可选中此伙伴关系,右键即可删除伙伴关系。
Label控件的热键设置:只须在Label的内容后面用半角括号将设置热键括起来即可。
此处的&B是指:alt + B。(注意:不能和已有的快捷重合)
如此,在伙伴关系和热键设置结束后,即可使用alt+B直接控制右侧的Line Edit控件。其原理是热键alt+B控制了Label控件,Label控件又通过伙伴关系控制了Line Edit。
2.Tab顺序
一个程序中,在一个控件上使用Tab键会跳到另一个控件上,其跳转的规则或顺序即为Tab顺序。
Tab顺序理解比较简单,设置亦是如此。点击菜单栏的快捷键即可进入编辑。
每个控件上的数字即代表Tab顺序。
更改主要有以下方法:
1.点击数字即可更改,每点一次就会改变。
2.右键->制表符顺序列表,可直接调节。
3.初识信号与槽
来了来了,它终于来了。信号与槽是GUI程序开发的重点及难点,是GUI程序开发的灵魂,同时也是PyQt的核心机制,其重要程度可见一斑。要想把它搞清楚搞明白还需很多很多时日,今天主要对其进行入门理解和学习,并做一个简单应用。
信号(signal): 是由控件或对象发射出去的信息。
槽(slot):很多时候又称槽函数,是对发送出去的信号的响应或反馈。槽本质上是一个函数或者方法。
举个例子:按钮控件(PushButton)可以进行单击,在用户单击了这个按钮之后,实质上就是发出了一个信号(即‘按钮被单击了’这个信号),从这个角度来讲,可以将信号理解为一种指令。好,发出了指令然后呢?程序内部接受了这个指令,需要做出对应的反馈及响应以接受这个指令,这个响应和反馈即是槽。即按钮单击事件,实际上是执行了槽对应的函数或方法。
信号可以理解为事件,槽可以理解为事件函数。信号的种类很多:如按钮有单击、双击、长按等事件,选择类控件有选中、不选中等事件。
一个信号可以与多个槽绑定,一个槽也可以拦截多个信号。
在QTdesigner中设置信号与槽的几个示例:
示例1:要求设置一个按钮,单击可以关闭窗口。
关闭窗口有内部函数,需勾选:显示从Qwidget继承的信号和槽。
左边选中信号:clicked() 右边选择槽函数:close() 即可完成。
示例2:用一个Radio Button和check box的选中与不选中来控制编辑栏的可编辑与不可编辑。
设置如下:
信号选择:toggled(bool)(toggle:切换) 槽函数选择:setVisible(bool)
效果:
学到现在基本对GUI的基本运作方式等等都有了基础的认识,我们现在来用代码和QTdesigner做一个简单的GUI程序。
上才艺,哦不,上实例。
要求:总共四个页面,一个主界面,三个功能页面,主界面可实现向三个页面任意一个页面转换,通过单击按钮完成,每个功能页面都可以通过返回主界面按钮返回主界面,也有关闭按钮关闭页面。
程序主要参考博客:
https://blog.csdn.net/weixin_43734095/article/details/106783108
前期准备:利用QTdesigner先设计四个页面窗口。并将其转换为py程序。
编写主程序:first.py如下
import sys
from PyQt5 import QtCore, QtWidgets
from main_ui import Ui_MainWindow as main_UI
from ui_1 import Ui_Form as UI1
from ui_2 import Ui_Form as UI2
from ui_3 import Ui_Form as UI3
# 主窗口类
class mainui(QtWidgets.QMainWindow, main_UI):
# 定义三个跳转信号
switch_window1 = QtCore.pyqtSignal() # 跳转信号
switch_window2 = QtCore.pyqtSignal() # 跳转信号
switch_window3 = QtCore.pyqtSignal() # 跳转信号
# 定义槽函数。其意义是:当按钮1被单击时,发出self.switch_window1这个信号。
def go_ui_1(self):
self.switch_window1.emit() # 发出信号
def go_ui_2(self):
self.switch_window2.emit()
def go_ui_3(self):
self.switch_window3.emit()
def __init__(self):
# super是指继承父类(此处主要是类main_UI)中的构造函数,即__init__方法
super(mainui, self).__init__()
self.setupUi(self) # 初始化窗口
# 注意:self.go_ui_1 是一个函数是一个方法,而self.go_ui_1()是函数的返回值
# 信号与槽对应,是与一种方法(函数)对应,所以不能对加括号实例化,应该使用self.go_ui_1
self.pushButton.clicked.connect(self.go_ui_1)
# 意思是指:main_UI里的pushButton单击(clicked)这个事件是与self.go_ui_1这个方法相绑定连接(connect)
self.pushButton_2.clicked.connect(self.go_ui_2)
self.pushButton_3.clicked.connect(self.go_ui_3)
# ui_1类
class UI_1(QtWidgets.QMainWindow, UI1):
switch_window = QtCore.pyqtSignal()
def __init__(self):
super(UI_1, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.go_main)
def go_main(self):
self.switch_window.emit()
# ui_2
class UI_2(QtWidgets.QMainWindow, UI2):
switch_window = QtCore.pyqtSignal()
def __init__(self):
super(UI_2, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.go_main)
def go_main(self):
self.switch_window.emit()
# ui_3
class UI_3(QtWidgets.QMainWindow, UI3):
switch_window = QtCore.pyqtSignal()
def __init__(self):
super(UI_3, self).__init__()
self.setupUi(self)
self.pushButton.clicked.connect(self.go_main)
def go_main(self):
self.switch_window.emit()
# 利用一个控制器来控制页面的跳转
class Controller:
def __init__(self):
pass
# 跳转到主窗口
def show_MianW(self):
# 加入应该异常捕捉,将切换了主界面后的界面关闭
try:
self.ui1.close() # 界面关闭
self.ui2.close()
self.ui3.close()
except:
pass
self.MianW = mainui() # 实例化
# 定义主窗口类:class mainui(QtWidgets.QMainWindow, main_UI)中各信号的槽
self.MianW.switch_window1.connect(self.show_ui_1)
self.MianW.switch_window2.connect(self.show_ui_2)
self.MianW.switch_window3.connect(self.show_ui_3)
self.MianW.show() # 显示窗口
# 跳转到ui_1窗口, 注意关闭原页面
def show_ui_1(self):
self.ui1 = UI_1()
self.MianW.close()
self.ui1.switch_window.connect(self.show_MianW)
self.ui1.show()
# 跳转到ui_2窗口, 注意关闭原页面
def show_ui_2(self):
self.ui2 = UI_2()
self.MianW.close()
self.ui2.switch_window.connect(self.show_MianW)
self.ui2.show()
# 跳转到ui_3窗口, 注意关闭原页面
def show_ui_3(self):
self.ui3 = UI_3()
self.MianW.close()
self.ui3.switch_window.connect(self.show_MianW)
self.ui3.show()
def main():
app = QtWidgets.QApplication(sys.argv)
controller = Controller() # 控制器实例化
controller.show_MianW() # 默认展示的是主页面
sys.exit(app.exec_())
if __name__ == '__main__':
main()
即可完成。
学习路漫漫,共勉!
附4个页面生成代码
main_ui.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'main_ui.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(310, 230, 112, 34))
self.pushButton.setObjectName("pushButton")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(320, 140, 91, 18))
self.label.setObjectName("label")
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(310, 300, 112, 34))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_3.setGeometry(QtCore.QRect(310, 370, 112, 34))
self.pushButton_3.setObjectName("pushButton_3")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "跳转到界面1"))
self.label.setText(_translate("MainWindow", "这是主窗口"))
self.pushButton_2.setText(_translate("MainWindow", "跳转到界面2"))
self.pushButton_3.setText(_translate("MainWindow", "跳转到界面3"))
ui_1.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_1.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(744, 411)
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(290, 100, 81, 18))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(140, 280, 112, 34))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setGeometry(QtCore.QRect(410, 280, 112, 34))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(Form)
self.pushButton_3.setGeometry(QtCore.QRect(120, 160, 112, 34))
self.pushButton_3.setObjectName("pushButton_3")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(300, 160, 221, 41))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Form)
self.pushButton_2.clicked.connect(Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "这是界面1"))
self.pushButton.setText(_translate("Form", "返回主界面"))
self.pushButton_2.setText(_translate("Form", "退出"))
self.pushButton_3.setText(_translate("Form", "function"))
ui_2.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_2.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(744, 411)
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(290, 100, 81, 18))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(140, 280, 112, 34))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setGeometry(QtCore.QRect(430, 280, 112, 34))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(Form)
self.pushButton_3.setGeometry(QtCore.QRect(120, 160, 112, 34))
self.pushButton_3.setObjectName("pushButton_3")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(300, 160, 221, 41))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Form)
self.pushButton_2.clicked.connect(Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "这是界面2"))
self.pushButton.setText(_translate("Form", "返回主界面"))
self.pushButton_2.setText(_translate("Form", "退出"))
self.pushButton_3.setText(_translate("Form", "function"))
ui_3.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_3.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(744, 411)
self.label = QtWidgets.QLabel(Form)
self.label.setGeometry(QtCore.QRect(290, 100, 81, 18))
self.label.setObjectName("label")
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(140, 280, 112, 34))
self.pushButton.setObjectName("pushButton")
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setGeometry(QtCore.QRect(430, 280, 112, 34))
self.pushButton_2.setObjectName("pushButton_2")
self.pushButton_3 = QtWidgets.QPushButton(Form)
self.pushButton_3.setGeometry(QtCore.QRect(120, 160, 112, 34))
self.pushButton_3.setObjectName("pushButton_3")
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(300, 160, 221, 41))
self.lineEdit.setObjectName("lineEdit")
self.retranslateUi(Form)
self.pushButton_2.clicked.connect(Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "这是界面3"))
self.pushButton.setText(_translate("Form", "返回主界面"))
self.pushButton_2.setText(_translate("Form", "退出"))
self.pushButton_3.setText(_translate("Form", "function"))