PyQt 设计思想,创建窗口,自定义标题栏,鼠标移入、移出、点击事件,切换窗口等基本操作功能实现

5 篇文章 1 订阅


一、前言

1.1Qt与PyQt

  PyQt是Qt在python中的封装库,其功能在于快速实现可视化界面软件在python环境下的部署。
  PyQt的基本思想诸如封装继承、信号与槽的机制等等与Qt一致,只是实现是通过python语言。

1.2C++与Python

  C++为编译型语言,接近硬件底层,合理利用指针可节约硬件资源,执行速度较快,适合嵌入式开发或大型服务器开发。
  Python为解释型语言,语法简单,有大量现成的开源算法库诸如Numpy、Matplotlib、Tensorflow、Opencv-python等,其在人工智能算法开发领域有着得天独厚的优势。
  python与C++在定义类时的区别:
  (1)C++定义一个具体的类时往往有.h文件与.cpp文件两个文件存在,其中.h文件负责类的声明,包含声明其相关访问权限、相关类型的变量及方法,且在C++中可定义各种类型的指针变量,可通过动态分配内存的方式将某些变量分配至堆区。而.cpp文件负责该类的具体实现,某个文件引用其他文件时,通过#include "xxxx.h"的形式包含。
  (2)Python定义一个具体的类直接在.py文件中实现,声明与定义同时实现,将另外某个文件引入本文件通过import xxx,或者from xxx import xxx实现。

本博客记录通过PyQt创建界面程序的一些常规性的操作,操作环境为win10,pythonIDE为pycharm,通过Anaconda3管理python虚拟环境。


二、效果

主要实现的窗口操作为以下4点内容:
(1)在“灰色”区域,即自定义标题栏区域内,最左侧为logo图标,往右为软件名称标题,最右边分别外三个按钮,依次为“最小化”、“关闭”按钮;
(2)标题栏区域(包含logo以及名称标题上)拖动鼠标,实现整个窗口的拖动功能,拖拽其他区域,不会拖动整个窗口;
(3)中间区域为显示区域,鼠标移入、移出,相应位置颜色发生变化;
(4)点击左边第一块绿色区域后,切换显示界面进入下一页,下一页点击返回按钮后再返回主页面。

下图为鼠标移入、移出,拖动自定义标题栏的效果。

在这里插入图片描述

下图为点击具体区域后实现最小化界面、关闭界面、切换显示区域内容的效果。

在这里插入图片描述

三、代码

3.1 编程思想

对一个PyQt项目进行编程,思路与Qt项目类似:
  Step1:首先设计一个主窗体类(这里可以是QMainWindow类,QWidget类,或是它们的派生类),令其在主函数中循环阻塞,进行GUI展示,这样即一个可视化程序的大框架;
  Step2:再该窗体类上进行相关逻辑操作,可以设计多个窗体类进行嵌套、切换等操作,通常需通过QtDesigner直接进行界面布局设计,设置布局关系、尺寸、styleSheet以及资源文件等,也可以直接代码实现(对于简单布局窗体可以,复杂布局窗体推荐还是利用QtDesigner);
  Step3:内部逻辑关系的实现,合理利用信号与槽的机制,重写相关函数如mousePressEvent等,合理利用定时器等;
  Step4:合理利用PyQt多线程(QThread)、串口通信(QSerialPort)、多媒体(QMovie、QSound等)、图表模块(QChart)等多个模块进行相关操作。

3.2 创建主窗体类

  python工程文件夹下内容如下图所示,最上层包含image、sound、UI三个文件夹及多个.py,src.qrc文件,其中image、sound两个文件夹内分别放置图像、音效文件,UI文件夹内为.ui文件及其生成的界面类py文件。

工程文件夹内容的设置时,本人习惯将所有UI设计相关的.ui及其生成的.py文件统统放置于同一文件夹UI内,使得整个工程文件夹排列较为整洁。

PyQt工程没有Qt中的.pro文件,且也不谈debug或者release版本及其编译文件夹路径的配置问题。

在这里插入图片描述

3.2.1 main.py

在python项目中通常以main.py作为整个程序的入口。
通过if __name__ == '__main__':语句提示python解释器此处开始运行,在页面上右击run(shift+F10)快速运行该脚本

首先application = QApplication(sys.argv) # 窗口通讯创建一个QApplication对象。然后再root = Widget() # 创建对象创建窗体对象,调用该窗体对象的show()方法,并通过sys.exit(application.exec_()) # 消息循环阻塞进程。这样便创建了一个主窗体,后面要做的就是不断往主窗体里加各种对象以实现相应的效果。

import sys
from widget import *
if __name__ == '__main__':
    application = QApplication(sys.argv)  # 窗口通讯
    application.setStyle('windows')  # 设置 windows 风格
    root = Widget()  # 创建对象
    root.show()  # 展示窗口
    sys.exit(application.exec_())   # 消息循环

3.2.2 GUI窗体类结构

3.2.2.1 PyQT界面类的定义及设计

  一个PyQt界面类主要包含一个.ui文件,一个由.ui文件生成的界面py文件以及一个逻辑实现py文件,若.ui文件需要图片、字体或者音效等资源,额外需要一个.qrc文件及其生成的py文件。
  命名规则,将.ui格式文件统一加ui_前缀,生成的.py文件与.ui文件同名,逻辑实现py文件与该类同名。如定义一个名称为Widget的类,则其ui文件名为ui_Widget.uiui_Widget.py,逻辑实现py为Widget.py

Step1:根据需求输入设计并绘制.ui文件

  通过QtDesigner实现。
  (1)绘制UI界面;
  (2)有时需要导入.qrc资源文件;
  (3)绘制完毕后通过UIC工具将.ui文件转换为.py文件;
  (4)有qrc文件的通过RCC工具将.qrc文件转换为src_**.py文件。

Step2:根据逻辑关系编写逻辑py文件

  通过Pycharm(或其它编辑器)实现。

3.2.2.2 class Widget的定义及设计

main.py中的Widget类由Ui_Widget以及Qwidget派生,Ui_Widget类涉及UI布局、QWidget涉及窗口对象的一般性操作。

class Widget结构如下图所示。

Ui_Widget
+self.stackedWidget
+self.labelinfo
+setupUi(self)
Widget
+self.Title
+self.WelcomPage
+init(self)
+changepage(self)
+backtowelPage(self)
QWidget
+QWidget一般性属性
+QWidget一般性方法()

Widget类自身有两个属性,即Title以及WelcomePageTitle为自定义标题栏类WelcomePage为欢迎页面类,这两个类均为PyQT界面类,有.ui文件及其生成的.py文件,也包括一个各自的逻辑实现py文件。

(1) ui_Widget.ui

Ui_Widgetui_widget.ui文件生成,ui_widget.ui如下图所示。
在这里插入图片描述
在右上方对象查看器中可以看到,在最顶层的QWidget下面自由放置了一个QLabel以及一个QStackedWidgetQwidget类对象名称为WidgetWidget此时不设置布局,布局通过后续代码实现。

(2) ui_Widget.py

以下为ui_Widget.py文件代码,每次对UI界面重新布局,即修改ui_Widget.ui后,均需要通过UIC工具重新生成该代码文件,因此对建议在该文件上编写代码。

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'ui_widget.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!

from PyQt5 import QtCore, QtGui, QtWidgets

class Ui_Widget(object):
    def setupUi(self, Widget):
        Widget.setObjectName("Widget")
        Widget.resize(1600, 1000)
        Widget.setMinimumSize(QtCore.QSize(1600, 1000))
        Widget.setMaximumSize(QtCore.QSize(1600, 1000))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/image/icon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        Widget.setWindowIcon(icon)
        Widget.setStyleSheet("QLabel#labelinfo\n"
"{\n"
"    \n"
"    background-color: rgb(255, 255, 255);\n"
"    border:1px solid;\n"
"}")
        self.stackedWidget = QtWidgets.QStackedWidget(Widget)
        self.stackedWidget.setGeometry(QtCore.QRect(30, 90, 821, 561))
        self.stackedWidget.setStyleSheet("")
        self.stackedWidget.setObjectName("stackedWidget")
        self.labelinfo = QtWidgets.QLabel(Widget)
        self.labelinfo.setGeometry(QtCore.QRect(30, 680, 821, 40))
        self.labelinfo.setMinimumSize(QtCore.QSize(0, 40))
        self.labelinfo.setMaximumSize(QtCore.QSize(16777215, 40))
        self.labelinfo.setObjectName("labelinfo")

        self.retranslateUi(Widget)
        QtCore.QMetaObject.connectSlotsByName(Widget)

    def retranslateUi(self, Widget):
        _translate = QtCore.QCoreApplication.translate
        Widget.setWindowTitle(_translate("Widget", "Widget"))
        self.labelinfo.setText(_translate("Widget", "TextLabel"))

import src_rc

(3) Widget.py

class Widget即Widget类的实现,是在Widget.py文件中

class Widget(QWidget, Ui_Widget):通过关键字class 定义类名称,后面括号中放父类的类名称。

def __init__(self, parent=None):该类的构造方法,括号内self指代本实例自身,约定使用“self”,最后一个参数为“parent”,这是python内部会处理的参数,没有parent的窗口会被认定是顶层窗口,此处按默认写即可。

super(Widget, self).__init__(parent)调用父类构造函数,这句必须有,不调用父类的构造函数的话无法显示Ui_Widget中的内容。

self.t1 = Title()实例化一个自定义标题栏界面类。

init(self)对界面的逻辑操作,如设置布局,设置信号与槽的连接情况等等操作。

self.setWindowFlags(Qt.FramelessWindowHint)设置窗口的无边框属性,需设置该属性后自定义标题栏才能生效。

changepage(self)切换页面至各自页面的操作。

backtowelPage(self)返回主页面的操作。

from UI.ui_widget import *
from welcomepage import *
from title import *
from visualslampage import *


# 定义Widget类继承QWidget以及Ui_Widget,缺一不可,继承QWidget一般性窗口操作方法,继承Ui_Widget的Ui设计
class Widget(QWidget, Ui_Widget):
    # 构造方法
    def __init__(self, parent=None):
        # 调用父类的构造方法
        super(Widget, self).__init__(parent)
        # 实例化标题栏
        self.t1 = Title()
        # 实例化欢迎页面
        self.p1 = WelcomePage()
        # 初始化窗体内的逻辑操作
        self.init()

    def init(self):
        # 初始化Ui界面,此处调用的是Ui_Widget中的setupUi函数
        self.setupUi(self)
        # 设置无边框属性,该属性继承于QWidget
        self.setWindowFlags(Qt.FramelessWindowHint)
        # 新建一个QVBoxLayout实例,用于垂直布局
        layout = QVBoxLayout(self)
        layout.addWidget(self.t1)
        layout.addWidget(self.stackedWidget)
        layout.addWidget(self.labelinfo)
        layout.setSpacing(0)
        layout.setContentsMargins(0, 0, 0, 0)

        self.stackedWidget.addWidget(self.p1)
        self.stackedWidget.setCurrentIndex(0)
        self.labelinfo.setText("欢迎使用近地告警地面数据记录系统!上海航空电器有限公司荣誉出品!")
        #信号与槽连接,label按下后调用changepage函数
        self.p1.label.label_pressed.connect(self.changepage)
	
	#label按下信号对应的槽函数
    def changepage(self):
        if self.sender() == self.p1.label:
            self.labelinfo.setText("进入视觉辅助模块!")
            #新建visualslamPage实例
            self.p4 = visualslamPage()
            #连接visulslamPage中的按钮按下信号与backtowelPage函数
            self.p4.pushButton.clicked.connect(self.backtowelPage)
            self.stackedWidget.addWidget(self.p4)
            self.stackedWidget.setCurrentIndex(1)
	
	#visulslamPage中按钮按下信号所对应的槽函数
    def backtowelPage(self):
        self.stackedWidget.setCurrentIndex(0)
        self.labelinfo.setText("主页")
        if self.sender() == self.p4:
        	#删除visulslamPage对象
            del self.p4
3.2.2.2 class Title的定义及设计

Widget类中属性self.t1 = Title()实例化一个Title类,在该类中实现了自定义标题栏的各个功能,如显示软件标题、logo、最小化、关闭,拖拽移动窗口等功能。

  Title类实现方法与Widget类实现方法步骤一致,即设计.ui文件,生成其.py,编写逻辑py。
  在实现逻辑功能的py文件中重写以下三个鼠标事件函数。

    def mousePressEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.m_leftButtonPressed = True
            self.m_start = event.globalPos()

    def mouseMoveEvent(self, event):
        if self.m_leftButtonPressed:
            self.window().move(self.window().geometry().topLeft() + event.globalPos()-self.m_start)
            self.m_start = event.globalPos()

    def mouseReleaseEvent(self, event):
        if event.button() == QtCore.Qt.LeftButton:
            self.m_leftButtonPressed = False
3.2.2.2 class WelcomePage的定义及设计

Widget类中属性self.p1 = WelcomePage()实例化一个WelcomePage类,在该类中实现了多个模块的选择功能,即鼠标移入、移出、点击事件的设计。

在这里插入图片描述
  WelcomePage类实现方法与Widget类实现方法步骤一致,即设计.ui文件,生成其.py,编写逻辑py。

WelcomePage类中需要对普通的QLabel类做提升操作,将鼠标操作变化QLabel样式的效果封装起来。

(1) WelcomePage.py

  此处的WelcomePage.py内暂未开展相关逻辑操作,仅作一个初始化父类Ui_WelcomePage类的功能。

(2) WelcomePage.ui

  WelcomePage.ui的设计如下图,将各个Qlabel按照需求进行布局,对绿色区域的4个QLabel右键提升为welLabel
  此处的WelcomePage.py内暂未开展相关逻辑操作,仅作一个初始化父类Ui_WelcomePage类的功能。
填写提升的类的类名称为"welLabel",头文件自动生成为"wellabel.h",这里由于是在python环境中,没有.h文件,忽略即可,这样编译器会在工程目录下自动寻找"wellabel.py"文件引入"ui_WelcomePage.py"
在这里插入图片描述
现在仅需在"wellabel.py"中实现对QLabel的封装效果即可。

(3) wellabel.py
from PyQt5.Qt import *

class welLabel(QLabel):
    label_pressed = pyqtSignal()

    def __init__(self, parent=None):
        super(welLabel, self).__init__(parent)

    def enterEvent(self, event):
        self.setStyleSheet("border:6px solid;"
                  "border-color:rgb(255,0,0);"
                  "background-color: rgb(0, 0, 255);")

    def leaveEvent(self, event):
        self.setStyleSheet("border:0px")
        self.setText(" ")
        self.setAlignment(Qt.AlignCenter)

    def mousePressEvent(self, event):
        self.setStyleSheet("border:2px solid;"
                      "background-color: rgb(255, 0, 0);")
        self.setFont(QFont("Microsoft YaHei", 30, 75))
        self.setText("被点击了")
        self.setAlignment(Qt.AlignCenter)
        self.label_pressed.emit()

label_pressed = pyqtSignal()为定义pyqt信号的操作,与Qt中需要在头文件中声明信号类型以及数据类型不同,python中直接在类定义中定义即可。

mousePressEvent(self, event)self.label_pressed.emit()发出了上述信号,在Widget类中将该信号与changepage(self)连接,实现点击QLabel实现页面切换的操作。

页面切换效果如下图所示。
在这里插入图片描述

四、代码资源

代码

项目代码至https://download.csdn.net/download/wang_chao118/86511095处下载。

项目环境

本项目在win10平台,Anaconda3虚拟环境下运行,
通过cmd配置以下内容

conda create -n py37_pyqt5 python==3.7
pip install pyqt5
pip install pyqt5-tools

在Pycharm编辑器中设置项目的虚拟环境为上述环境py37_pyqt5

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
以下是使用PyQt实现自定义标题栏的示例代码: ```python from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout, QLabel, QPushButton from PyQt5.QtCore import Qt from PyQt5.QtGui import QColor class CustomTitleBar(QWidget): def __init__(self, parent): super().__init__(parent) self.setFixedHeight(30) layout = QVBoxLayout(self) layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) self.title_label = QLabel("Custom Title Bar") self.title_label.setAlignment(Qt.AlignCenter) layout.addWidget(self.title_label) self.minimize_button = QPushButton("-") self.minimize_button.setFixedSize(30, 30) self.minimize_button.clicked.connect(self.parent().showMinimized) layout.addWidget(self.minimize_button) self.maximize_button = QPushButton("□") self.maximize_button.setFixedSize(30, 30) self.maximize_button.clicked.connect(self.toggleMaximize) layout.addWidget(self.maximize_button) self.close_button = QPushButton("×") self.close_button.setFixedSize(30, 30) self.close_button.clicked.connect(self.parent().close) layout.addWidget(self.close_button) layout.addStretch() self.setStyleSheet(""" background-color: #333333; color: white; font-size: 14px; font-weight: bold; padding-left: 5px; padding-right: 5px; """) def toggleMaximize(self): if self.parent().isMaximized(): self.parent().showNormal() self.maximize_button.setText("□") else: self.parent().showMaximized() self.maximize_button.setText("◻") class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("Custom Title Bar Example") self.setWindowFlags(Qt.FramelessWindowHint) self.setAttribute(Qt.WA_TranslucentBackground) self.title_bar = CustomTitleBar(self) self.setCentralWidget(QWidget(self)) self.centralWidget().setLayout(QVBoxLayout()) self.centralWidget().layout().addWidget(QLabel("Content Area")) self.setStyleSheet(""" QMainWindow { background-color: white; } """) self.show() app = QApplication([]) window = MainWindow() app.exec_() ``` 这段代码创建了一个自定义标题栏,其中包含了一个标题标签、最小化按钮、最大化/还原按钮和关闭按钮。通过设置窗口的`setWindowFlags(Qt.FramelessWindowHint)`和`setAttribute(Qt.WA_TranslucentBackground)`属性,使窗口无边框并且背景透明。然后,将自定义标题栏添加到主窗口的顶部,并在主窗口的中央添加一个内容区域。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wang_chao118

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值