UI ui_untitled.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(475, 331)
MainWindow.setProperty("menu", "")
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setObjectName("pushButton")
self.horizontalLayout.addWidget(self.pushButton)
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setObjectName("pushButton_2")
self.horizontalLayout_2.addWidget(self.pushButton_2)
self.retranslateUi(MainWindow)
#实现装饰器信号与槽,self.pushButton.setObjectName("pushButton")和下面是必须得
QtCore.QMetaObject.connectSlotsByName(MainWindow)
逻辑代码页
# ui下的ui_untitled.py....类 Ui_MainWindow
from ui.ui_untitled import *
class winForm(Ui_MainWindow, QMainWindow):
def __init__(self):
super(winForm, self).__init__() # 运行父类的构造方法
self.setupUi(self) # 传递自己
@QtCore.pyqtSlot()
def on_pushButton_clicked(self):
QMessageBox.information(self, "提示", "btn1信息对话框", QMessageBox.Ok | QMessageBox.Cancel)
@QtCore.pyqtSlot()
def on_pushButton_2_clicked(self):
"""
:param self:
"""
QMessageBox.information(self, "提示", "btn2信息对话框", QMessageBox.Ok | QMessageBox.Cancel)
if __name__ == '__main__':
app = QApplication(sys.argv)
ui = winForm() # 创建PyQt设计的窗体对象
ui.show() # 显示窗体
sys.exit(app.exec_())
目录
一、PyCharm+PyQt5的环境配置
二、使用Qt Designer将界面显示与业务逻辑分离
三、PyQt5工程中的多文件开发
转自原文链接
作为一个使用C++开发QT五年的“老”程序猿,总觉得使用C++开发GUI,是一个很费时费力或者说没有“钱”途的事情,因为现在有大量的轻量化的编程语言可以做很绚丽的交互界面,所以笔者现在逐渐向Python转移,逐渐使用PyQt5开发Qt项目,作为一个python新手,请大家多多指教。
具体配置可以在网上搜其它帖子,在这里不作过多论述。
个人在使用过程中,有个习惯,当我们新建了xxx.ui文件,然后使用pyuic5生成xxx.py文件的时候,为了更清楚的看出来这个py文件是由ui文件生成的,也为了防止我们修改这个文件,可以在setting中将pyuic5的Arguments配置中改为“$FileName$ -o ui_$FileNameWithoutExtension$.py”,这样生成的py文件都是加了“ui_”前缀的。
大部分的教程都是将使用Qt Designer进行界面布局和Qt中控件的使用分开来讲,讲Qt Designer的时候直接在.ui文件生成的.py文件里面进行修改,这样虽然可以理解界面和代码之间是如何互联共通的,但是不方便.ui文件的修改。在讲Qt的各种控件的使用的时候,又几乎全部用代码在布局界面,这对于初识Qt的新手来说倒还可以,但对于像笔者这种只换语言不换框架的工程师来讲,未免有点太拖沓,所以我们直接讲将界面显示与业务逻辑分离的方式开发。
1、例如我新建一个mainpage.ui文件,里面放几个控件。
2、将mainpage.ui文件转换成ui_mainpage.py文件
当然,也可以直接使用命令生成,不过需要配置环境变量,需要大家自己去配置,“pyuic5 -o ui_mainpage.py mainpage.ui”
生成的mainpage.py文件,其完整代码如下:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'mainpage.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainPage(object):
def setupUi(self, MainPage):
MainPage.setObjectName("MainPage")
MainPage.resize(739, 449)
self.layoutWidget = QtWidgets.QWidget(MainPage)
self.layoutWidget.setGeometry(QtCore.QRect(90, 80, 521, 271))
self.layoutWidget.setObjectName("layoutWidget")
self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget)
self.gridLayout.setContentsMargins(8, 8, 8, 8)
self.gridLayout.setObjectName("gridLayout")
self.driveButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(14)
self.driveButton.setFont(font)
self.driveButton.setObjectName("driveButton")
self.gridLayout.addWidget(self.driveButton, 2, 0, 1, 1)
self.rangingButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(14)
self.rangingButton.setFont(font)
self.rangingButton.setObjectName("rangingButton")
self.gridLayout.addWidget(self.rangingButton, 1, 0, 1, 1)
self.cameraButton = QtWidgets.QPushButton(self.layoutWidget)
font = QtGui.QFont()
font.setPointSize(14)
self.cameraButton.setFont(font)
self.cameraButton.setObjectName("cameraButton")
self.gridLayout.addWidget(self.cameraButton, 0, 0, 1, 1)
self.retranslateUi(MainPage)
QtCore.QMetaObject.connectSlotsByName(MainPage)
def retranslateUi(self, MainPage):
_translate = QtCore.QCoreApplication.translate
MainPage.setWindowTitle(_translate("MainPage", "小车控制器"))
self.driveButton.setText(_translate("MainPage", "打开电机驱动控制界面"))
self.rangingButton.setText(_translate("MainPage", "打开超声波测距控制界面"))
self.cameraButton.setText(_translate("MainPage", "打开摄像头控制界面"))
3、新建一个业务逻辑文件,我们可以起名叫“call_mainpage.py”,我们可以在这个文件中新建一个MainPageWindow类,让它继承由ui文件生成的py文件中的Ui_MainPage类,这样我们所有的业务逻辑处理,都可以在“call_mainpage.py”文件中进行,这样就不管UI文件什么事情了,当修改ui文件后,只影响生成的py文件,逻辑处理文件不受影响。
编写的call_mainpage.py文件,其代码如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from HomePages.ui_mainpage import Ui_MainPage
from PyQt5.QtCore import pyqtSignal,Qt
class MainPageWindow(QWidget,Ui_MainPage):
#定义点击信号
chooseSignal = pyqtSignal(str)
def __init__(self,parent=None):
super(MainPageWindow, self).__init__(parent)
self.setupUi(self)
self.initUI()
def initUI(self):
self.setLayout(self.gridLayout)
self.cameraButton.clicked.connect(self.showDialog)
self.rangingButton.clicked.connect(self.showDialog)
self.driveButton.clicked.connect(self.showDialog)
def showDialog(self):
sender = self.sender()
if sender == self.cameraButton:
#发射点击信号
self.chooseSignal.emit('camera')
elif sender == self.rangingButton:
self.chooseSignal.emit('ranging')
elif sender == self.driveButton:
self.chooseSignal.emit('drive')
4、在MainPageWindow类中,我定义一个chooseSignal信号,用于向外界发送按钮点击信号。
这样大家可以直接在call_mainpage.py文件中添加程序main入口运行了:
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainPageWindow()
mainWindow.show()
sys.exit(app.exec_())
不过我暂时没有在这个文件中添加main入口,因为我要在其它文件中创建main入口,进行多文件调用。
习惯使用C++开发Qt工程,都是习惯多文件分离开发,每个界面一个ui文件,转换后加一个py文件,再加负责一个业务逻辑的py文件,一共三个文件。例如写一个四个界面的工程,步骤如下:
1、使用Qt Designer新建四个不同的ui文件,分别为camerapage.ui、drivepage.ui、mainpage.ui、rangingpage.ui
2、使用pyuic5将四个ui文件转换成对应的py文件,分别为ui_camerapage.py、ui_drivepage.py、ui_mainpage.py、ui_rangingpage.py
可以将和UI文件相关的文件放在一个目录中,方便管理,笔者把它们都放在了HomePages目录中。
3、创建四个“ui_”文件对应的业务逻辑文件,分别为call_camerapage.py、call_drivepage.py、call_mainpage.py、call_rangingpage.py
call_camerapage.py文件内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal,Qt
from HomePages.ui_camerapage import Ui_CameraPage
class CameraPageWindow(QWidget,Ui_CameraPage):
#声明信号
returnSignal = pyqtSignal()
def __init__(self,parent=None):
super(CameraPageWindow, self).__init__(parent)
self.setupUi(self)
self.initUI()
def initUI(self):
self.setLayout(self.gridLayout)
self.returnButton.clicked.connect(self.returnSignal)
call_drivepage.py文件内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal,Qt
from HomePages.ui_drivepage import Ui_DrivePage
class DrivePageWindow(QWidget,Ui_DrivePage):
# 声明信号
returnSignal = pyqtSignal()
def __init__(self, parent=None):
super(DrivePageWindow, self).__init__(parent)
self.setupUi(self)
self.initUI()
def initUI(self):
self.setLayout(self.gridLayout)
self.returnButton.clicked.connect(self.returnSignal)
call_rangingpage.py文件内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtCore import pyqtSignal,Qt
from HomePages.ui_rangingpage import Ui_RangingPage
class RangingPageWindow(QWidget,Ui_RangingPage):
# 声明信号
returnSignal = pyqtSignal()
def __init__(self, parent=None):
super(RangingPageWindow, self).__init__(parent)
self.setupUi(self)
self.initUI()
def initUI(self):
self.setLayout(self.gridLayout)
self.returnButton.clicked.connect(self.returnSignal)
call_mainpage.py在前面讲过了,就不重复了,其实每个call_文件的框架都一样,分别声明了CameraPageWindow、DrivePageWindow、RangingPageWindow、MainPageWindow四个类,每个类分别继承自己对应的UI类。
4、这时候需要一个总界面,用来整合所有子页面,并负责界面之间的切换等功能,新建一个mainwindow.py文件,内容如下:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
from call_mainpage import MainPageWindow
from call_camerapage import CameraPageWindow
from call_drivepage import DrivePageWindow
from call_rangingpage import RangingPageWindow
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
self.resize(480,320)
self.layout = QGridLayout()
self.setLayout(self.layout)
self.Stack = QStackedWidget()
self.layout.addWidget(self.Stack)
self.mainPageUi = MainPageWindow()
self.cameraPageUi = CameraPageWindow()
self.drivePageUi = DrivePageWindow()
self.rangingPageUi = RangingPageWindow()
self.Stack.addWidget(self.mainPageUi)
self.Stack.addWidget(self.cameraPageUi)
self.Stack.addWidget(self.drivePageUi)
self.Stack.addWidget(self.rangingPageUi)
self.mainPageUi.chooseSignal.connect(self.showDialog)
self.cameraPageUi.returnSignal.connect(self.returnDialog)
self.drivePageUi.returnSignal.connect(self.returnDialog)
self.rangingPageUi.returnSignal.connect(self.returnDialog)
def showDialog(self,msg):
print(0)
if msg == 'camera':
self.Stack.setCurrentIndex(1)
print(1)
elif msg == 'ranging':
self.Stack.setCurrentIndex(2)
print(2)
elif msg == 'drive':
self.Stack.setCurrentIndex(3)
print(3)
def returnDialog(self):
self.Stack.setCurrentIndex(0)
我在这里使用了QStackedWidget叠层窗口,将所有子窗口添加进来,根据不同的点击显示不同的页面。
5、最后,需要有一个main入口,我们单独再写一个main.py文件,这也和C++工程比较统一,具体内容如下:
from PyQt5.QtWidgets import *
from mainwindow import MainWindow
import sys
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
6、PyQt5的多界面开发工程的大体框架就完成,现在只需要添加具体的内容即可,可以运行试一下,注意一定要运行main.py文件,如果运行其它py文件,只会出现如下提示。