Python编写GUI程序
一、关于GUI程序:
图形用户界面(Graphical User Interface,简称 GUI,又称图形用户接口)是指采用图形方式显示的计算机操作用户界面。
GUI程序的存在可以让我们忘记繁琐的代码,使用直观的图形方式解决问题,展示结果,降低了程序的使用成本。
对于我们的常用的Windows操作系统下,编写GUI桌面程序方式很多,包括Java的Swing包、 winform 、WPF(使用C#)、QT框架(使用C++)等等,甚至可以使用web方式编写GUI桌面程序如electron(JS等语言)。
二、Python下的GUI编程实现:
我们可以用Python完成各种各样的数据处理、机器学习等工作,此外当然也可以用Python完成桌面程序的开发。
Python常见的GUI库 :
1、tkInter :
python官方标准库,支持多平台,IDLE就是使用它编写的!虽然是官方推荐(内置了,直接import就可以使用),但是它的界面比较简单基本,组件不够丰富,这里就不作展开了。
写个Hello World看一看:
#导入tkinter模块
import tkinter
#创建主窗口
win = tkinter.Tk()
win.title("Hello World")
#创建标签
tkinter.Label(win, text="Hello World").pack()
#启动主循环
win.mainloop()
2、wxPython :
wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。支持win,unix,linux等操作系统。
关于wxWidgets大家只需要知道这是一个跨平台的GUI工具库,和Qt有点类似,是C++实现的。wxPython是对它的python绑定,这使得我们可以使用Python的语法编写GUI程序而不用使用C++进行实现。
考虑到使用群体较少,技术文档相对缺少,这里就不对其使用展开讲解,仅做简单示范使用。
安装:
pip install wxpyhton
编写一个Hello World窗口示例:
# 导入wxpython库
import wx
# 新建一个app
app = wx.App()
# 创建一个窗口
window = wx.Frame(None, title="wxPython 你好!", size=(400, 300))
panel = wx.Panel(window)
# 添加一个静态文本,显示Hello World欢迎字样
label = wx.StaticText(panel, label="Hello World", pos=(100, 100))
# 显示窗口
window.Show(True)
# 进入程序主循环(app开始运行)
app.MainLoop()
运行结果:
3、PyQt5 :
Qt 是一个1991年由Qt Company开发的跨平台C++图形用户界面应用程序开发框架。它既可以开发GUI程序,也可用于开发非GUI程序,比如控制台工具和服务器。
PyQt则是Python编程语言和Qt库的成功融合,是Qt的python语言绑定,使得我们可以利用python语言完成Qt程序的开发。这里的PyQt5中的5是指的对于Qt5的实现,可以简单的理解为更新的版本(PyQt4与PyQt5存在一些用法差异)。
相对来说,由于商业化的程度较高,PyQt5的技术文档更加全面,可以直接参考Qt的官方文档学习使用,另外,Qt还提供了Qt Designer等开发工具,帮助我们通过图形化的方式创建界面。
考虑PyQt5丰富的组件与学习资源,这里推荐大家可以尝试学习使用PyQt5(或者PySide2,这是Qt官方的Python实现)。
安装:
pip install pyqt5
编写一个Hello World窗口示例:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
# 创建一个app主体
app = QApplication(sys.argv)
# 创建一个主窗口
win = QMainWindow()
# 设置窗口的标题栏
win.setWindowTitle('Hello World')
# 向窗体中加入一个Label标签
label = QLabel(win)
# 设置标签的显示内容
label.setText('Hello World')
# 显示程序窗口
win.show()
# 启动主循环,开始程序的运行
sys.exit(app.exec_())
运行结果:
三、PyQt5的编程实践:
在上面内容里面,我们可以看到如何利用Python的三种主流GUI库编写简单的Hello World程序。接下来,我们将专注于PyQt5来进行进一步实践:编写一个展示正余弦函数的交互式波形展示程序。
我们将学习到:
- 使用Qt Designer编写图形界面
- 了解到PyQt5提供的基本图形组件
- 使用pyqtgraph实现数据可视化
1、使用Qt Designer快速构建图形界面:
Qt Designer是Qt提供的一个图形界面编辑工具,可以让我们利用拖拽组件的方式创建程序界面,直观且易于上手。
这个程序在我们通过pip安装pyqt5这个第三方库时就已经下载在了库安装目录下,比如:
C:\Users\zhangs\Anaconda3\pkgs\qt-5.9.7-vc14h73c81de_0\Library\bin\designer.exe
(1) 打开程序,新建一个窗体:
(2) 拖拽组件,布局程序界面:
此时的布局比较随意,不太美观,我们可以调整界面布局,使用右键,点击对象查看器中centralwidget或者右键点击界面空白处,选择 “布局->栅格布局”。
另外此时我们的用于绘图的graphicsView其实并不能完成数据可视化工作,我们需要借助于另外一个数据可视化工具pyqtgraph(可以当作另一个版本的matplotlib),当然这里也少不了pip安装:
pip install pyqtgraph
安装成功后,我们需要将绘图的graphicsView变成一个pyqtgraph内的绘图组件 PlotWidget
,用专业术语表示就是**“提升”**,我们只需要在graphicsView组件上右键,选择“提升为…”就会弹出如下对话框:
按照上图设置完成后,点击添加,提升就完成了我们的界面布局了。
对于后续编写代码的方便,我们可以对上面使用到的四个组件分别命名如下:
最后,保存文件,这里我保存在工作目录下的qt_UI.ui文件里。
2、读取转换图形界面为py文件:
这里我们借助于pyqt5提供的uic.exe程序(C:\Users\zhangs\Anaconda3\Scripts\pyuic5.exe),将qt_UI.ui文件转换为.py文件,工作目录下打开CMD终端中输入如下命令:
pyuic5 -d -o ./"qt_UI.py" ./"qt_UI.ui"
(注意:上面的操作过程实际上可以借助第三方编辑器如VsCode或者PyCharm配置相应插件工具简化操作,感兴趣可以百度学习)。
这样我们得到了图形化的描述文件如下:
# qt_UI.py文件内容
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.plotView = PlotWidget(self.centralwidget)
self.plotView.setObjectName("plotView")
self.gridLayout.addWidget(self.plotView, 0, 0, 1, 1)
self.hSlider = QtWidgets.QSlider(self.centralwidget)
self.hSlider.setOrientation(QtCore.Qt.Horizontal)
self.hSlider.setObjectName("hSlider")
self.gridLayout.addWidget(self.hSlider, 1, 0, 1, 1)
self.changeBt = QtWidgets.QPushButton(self.centralwidget)
self.changeBt.setObjectName("changeBt")
self.gridLayout.addWidget(self.changeBt, 0, 2, 1, 1)
self.vSlider = QtWidgets.QSlider(self.centralwidget)
self.vSlider.setOrientation(QtCore.Qt.Vertical)
self.vSlider.setObjectName("vSlider")
self.gridLayout.addWidget(self.vSlider, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 18))
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.changeBt.setText(_translate("MainWindow", "切换波形"))
from pyqtgraph import PlotWidget
3、编写主逻辑main.py文件内容:
在之前的Hello World程序基础上,我们做如下改变:
导入编写好的界面代码模块qt_UI.py:
from myui.qt_UI import Ui_MainWindow
将win = QMainWindow()编程了win = MainWin():
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from myui.qt_UI import Ui_MainWindow
class MainWin(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
if __name__ == "__main__":
# 创建一个app主体
app = QApplication(sys.argv)
# 创建一个主窗口
win = MainWin()
# 显示程序窗口
win.show()
# 启动主循环,开始程序的运行
sys.exit(app.exec_())
这个时候我们已经可以运行程序,只是按钮点击等没有任何反应,那是因为我们还没有编写任何相应的逻辑响应代码!
编写之前,我们需要知道一个基本的Qt概念:信号(signal)与槽(slot)
简单的理解:当我们点击按钮“切换波形”时,系统会发出一个“clicked”的信息(signal),这个信息需要相应处理函数与之“绑定”,这个事件处理函数我们称之为槽(slot),如果我们没有实现绑定相应的槽函数或者槽函数实习为空,表现出来的结果就是什么也没有发生!如同上面我们的程序那样仅仅是一个空壳。
接下来添加全部组件的槽函数,完整代码如下:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel
from myui.qt_UI import Ui_MainWindow
import numpy as np
class MainWin(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.setConnect()
self.type = 0
self.amp = 1
self.freq = 1
self.plot_lh = None
self.plot_curve()
def setConnect(self):
'''绑定槽函数'''
self.changeBt.clicked.connect(self.change_wave)
self.hSlider.sliderMoved.connect(self.change_freq)
self.vSlider.sliderMoved.connect(self.change_amp)
def change_wave(self):
''' 波形切换按钮点击响应槽函数'''
self.type = not self.type
self.plot_curve()
def change_freq(self,pos):
'''水平滑条拉动,改变波形周期的槽函数'''
self.freq = pos
self.plot_curve()
def change_amp(self,pos):
'''垂直滑条拉动,改变波形幅度的槽函数'''
self.amp = pos
self.plot_curve()
def plot_curve(self):
'''
@功能: 绘制正余弦曲线
'''
if self.plot_lh is None:
self.plot_lh = self.plotView.plot()
xdata = np.linspace(1,10,1000)
if self.type == 0:
ydata = self.amp*np.sin(xdata*self.freq)
else:
ydata = self.amp*np.cos(xdata*self.freq)
self.plot_lh.setData(y=ydata,x=xdata)
if __name__ == "__main__":
# 创建一个app主体
app = QApplication(sys.argv)
# 创建一个主窗口
win = MainWin()
# 显示程序窗口
win.show()
# 启动主循环,开始程序的运行
sys.exit(app.exec_())
运行结果如图:
四、补充资料:
[1] 关于pyqt5大家可以去Qt官网
学习,官方推出的pyside2与pyqt5实际操作几乎一致。
[2] 对于绘图的模块大家有兴趣也可以点击:pyqtgraph
[3] 程序的打包:github上有许多优秀的开源项目,比如auto-py-to-exe可以实现图形化打包exe发布程序,当然也有pyinstaller、fbs等方式打包。