目录

1、简介

2、安装步骤

2.1 安装PyQt5

2.2 Pycharm配置

3、界面设计介绍

3.1 组件

3.1.1 菜单类组件

3.1.2 图标和快捷键设置

3.1.3 分页组件Tab Widget

3.2 整体框架

3.2.1 ui 解析py文件

3.2.2 主函数

3.3 信号和槽

3.2.1 自定义信号和槽

3.4 交互实现



1、简介

PyQt基于QT库的python封装,是一个图形用户界面(GUI)工具包,允许用户使用python语言创建桌面应用程序。目前,不同版本中,PyQt5是较为流行的版本,支持python 2.7 和 python 3.x 。

PyQt支持两种开发方式,可视化和编程化。

 - 编程式创建界面无需多说,pip安装成功以后,有较深基础功底的可直接上手编码。
 - 可视化方式对新手非常友好,用户可基于Qt Designe工具包进行组件拖拽、布局管理等操作。

2、安装步骤

2.1 安装PyQt5

在自己的python虚拟环境中,pip安装依赖包PyQt5, pyqt5_tools
pyqt5_tools 包含一些辅助 PyQt5 的开发工具,其中就有我们要用的 Qt Designer

pip install PyQt5 PyQt5-tools

一般会报错或爆红,建议带上国内镜像源

-i https://pypi.tuna.tsinghua.edu.cn/simple

安装成功以后,win+s 搜索"designer",出现图标表示成功。

如果没有,可以使用下面链接下载安装包,一键安装即可,安装成功后,会直接弹出来该工具。

https://build-system.fman.io/qt-designer-download

2.2 Pycharm配置

python语言开发,大部分使用Pycharm集成开发工具,这里在Pycharm工具中配置QT designer外部工具,在工程开发中让界面设计和解析变得容易。

打开Pycharm,File -> Settings ->Tools -> External Tools,点击加号添加,Program我这里添加的是安装包路径,因为我安装了PyQt_tools,找不到designer。Working directory设置保存ui文件的文件,$FileDir$表示当前文件所在目录

全部设置完成以后,可在Tools ->External Tools中打开。

用designer设计好的界面,会以.ui文件形式保存,下次直接右击该文件,选择External Tools中的designer工具加载即可

保存界面的另一种方式,是将生成的.ui文件解析成python脚本,下次可以直接运行脚本文件,打开ui界面。这种方式一般在整个GUI界面设计完成后执行,当然也不失为学习编程式UGI的好办法。

解析需要用到另外一个工具pyuic,直接命令生成py文件,该工具在安装pyqt后自带,无需安装。

pyuic5 /untitled.ui -o output_ui.py

另一种方式,是将该工具配置到Pycharm中,和上面designer添加方式一样,填写信息如下。

3、界面设计介绍

打开外部工具,会弹出窗口提示,如果不想每次启动都弹,在该窗口左下角设置去掉即可。

先整体认识下designer工具,左侧是不同类型组件,右侧可查看ui结构以及设置每个组件的属性,中间灰色地带为画布。

3.1 组件

组件是构建图像界面基本的模块,pyqt提供了多种组件,这里介绍一些使用频率较高的组件

组件名功能
窗口组件Main Window用于创建应用程序的主窗口,包含额外功能,如菜单栏、工具栏、状态栏等
Widget通用窗口组件,无额外功能,可作为Main Window的子组件或容器小部件使用
菜单类MenuBar菜单栏
StatusBar状态栏
ToolBar工具栏
展示组件Label显示文本或图像
Progress Bar显示进度条
Graphics View显示图像,支持缩放平移以及交互
List View以列表形式展示多行数据
输入组件Line Eidt输入单行文本
Text Edit输入多行文本
按钮组件Push Button按钮
CheckBox复选框
RadioButton单选按钮,多选项中只允许选择一个

3.1.1 菜单类组件

菜单栏组件包含 菜单栏+状态栏+工具栏 三部分

在designer中,先创建一个主窗口, File->New->Main Window

查看主窗口右侧ui结构,自带的菜单栏,状态栏,缺少工具栏ToolBar,选中MainWindow右击添加

主窗口中双击Type Here,输入菜单栏的名称File,回车即可进入到二级菜单栏,我这创建了四个二级菜单项,如下图所示。三级菜单项创建,点击二级菜单项右侧蓝色加号创建。如果想在菜单上面添加分割线,选中菜单名右击 Insert separator。

  • Type Here:输入菜单名
  • Add Separator:添加分割线

工具栏按钮不同于普通按钮,本质上是动作Action,而菜单栏中的每个菜单项也是Action。在PyQt中,如果在菜单栏中已经创建了某项,比如open,此时open这个动作就已经存在了。

工具栏按钮是直接拖拽现有的动作Action生成的,所以菜单栏和工具栏中,只要是对应同一Action的按钮,响应操作是一样的。在这里,我理解的工具栏更像是快捷键,将菜单栏中较为重要的选项放在外面,便于用户操作,接下里演示如何拖拽生成。

右击选中ui结构中的工具栏(如果没有可添加),下面属性设置中选中QtoolBar,其中

  • movable:工具栏移动,默认选中,主窗口左侧会出现一列
  • allowedAreas:设置工具栏位置,左右上下均可

找到工具栏可拖拽放到上下左右那个位置都行,下图是放在左侧了。

接下来拖拽Action到工具栏,首先需打开动作编辑(上面总体介绍的图解哪里有),能看到刚才菜单栏中创建的四个菜单项的Action都已经存在了,用鼠标拖住向工具栏位置放。

拖拽都没成功过,手都酸了,一个也没拖进去。这里分享个比较容易拖拽的方式,调节工具栏的高度,怎么调节看下图,依次选中图中选项,设置工具栏的宽和高。

3.1.2 图标和快捷键设置

如果想为菜单栏设置快捷键以及图标,可在动作编辑器中,选中某个Action右击,Eidt。

如下图,快捷键哪直接按键盘就自动输入进去了,Icon图标设置右边下拉三角中,我用的是choose file选择文件。

为全部的Action设置完成以后,如下图右侧所示,这时候拖拽工具栏只有图标,菜单栏中文字,图标,快捷键信息都有,想查看,可用ctrl+r快捷键方式,预览整个界面效果。

切记,添加的图标文件一定要放在你的工程目录下,否则换台电脑找不到图标就报错了 ,解析成python文件后,看下代码,里面用的是绝对文件路径。

3.1.3 分页组件Tab Widget

PyQt中的Tab Widget组件,通过创建选项卡界面,允许在一个窗口中显示多个界面,并来回切换,接下来让我们看看如何实现。

使用designer工具,创建主窗口后,直接拖拽左侧容器组件中的Tab Widget组件,默认是创建两个选项卡的,如中间画布所示,右侧是属性设置中修改选项卡名字的位置。

如果想增加新的选项卡,选中其中一个选项卡,右击弹出属性设置,如下可在该选项卡前面或后面增加新的选项卡。

删除选项卡,依然是选中右击,如下图所示,右拉三角delet。

接下来大家在每个选项卡内 设计自己的界面了,每个界面也都是独立的。

3.2 整体框架

这部分介绍如何使用.py文件执行ui界面。

3.2.1 ui 解析py文件

使用designer设计界面后,保存为.ui文件,使用pyuic工具生成.py,可直接使用如下命令

pyuic5 /untitled.ui -o output_ui.py

这里生成为Mainform.py文件,着重介绍下Mainform.py文件的内容,里面定义了一个类Ui_MainWindow,两个方法setupUi,retranslateUi。用designer工具设计并解析的py文件,一般都是这样的结构模式。

在setupUi方法中,会看到很多组件的变量名,后续会引用这些组件变量做交互操作,大家要分的清自己不同组件名所对应界面的那个区域,尤其是同一种组件的多处使用,最好呢在designer设计中就按自己的想法定义每个组件的名称。

在designer设计过程中,可直接在对应组件的的属性设置中,修改objectName

3.2.2 主函数

解析后的Mainform.py文件,直接运行并不会弹出界面,需要加一些固定内容。

在同目录下,我新建了一个Main.py文件,接着填充该文件。

Main.py内容,首先,定义了一个主窗口类LMainWindow,继承基类QMainWindow,__init__方法中调用了基类的 __init__方法,初始化了 QMainWindow。(照抄即可)

from PyQt5.QtWidgets import *
from Mainform import Ui_MainWindow

class LMainWindow(QMainWindow):
    def __init__(self,parent = None):
        super(LMainWindow,self).__init__(parent)

其中,parent表示这个窗口没有指定父级窗口,可以独立存在。如果需要将它嵌入到其他窗口中,可以传递一个父级窗口作为parent参数。

 接下来定义了一个LMain类,主要是怕类名和文件名一样,所以前面加了个L,大家可自行命名。以下代码中总共包含了3个类函数,

from tkinter import filedialog
from PyQt5.QtWidgets import *
from Mainform import Ui_MainWindow
import sys
import tkinter as tk

class LMainWindow(QMainWindow):
    def __init__(self,parent = None):
        super(LMainWindow,self).__init__(parent)


class LMain():
    def __init__(self):
        self.__mainWindow = None
        self.__mainform = None

    def _init_mainWindow(self):
        "初始化主窗口"
        self.__mainWindow = LMainWindow()  # 主窗口
        self.__mainform = Ui_MainWindow()  # 主界面
        self.__mainform.setupUi(self.__mainWindow)    
   
   def run(self):
        #创建应用程序实例
        app = QApplication(sys.argv)
        #初始化主窗口
        self._init_mainWindow()
        #显示主窗口
        self.__mainWindow.show()
        #运行应用程序
        sys.exit(app.exec_())

if __name__ == '__main__':
    app = LMain()
    app.run()

初始化__init__自然无需多说,大家可根据自己的需求编写。

初始化主窗口_init_mainWindow,先实例化了上面定义的窗口类LMainWindow对象,后实例化了Mainform.py文件中的Ui_MainWindow界面对象,并主窗口类对象作为参数传递给界面对象中的setupUi函数,将界面和窗口关联起来,使得主窗口能将界面展示出来,这部分照抄就行

run函数,这部分也是照抄就行,都是打开应用程序的一些基本操作。

完成之后,执行Main.py文件,就会弹出咱们设计的ui界面了,此时点击任何按钮都不会有反应。

3.3 信号和槽

使用designer设计的UI,其中设计的动作、按钮等都是没有实际作用的,因为我们并未告诉它就或者设置它,触发后应该去做什么。这部分内容主要是讲解PyQt中的信号和槽机制,为设计的UI界面,加上实际的操作,做到真正的交互。

  • 信号(Signal):触发特定组件时发出的信号
  • 槽(Slot):接收信号后,调用执行的函数或方法

将信号与槽连接connect,组件(Action,Button等)被触发时,连接的槽函数将被调用执行。

3.2.1 自定义信号和槽

Action动作action_objectName.triggered.connect(槽函数);

Button按钮button_objectName.clicked.connect(槽函数);

3.4 交互实现

3.2小节,搭建好了打开ui界面的基本框架,这一部分内容则是为组件添加信号和槽函数,做到真正的交互。以下内容均添加在Main.py文件中得LMain类内。

这是我创建的ui,主要参考标注画框软件Labelimg的界面。

初始化界面如下,图中多创建了一个List View,大家创建一个就行。

当用户分别点击左侧的Open Dir和Save Dir后,会弹出一个对话框,让用户选择一个目录,并记录下该目录的路径,同步展示在右侧的ListView中。如下图所示。

实现代码如下,其中的组件名称可能需要更换。

from tkinter import filedialog
from PyQt5.QtCore import QStringListModel
from PyQt5.QtWidgets import *
from Mainform import Ui_MainWindow
import sys
import tkinter as tk

class LMainWindow(QMainWindow):
    def __init__(self,parent = None):
        super(LMainWindow,self).__init__(parent)


class LMain():

    def __init__(self):
        self.__mainWindow = None
        self.__mainform = None
        self.__opendir =None
        self.__savedir = None

    def _init_mainWindow(self):
        "初始化主窗口"
        self.__mainWindow = LMainWindow()  # 主窗口
        self.__mainform = Ui_MainWindow()  # 主界面
        self.__mainform.setupUi(self.__mainWindow)

    #打开文件动作的槽函数
    def _action_event_opendir(self,type):
        root = tk.Tk()
        root.withdraw()
        file_dir = filedialog.askdirectory()
        if type == 'opendir':
            self.__opendir = file_dir
            #更新显示内容
            self._init_UI(1)
        elif type == 'savedir':
            self.__savedir = file_dir
            self._init_UI(1)

    def _init_view_model(self):
        self.view_model = QStringListModel()

    def _init_UI(self,type):
        "不同状态的界面"

        #初始状态
        if type == 0:
            #设置显示的字符串内容     
            self.view_model.setStringList([])
            self.__mainform.listView.setModel(self.view_model)
        #点击Open Dir 动作后界面状态
        elif type == 1:
            #此时显示选择的opendir路径,和savedir路径
            printvalue = [self.__opendir,self.__savedir]
            self.view_model.setStringList(printvalue)
            self.__mainform.listView.setModel(self.view_model)


    def _init_mainForm_widget_event(self):
        "绑定组件事件"

        #绑定Action
        self.__mainform.actionOpen_DIR.triggered.connect(lambda :self._action_event_opendir('opendir'))
        self.__mainform.actionSave_Dir.triggered.connect(lambda :self._action_event_opendir('savedir'))


    def run(self):
        # 创建应用程序实例
        app = QApplication(sys.argv)
        self._init_mainWindow()

        self._init_view_model()
        self._init_UI(0)
        self._init_mainForm_widget_event()

        # 显示主窗口
        self.__mainWindow.show()
        # 运行应用程序
        sys.exit(app.exec_())


if __name__ == '__main__':
    app = LMain()
    app.run()
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐