PyQt5实现多文件调用以及UI和逻辑分离

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新手,请大家多多指教。

一、PyCharm+PyQt5的环境配置

具体配置可以在网上搜其它帖子,在这里不作过多论述。

个人在使用过程中,有个习惯,当我们新建了xxx.ui文件,然后使用pyuic5生成xxx.py文件的时候,为了更清楚的看出来这个py文件是由ui文件生成的,也为了防止我们修改这个文件,可以在setting中将pyuic5的Arguments配置中改为“$FileName$ -o ui_$FileNameWithoutExtension$.py”,这样生成的py文件都是加了“ui_”前缀的。

PyQt5实现多文件调用以及UI和逻辑分离_第1张图片

二、使用Qt Designer将界面显示与业务逻辑分离

大部分的教程都是将使用Qt Designer进行界面布局和Qt中控件的使用分开来讲,讲Qt Designer的时候直接在.ui文件生成的.py文件里面进行修改,这样虽然可以理解界面和代码之间是如何互联共通的,但是不方便.ui文件的修改。在讲Qt的各种控件的使用的时候,又几乎全部用代码在布局界面,这对于初识Qt的新手来说倒还可以,但对于像笔者这种只换语言不换框架的工程师来讲,未免有点太拖沓,所以我们直接讲将界面显示与业务逻辑分离的方式开发。

1、例如我新建一个mainpage.ui文件,里面放几个控件。

PyQt5实现多文件调用以及UI和逻辑分离_第2张图片

2、将mainpage.ui文件转换成ui_mainpage.py文件

PyQt5实现多文件调用以及UI和逻辑分离_第3张图片

当然,也可以直接使用命令生成,不过需要配置环境变量,需要大家自己去配置,“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入口,进行多文件调用。

三、PyQt5工程中的多文件开发

习惯使用C++开发Qt工程,都是习惯多文件分离开发,每个界面一个ui文件,转换后加一个py文件,再加负责一个业务逻辑的py文件,一共三个文件。例如写一个四个界面的工程,步骤如下:

1、使用Qt Designer新建四个不同的ui文件,分别为camerapage.ui、drivepage.ui、mainpage.ui、rangingpage.ui

PyQt5实现多文件调用以及UI和逻辑分离_第4张图片

2、使用pyuic5将四个ui文件转换成对应的py文件,分别为ui_camerapage.py、ui_drivepage.py、ui_mainpage.py、ui_rangingpage.py

PyQt5实现多文件调用以及UI和逻辑分离_第5张图片

可以将和UI文件相关的文件放在一个目录中,方便管理,笔者把它们都放在了HomePages目录中。

PyQt5实现多文件调用以及UI和逻辑分离_第6张图片

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文件,只会出现如下提示。

你可能感兴趣的:(python,开发语言)