是不是感觉还不错,接下来我们就来看看做这么一个小工具的过程吧。
使用Qt进行界面创作的理由是它可以很方便的生成UI界面,并且制作UI界面的过程不需要任何代码的编写,这对于想要快速制作一个界面的人来说,Qt在这方面算是个不错的优点。
首先是Qt的安装。
Qt的安装很方便,在其官网上下载便可。
Qt官网地址:Qt官网.
Python的IDE有很多,我个人喜欢PyCharm,它的代码提示与补全功能在开发任何项目里都有很大的价值。
Python 3.7的环境已经用了很多年,个人认为比较稳定。
安装好Qt以后,我们就可以进行UI界面的制作了。在制作的过程中不需要编写任何代码,只需要使用Qt本身自带的组件库就可以完成基本的UI界面了,这对于不熟悉Qt的人来说是一件好事。
打开Qt Creator后,点击“新建文件或项目”,选择默认的“Application”–“Qt Widgets Application”即可,之后自定义项目名称和路径,接下来一路按照默认点击“下一步”即可。
创建项目后具体的结构如图所示:
其中Resources为资源文件,其中包括之后界面设计用到的图标,logo等图片文件,Resources的创建方法为:右键项目名称,点击“Add New…”,选择“Qt”–“Qt Resources Files”即可完成Resources的创建。
在项目列表中点击“Forms”—”MainWindow.ui“后,便出现了如图所示的设计界面,然后便根据情况,通过拖拽左侧的组件设计自己需要的界面。
在拖拽组件后,在右侧有相关组件的属性,根据实际情况修改属性,而在其中,修改组件的名称至关重要,因为在之后使用Python代码编写具体功能时需要使用组件的名称。
和CSS类似,Qt有着自己的界面优化方案。Qt样式表(Qt Style Sheets,QSS)是用于定制用户界面的强有力的机制,其概念、术语是受到HTML中的级联样式表(Cascading Style Sheets,CSS)启发而来。而在该界面的制作中,我选择了直接在每个组件内加入QSS,但这耗费的一定的时间。
修改QSS的方法为:右键单击你想要修改的组件,选择”改变样式表“,在弹出的文本框中加入QSS,即可完成界面的美化。
在将在Qt制作的UI文件之后,就是将其转换为.py文件,在操作之前需要安装PyQt5,而安装PyQt5的方法很简单,在PyPI网站上有最新的版本,直接使用pip安装即可:
pip3 install PyQt5
直接连接PyPI服务器可能速度比较慢,我们可以使用清华大学的镜像网站:
pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple PyQt5
使用PyQt5的两个可执行程序进行转换,分别是:pyuic5.exe和pyrcc5.exe。
这两个工具软件使用起来也很方便,Win+R打开控制台后首先使用cd跳转到UI文件的地址,然后使用pyuic5和pyrcc5即可。
例如:假设文件HelloWorld.ui保存在目录“C:\admin\UI”,执行下面的指令即可完成转换:
cd C:\admin\UI
pyuic5 -o ui_HelloWorld.py HelloWorld.ui
同理,将资源文件转换为Python文件的方法如下所示:
cd C:\admin\UI
pyrcc5 res.qrc -o HelloWorld.ui
而为了节约时间,方便操作,我们可以建立一个批处理文件app.bat。你只要双击该文件便可以快速将UI文件和资源文件转换为Python文件。例如:假设你所建立的Qt项目名称为“QtApp”,所在路径为“C:\admin”,那么你就可以在该路径下新建一个批处理文件,文件内容如下:
echo off
rem将子目录QtApp下的UI文件复制到当前目录下
copy .\QtApp\HelloWorld.ui HelloWorld.ui
rem用pyuic5编译UI文件
pyrcc5 res.qrc -o HelloWorld.ui
rem用pyrcc5编译UI文件
pyrcc5 .\QtApp\res.qrc -o HelloWorld.ui
在进行如上所示的操作后,同时生产了UI文件和资源文件,这时你就可以在目录中看到编译完成后的Python文件了。
UI文件编译后的内容是一个类,如下所示:
pyuic5通过编译,实际上创建了一个叫做Ui_MainWindow的类,在这个类里包含了UI文件中各个组件的相关属性,以及涉及的资源文件等。
打开编译后的资源文件后,查看它的内容,你会发现文件的内容如图所示:
编译完成后的资源文件里保存的是相关图片的十六进制编码数据,还有相关的管理代码。
我们在设计这个UI的时候,是使用matplotlib等绘图库的,为了方便设计,设计一个从QWidget继承的绘图组件类QmyFigureCanvas,在这个类里创建一个FigureCanvas对象、一个Figure对象和一个NavigationToolBar工具栏,构成一个绘图组件。在进行界面设计的时候,我们只要将放置的QWidget组件提升为QmyFigureCanvas类,就可以完成可视化的展示,其完整代码如下所示:
from PyQt5.QtWidgets import QWidget
import matplotlib as mpl
from matplotlib.backends.backend_qt5agg import (FigureCanvas,
NavigationToolbar2QT as NavigationToolbar)
from PyQt5.QtWidgets import QVBoxLayout
import matplotlib.pyplot as plt
class QmyFigureCanvas(QWidget):
def __init__(self, parent=None, toolbarVisible=True,showHint=False):
super().__init__(parent)
self.figure=plt.figure() #公共的figure属性
figCanvas = FigureCanvas(self.figure) #创建FigureCanvas对象,必须传递一个Figure对象
self.naviBar=NavigationToolbar(figCanvas, self) #公共属性naviBar
self.__changeActionLanguage() #改为汉语
actList=self.naviBar.actions() #关联的Action列表
count=len(actList) #Action的个数
self.__lastActtionHint=actList[count-1] #最后一个Action,坐标提示标签
self.__showHint=showHint #是否在工具栏上显示坐标提示
self.__lastActtionHint.setVisible(self.__showHint) #隐藏其原有的坐标提示
self.__showToolbar=toolbarVisible #是否显示工具栏
self.naviBar.setVisible(self.__showToolbar)
layout = QVBoxLayout(self)
layout.addWidget(self.naviBar) #添加工具栏
layout.addWidget(figCanvas) #添加FigureCanvas对象
layout.setContentsMargins(0,0,0,0)
layout.setSpacing(0)
#鼠标滚轮缩放
self.__cid=figCanvas.mpl_connect("scroll_event",self.do_scrollZoom)
##=====公共接口函数
def setToolbarVisible(self,isVisible=True): ##是否显示工具栏
self.__showToolbar=isVisible
self.naviBar.setVisible(isVisible)
def setDataHintVisible(self,isVisible=True): ##是否显示工具栏最后的坐标提示标签
self.__showHint=isVisible
self.__lastActtionHint.setVisible(isVisible)
def redraw(self): ##重绘曲线,快捷调用
self.figure.canvas.draw()
def __changeActionLanguage(self): ##汉化工具栏
actList=self.naviBar.actions() #关联的Action列表
actList[0].setText("复位") #Home
actList[0].setToolTip("复位到原始视图") #Reset original view
actList[1].setText("回退") #Back
actList[1].setToolTip("回退前一视图") #Back to previous view
actList[2].setText("前进") #Forward
actList[2].setToolTip("前进到下一视图") #Forward to next view
actList[4].setText("平动") #Pan
actList[4].setToolTip("左键平移坐标轴,右键缩放坐标轴") #Pan axes with left mouse, zoom with right
actList[5].setText("缩放") #Zoom
actList[5].setToolTip("框选矩形框缩放") #Zoom to rectangle
actList[6].setText("子图") #Subplots
actList[6].setToolTip("设置子图") #Configure subplots
actList[7].setText("定制") #Customize
actList[7].setToolTip("定制图表参数") #Edit axis, curve and image parameters
actList[9].setText("保存") #Save
actList[9].setToolTip("保存图表") #Save the figure
def do_scrollZoom(self,event): #通过鼠标滚轮缩放
ax=event.inaxes # 产生事件axes对象
if ax==None:
return
self.naviBar.push_current() #Push the current view limits and position onto the stack,这样才可以还原
xmin,xmax=ax.get_xbound()
xlen=xmax-xmin
ymin,ymax=ax.get_ybound()
ylen=ymax-ymin
xchg=event.step*xlen/20 #step [scalar],positive = ’up’, negative ='down'
xmin=xmin+xchg
xmax=xmax-xchg
ychg=event.step*ylen/20
ymin=ymin+ychg
ymax=ymax-ychg
ax.set_xbound(xmin,xmax)
ax.set_ybound(ymin,ymax)
event.canvas.draw()
而将QWidget提升为QmyFigureCanvas的方法也很简单,在该项目里,我们进行可视化展示的界面组件为QWidget,将该组件拖拽到需要的位置,将这个组件提升为QmyFigureCanvas类,头文件为myFigureCanvas,提升组件的对话框如下图所示。
该文件也是一个基于QMainWindow的出口类QmyMainWindow,它包含了众多定义的函数,而这些函数就是最终进行可视化的实现。
完成后的可视化工具有五大类多大20+的不同可视化结果,在这里我们使用matplotlib中最常用的plot()函数来举例,它所绘制出的结果为折线图。
首先我们在该类中定义一个基本的绘图功能__drawPlot( ),它将给定的数据绘制在之前提升的QmyFigureCanvas的QWidget组件中。该函数如下所示:
def __drawPlot(self,x=[1,2,3,4,5],y=[2,3,5,6,9],title='Plot',
leg='Line-Plot',xlabel='Xlabel',
ylabel='Ylabel',style='fast',loc='best',
titlefontsize=14,titlecolor='black',
axisfontsize=14,axisfontcolor='black',bgcolor='white',
linestyle='-',linewidth=2,
linecolor='steelblue',alpha=0.8):
self.ui.widgetPlot.figure.clear()
mpl.style.use(style)
mpl.rcParams['font.sans-serif']=['simhei']
mpl.rcParams['font.size']=9 #显示汉字
mpl.rcParams['axes.unicode_minus'] =False #减号unicode编码
ax1=self.ui.widgetPlot.figure.add_subplot(111,facecolor=bgcolor)
ax1.set_title(title,fontsize=titlefontsize,color=titlecolor)
ax1.plot(x,y,label=leg,ls=linestyle,lw=linewidth,c=linecolor,alpha=alpha)
ax1.set_xlabel(xlabel,fontsize=axisfontsize,color=axisfontcolor)
ax1.set_ylabel(ylabel,fontsize=axisfontsize,color=axisfontcolor)
ax1.legend(loc='upper left')
而另一个函数为当点击绘制函数时,该函数将其他组件获取的参数和数据进行重新绘制,在这个过程中会调用上面的__drawPlot()函数。这个函数的命名也有讲究,函数命名格式为“on_XXX_clicked”,其中“XXX”为QPushButton组件的名称。该函数代码如下所示:
@pyqtSlot() #重画折线图表
def on_redraw_plot_clicked(self):
try:
self.ui.statusBar.clearMessage()
xdata=self.ui.x_data.text().split()
ydata=[float(y) for y in self.ui.y_data.text().split()]
xlab=self.ui.editXtitle.text() #获取X轴标题
ylab=self.ui.editYtitle.text() #获取Y轴标题
totaltitle=self.ui.edittitle.text() #获取图表标题
plotstyle=self.ui.comboBox_style.currentText() #获取绘图风格
plotlabel=self.ui.editlegendname.text() #获取图例名称
titlefontsize=self.ui.spinbox_titlefontsize.value() #获取标题字体大小
axisfontsize=self.ui.spinbox_titlefontsize.value() #获取坐标轴字体大小
titlefontcolor=self.ui.comboBox_titlefontcolor.currentText() #获取标题文字颜色
axisfontcolor=self.ui.comboBox_axisfontcolor.currentText() #获取坐标轴文字颜色
plotbgcolor=self.ui.comboBox_plotbgcolor.currentText() #获取图表背景颜色
#获取线条类型
linestyle='-'
or_linestyle=self.ui.comboBox_plotlinetype.currentText()
if or_linestyle=='实线':
linestyle='-'
elif or_linestyle=='破折线':
linestyle='--'
elif or_linestyle=='点划线':
linestyle='-.'
elif or_linestyle=='虚线':
linestyle=':'
else:
linestyle=""
#获取线宽
linewidth=self.ui.doubleSpinBox_plotlw.value()
#获取线条颜色
linecolor=self.ui.comboBox_plotlinecolor.currentText()
#获取透明度
alpha=self.ui.doubleSpinBox_plotalpha.value()
#获取图例位置
loc=self.ui.comboBox_loc.currentText()
self.__drawPlot(x=xdata,y=ydata,xlabel=xlab,ylabel=ylab,title=totaltitle,
style=plotstyle,leg=plotlabel,bgcolor=plotbgcolor,
titlefontsize=titlefontsize,axisfontsize=axisfontsize,
titlecolor=titlefontcolor,axisfontcolor=axisfontcolor,
linestyle=linestyle,linewidth=linewidth,
linecolor=linecolor,alpha=alpha,loc=loc)
self.ui.widgetPlot.redraw()
self.ui.statusBar.showMessage('折线图绘制成功!')
except:
self.ui.statusBar.clearMessage()
self.ui.statusBar.showMessage('绘制失败!请检查是否操作正确!')
其他可视化结果的函数同理。
该函数为项目的GUI程序入口,运行此Python文件便可以生成可视化窗口。具体代码如下所示:
# -*- coding:GBK -*-
## GUI应用程序主程序入口
import sys
from PyQt5.QtWidgets import QApplication
from myMainWindow import QmyMainWindow
app = QApplication(sys.argv) #创建GUI应用程序
##icon = QIcon(":/icons/images/app.ico")
##app.setWindowIcon(icon)
mainform=QmyMainWindow() #创建主窗体
mainform.show() #显示主窗体
sys.exit(app.exec_())
Python程序打包我们使用最常用的pyinstaller即可,在Windows里使用Win+R进入到控制台,使用cd进入到DataVisualizationTool.py文件所在的目录,然后使用如下命令即可:
pyinstaller DataVisualizationTool.py --noconsole --icon="logo.ico"
其中“–noconsole”表示项目打开的时候不会出现控制台,而–icon=“logo.ico”标识给打包生成的软件添加的Logo,并且注意这里的图片文件必须是ico格式,不能是png等图片文件。
另外一点,在项目主程序里涉及到文件的读写,为了程序的正常运行,记得把所用到的文件复制到打包的文件中。
该项目的UI界面结构很简单,左侧是操作区,右侧是显示区,下方还有一个状态栏用来显示绘图是否成功。
左侧的状态栏里的功能很明显,在数据栏中输入数据,然后在下方调整相关属性,最后点击绘图按钮,便可以在右侧的显示区展示可视化结果了。
值得一提的是,输入的数据必须以空格分隔,个别的数据是二维数据,数据间以逗号(英文输入法)分隔,数组间以空格分隔,比如热力图。
百度网盘链接: DataVisualizationTool.
提取码:kymd
在做这个项目的过程中,其实还使用了pyecharts进行绘图,当然你也可以将Python的其他绘图库嵌入其中,实现起来也并不难。
《Python Qt GUI与数据可视化编程》这本书对我有很大的帮助,对于想学习Python+Qt的爱好者来说是很有价值的,推荐一看。