痞子衡嵌入式:超级好用的可视化PyQt GUI构建工具(Qt Designer)
大家好,我是痞子衡,是正经搞技术的痞子。今天痞子衡给大家介绍的是pyqt gui构建工具qt designer。
痞子衡开博客至今已有好几年,一直以嵌入式开发相关主题的文章为主线,偶尔穿插一些其他技术或工具的介绍,前段时间因为要做一个跟恩智浦mcu启动相关的上位机工具 nxp-mcubootutility,网上搜索对比了几个python下的gui框架,最终选择了wxpython这个成熟稳定的gui库,从而接触到wxformbuilder这个配套wxpython使用的gui构建工具。苦于网上关于该构建工具的中文资料不多,所以根据自己使用经验写了一篇 极易上手的可视化wxpython gui构建工具(wxformbuilder),没想到该篇博客很受欢迎,居然目前是痞子衡博客里阅读量最高的一篇博客,而且也是搜索 wxformbuilder 关键字出来的中文结果排名第二位的链接,真是万万没想到。
wxpython框架虽然成熟稳定,但是相对最近更火的pyqt框架来说,还是显得古老了一些,控件风格不符合现代审美观,因此痞子衡决定学习一下pyqt的用法,感受下pyqt做出来的界面效果到底如何。根据wxpython学习经验,当然首先要从pyqt的可视化gui构建工具qt designer开始下手,因此便有了本篇博客。
一、qt designer工具背景
qt designer从名字上来看显然就是久负盛名的跨平台gui库qt的配套设计工具。qt库本身是c++语言实现的;riverbank公司用python语言对qt做了一层封装,封装后便成了python版gui库pyqt(目前最新的版本是pyqt5);下面是这两个gui库的官方主页:
- qt项目官方网站:
- pyqt项目官方主页:
qt的各种ui控件功能均是通过class来实现的,这个链接 列出了qt里的所有class。pyqt5其用法基本与qt一致,这个链接 https://www.riverbankcomputing.com/static/docs/pyqt5/module_index.html#ref-module-index 列出了pyqt5里所有的modules,其中用于设计界面最常用的便是 qtwidgets 模块。
在qt官网的tools下面可以看到所有qt相关的工具,在ui design tools下面可以找到qt designer,可见qt designer是用于设计gui界面的工具之一。由于痞子衡介绍的pyqt5下的gui构建工具,因此本文的qt designer并不是直接在qt官网下载安装的,具体安装方法详见下一章节。
二、qt designer快速上手
使用qt designer去设计gui界面可以不用掌握pyqt5里的各个控件class的具体用法,你只需要在qt designer软件里添加这些控件即可,下面痞子衡将简介qt designer的用法:
2.1软件安装
简单了解pyqt5的module和class便可以开始设计gui界面,首先得安装qt designer,在安装完python3之后(痞子衡安装的是python 3.6),借助\python36\scripts\下的pip.exe工具来分别安装pyqt5和qt designer,命令见如下主页:
- pyqt5安装: https://pypi.org/project/pyqt5/
- qt designer安装:
安装完成之后打开\python36\lib\site-packages\pyqt5_tools\designer.exe,这便是qt designer。
2.2软件界面
打开qt designer可见到如下界面,界面主要分为四大区:项目区、控件区、编辑区、属性区。软件使用起来非常简单,就是在【控件区】里点击添加需要的控件,这些控件的效果会在【编辑区】里实时显示,并在【属性区】这些控件的属性,【项目区】用于显示控件间的层级关系。
2.3基础布局
让我们开始创建一个gui的基础框架,基础框架包括:container(局部外围轮廓)、layout(内部控件区)、menubar(顶部菜单栏)、statusbar(底部状态栏)。
第一步是添加一个container(此处选择常用的frame),这是gui的轮廓基础,有了frame之后还需要在frame里添加layout(此处选择竖排样式),用于规范后续控件的排列样式。默认gui即有menubar和statusbar。
2.4多种控件
基础布局搞定之后,接下来便是在layout里添加控件,pyqt5支持的控件非常丰富,其中比较常用的是如下几个:各种button(按钮)、label(静态显示文本框)、text edit(输入输出文本框)、check box(选中框)、各种slider(滑动条)等。由于前面痞子衡选择的是verticallayout,因此你会看到控件们都是竖着排的。
2.5控件属性
添加了所有控件之后,下一步便是分别设置控件的属性,进一步调整控件。痞子衡以push button属性为例,痞子衡勾选了如下3项比较重要的属性设置,分别是objectname(button在后续python代码的对象名,一般需要按其功能修改,修改后使得代码阅读/修改起来更直观)、geometry(设置button的尺寸与位置,如果是放在layout里,则受限于layout不可设置)、text(button在gui里显示的标签名,此处是pushbutton,也需要按其功能修改,方便用户使用软件)。
2.6保存为xml代码(工程文件)
当gui界面布局全部完成之后,需选择file->save as保存为.ui文件,该文件既是qt designer的工程文件也是最终生成的gui xml代码文件,痞子衡保存在了my_win.ui文件里。
2.7转换成python代码
虽然保存的my_win.ui文件里是可以直接在python代码里被加载使用的,但是更好的办法是直接将.ui文件转换成相应的.py文件。需要借助 \python36\scripts\pyuic5.exe工具,命令如下:
pyuic5 - o my_win.py my_win.ui
转换成功后,让我们打开my_win.py文件,可以简单看一下这个my_win.py里的内容,代码里首先import了pyqt5相关库,并定义了名为ui_mainwindow的class,这个class主要包含两个函数setupui()和retranslateui()。setupui()里初始化了各个控件成员self.xx,这与我们在qt designer里添加控件是对应的。
# -*- coding: utf-8 -*- # form implementation generated from reading ui file '.\my_win.ui' # # created by: pyqt5 ui code generator 5.11.3 # # warning! all changes made in this file will be lost! from pyqt5 import qtcore, qtgui, qtwidgets class ui_mainwindow(object): def setupui(self, mainwindow): mainwindow.setobjectname("mainwindow") mainwindow.resize(603, 448) self.centralwidget = qtwidgets.qwidget(mainwindow) self.centralwidget.setobjectname("centralwidget") self.frame = qtwidgets.qframe(self.centralwidget) self.frame.setgeometry(qtcore.qrect(100, 80, 361, 211)) self.frame.setframeshape(qtwidgets.qframe.styledpanel) self.frame.setframeshadow(qtwidgets.qframe.raised) self.frame.setobjectname("frame") self.verticallayoutwidget = qtwidgets.qwidget(self.frame) self.verticallayoutwidget.setgeometry(qtcore.qrect(30, 20, 160, 172)) self.verticallayoutwidget.setobjectname("verticallayoutwidget") self.verticallayout = qtwidgets.qvboxlayout(self.verticallayoutwidget) self.verticallayout.setcontentsmargins(0, 0, 0, 0) self.verticallayout.setobjectname("verticallayout") self.pushbutton = qtwidgets.qpushbutton(self.verticallayoutwidget) self.pushbutton.setenabled(true) self.pushbutton.setobjectname("pushbutton") self.verticallayout.addwidget(self.pushbutton) self.label = qtwidgets.qlabel(self.verticallayoutwidget) self.label.setobjectname("label") self.verticallayout.addwidget(self.label) self.textedit = qtwidgets.qtextedit(self.verticallayoutwidget) self.textedit.setobjectname("textedit") self.verticallayout.addwidget(self.textedit) self.checkbox = qtwidgets.qcheckbox(self.verticallayoutwidget) self.checkbox.setobjectname("checkbox") self.verticallayout.addwidget(self.checkbox) self.horizontalslider = qtwidgets.qslider(self.verticallayoutwidget) self.horizontalslider.setorientation(qtcore.qt.horizontal) self.horizontalslider.setobjectname("horizontalslider") self.verticallayout.addwidget(self.horizontalslider) mainwindow.setcentralwidget(self.centralwidget) self.menubar = qtwidgets.qmenubar(mainwindow) self.menubar.setgeometry(qtcore.qrect(0, 0, 603, 21)) 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", "pushbutton")) self.label.settext(_translate("mainwindow", "textlabel")) self.checkbox.settext(_translate("mainwindow", "checkbox"))
三、使用qt designer生成的代码
前面已经使用qt designer生成gui界面类ui_mainwindow并保存在my_win.py文件中,此时需要创建一个主函数文件去调用ui_mainwindow,下面是痞子衡创建的main_win.py中的代码:
import sys from pyqt5.qtwidgets import qapplication, qmainwindow # 导入my_win.py中内容 from my_win import * # 创建mainwin类并传入ui_mainwindow class mainwin(qmainwindow, ui_mainwindow): def __init__(self, parent=none): super(mainwin, self).__init__(parent) self.setupui(self) if __name__ == '__main__': # 下面是使用pyqt5的固定用法 app = qapplication(sys.argv) main_win = mainwin() main_win.show() sys.exit(app.exec_())
3.1触发事件与响应
有了button,我们肯定希望其能与一个响应函数相联系起来,此处痞子衡定义了showmessage()函数,并且将showmessage()与pushbutton绑定起来,点击button便会执行一次这个showmessage()函数。代码如下:
class mainwin(qmainwindow, ui_mainwindow): def __init__(self, parent=none): super(mainwin, self).__init__(parent) self.setupui(self) # 将响应函数绑定到指定button self.pushbutton.clicked.connect(self.showmessage) # button响应函数 def showmessage(self): self.textedit.settext('hello world')
最后让我们测试一下这个gui软件,在命令行下运行main_win.py
ps d:\my_git_repo\> python .\main_win.py
至此,pyqt5 gui构建工具qt designer痞子衡便介绍完毕了,掌声在哪里~~~