以下内容为自己的学习笔记,如需求转载,请声明原文链接 微信公众号「englyf」mp.weixin.qq.com/s/3Yb_YAKiM…


本文大概 3617 个字,阅读需花 10 分钟
内容不多,但也花了一些精力
如要沟通,欢迎评论区留言
谢谢你的点赞收藏分享

假如你接触过桌面 GUI 软件开发,那么你一定会对 MFC、WPF、Qt 等有或多或少的了解。

那么什么是 GUI 软件呢?GUI 软件是带有用户交互界面的软件,有按钮,有窗口,还有许多其它用于和用户交互的小部件。常见的例子是,比方各个厂家推出的浏览器,上面有标签,有按钮,有网址输入栏,有网页内容展现窗口和状态栏等等。

不过,这儿计划为大家介绍一下运用 Python 怎么去做 GUI 开发,因为会 Python 的人更多,相信其中也有许多人对开发界面软件颇有兴趣。好,看下文。

Python 的 GUI 开发结构有好几种,比较主流的有 wxPython、PyQt、Tkinter,这三种都是跨渠道方案。

wxPython 是 Python 的第三方库,代码完成根据 C++ 的 wxWidgets 库封装,出现的界面风格和体系本地风格共同。其答应协议规则假如直接引证 wxPython 的二进制库文件,则能够随意运用。

能够看看在 linux 体系下根据 wxPython 的界面程序是什么姿态

Python:界面开发,wx入门篇

PyQt 是 Qt 渠道的 Python 版本,自绘的界面风格,答应协议对商业运用不太友爱。尽管和原生风格已经很接近了,但还是有人能挑出刺来。

能够看看在 linux 体系下根据 PyQt 的界面程序是什么姿态

Python:界面开发,wx入门篇

Tkinter 是 Python 自带的 GUI 开发结构,也是本地化风格。

看看在 linux 体系下根据 Tkinter 的界面,风格真的有些过时了

Python:界面开发,wx入门篇

值得一提的是,wxPython 也是 Python 作者主推的 GUI 开发结构。

今日先讲 wxPython,至于其它方案,会在后边的其它推文解说,敬请关注。

环境装备

因为 VSCODE 的开放性和插件生态极其丰厚的原因,引荐根据 VSCODE 来建立开发环境。

本文以下内容根据 windows 10 和 Python3.

开发 Python 工程之前,先装备一个虚拟环境。

在 VSCODE 里翻开选好的工程存放目录,然后点击 VSCODE 顶部菜单栏 Terminal -> New Terminal,弹出命令行终端,输入

python -m venv .venv

发动虚拟环境

.venv\Scripts\activate.bat

装置 wxPython

先查看一下当时环境里已经预装了哪些东西包

pip list

Output:

Package    Version
---------- -------
pip        21.1.1
setuptools 56.0.0
WARNING: You are using pip version 21.1.1; however, version 22.3.1 is available.
You should consider upgrading via the '.\.venv\scripts\python.exe -m pip install --upgrade pip' command.

主张晋级一下 pip

python -m pip install --upgrade pip

Output:

Requirement already satisfied: pip in .\.venv\lib\site-packages (21.1.1)
Collecting pip
  Using cached pip-22.3.1-py3-none-any.whl (2.1 MB)
Installing collected packages: pip
  Attempting uninstall: pip
    Found existing installation: pip 21.1.1
    Uninstalling pip-21.1.1:
      Successfully uninstalled pip-21.1.1
Successfully installed pip-22.3.1

装置 wxPython 包

pip install wxpython

Output:

Collecting wxpython
  Using cached wxPython-4.2.0-cp38-cp38-win_amd64.whl (18.0 MB)
Collecting pillow
  Using cached Pillow-9.3.0-cp38-cp38-win_amd64.whl (2.5 MB)
Collecting numpy
  Using cached numpy-1.23.5-cp38-cp38-win_amd64.whl (14.7 MB)
Collecting six
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: six, pillow, numpy, wxpython
Successfully installed numpy-1.23.5 pillow-9.3.0 six-1.16.0 wxpython-4.2.0

再查看一下实践都装置了哪些东西包

Package    Version
---------- -------
numpy      1.23.5
Pillow     9.3.0
pip        22.3.1
setuptools 56.0.0
six        1.16.0
wxPython   4.2.0

看到,wxpython 其实还依靠了 numpy、Pillow、six 这几个包。

根本程序

先来看一看一个根本的 wxPython GUI 程序骨架,新建文件 main.py,输入以下内容并保存。

// main.py

import wx
app = wx.App()
window = wx.Frame(parent=None, title="hello Python GUI APP!")
window.Show()
app.MainLoop()

导入 wx 库,也便是 wxPython 库,首要实例化类 wx.App

wx.App 类代表着整个运用,被用于引导 wxPython 体系,初始化底层的 gui 东西包,设置或者获取运用级别的特点,完成本机窗口体系的主音讯或者事情环,以及分配事情到各个窗口实例等。每个 wx 运用都必须有且仅有一个 wx.App 类实例,并且为了保证 gui 渠道和小部件都被初始化完成,一切 UI 方针的创立必须在 wx.App 类实例创立之后。为了完成更杂乱的初始化进程,能够对 wx.App 类履行派生,然后重写办法 OnInit,窗口初始化完成时会调用办法 OnInit

然后,创立 wx.Frame 类实例,初始化时,设置父窗口为空和设置标题为 hello Python GUI APP!

wx.Frame 是用户能够改动巨细和方位的窗口类,调用 Show() 显现窗口。

wxPython 供给了十分丰厚的窗口部件(widget)和辅佐控件来简化杂乱 GUI 的开发进程。根本的 widget 比方有输入框 TextCtrl,按键 Button,静态文本 StaticText,菜单栏 MenuBar,列表 ListCtrl等。简略的辅佐控件比方有布局器 BoxSizer,菜单 Menu等。为了显现丰厚的内容,除了能够直接运用结构供给的窗口部件,还能够对这些部件派生以增加更多功用。

最终,调用类 wx.App 方针的 MainLoop() 办法来发动主界面的事情环,这时候用户和界面交互才会有反应。

输入指令以履行程序

python main.py

Python:界面开发,wx入门篇

通过显现的程序窗口,可看到整个程序只做了很根本的 UI 窗口显现,可是代码结构也相对简略。假如需求完成更杂乱的窗口界面呢?往下看。

运用 wxFormBuilder 规划杂乱 UI

从上一节的 demo 代码中,看到要完成显现一个窗口是很简略的,可是假如窗口内部包含了许多其它部件呢?

持续手堆代码吗?不是不能够,可是这姿态的做法对工程或者项目后期保护是很晦气的。

那么怎么办?很巧,wxWidgets 结构供给了一个 GUI 构建器 wxFormBuilder。

Python:界面开发,wx入门篇

翻开 wxFormBuilder,能够看到供给了十分多的东西,并且主动创立一个空白工程。为了规划需求的界面,开发者能够通过手动点击组件面板(Component Palette)中不同种类的各种控件来布局界面,同时在修改器(Editor)中生成规划图和各种开发言语的代码,支撑 C++, Python, XRC, Lua 和 PHP 等。规划完成后,开发者只需求把对应页面的方针言语代码拷贝到自己的工程源文件中即可直接运用。

如需求装置 wxFormBuilder,主张前往官方下载页面获取对应渠道装置包

https://github.com/wxFormBuilder/wxFormBuilder/releases

下面就运用 wxFormBuilder 来规划一个简略的界面。

一般界面都以 Frame 为底,所以在空白工程基础上增加一个 Frame 窗口。点击工作空间顶部的组件面板(Component Palette) -> Forms 类型 -> Frame 控件,如图

Python:界面开发,wx入门篇

先在左面的控件树(Object Tree)面板里点击刚增加的 Frame 控件,然后在右边的方针特点(Object Properties)面板中就能够修正这个控件的特点了。这儿修正控件的特点 name 为 w_frame_xrc,title 为 hello Python GUI APP!。最终输出代码会以一个窗口类的方式输出,而最底层窗口的 name 特点会决议这个窗口类的类名。

Python:界面开发,wx入门篇

计划规划一个简略的名单录,为演示简略起见,只增加人员名称,而不修改或者删去。依照元素控件的层次逐一增加,规划图最终效果图如下

Python:界面开发,wx入门篇

如需求获取本工程一切源文件,包含规划文件等,可查看文末的链接。

规划界面完成后,点击修改器(Editor)中的 Python 标签,仿制窗口内一切内容,粘贴保存到新建的源文件 w_frame_xrc.py 中。

// w_frame_xrc.py

# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilder (version Oct 26 2018)
## http://www.wxformbuilder.org/
##
## PLEASE DO *NOT* EDIT THIS FILE!
###########################################################################
import wx
import wx.xrc
###########################################################################
## Class w_frame_xrc
###########################################################################
class w_frame_xrc ( wx.Frame ):
	def __init__( self, parent ):
		wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = u"hello Python GUI APP!", pos = wx.DefaultPosition, size = wx.Size( 500,300 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )
		self.SetSizeHints( wx.DefaultSize, wx.DefaultSize )
		bSizer1 = wx.BoxSizer( wx.VERTICAL )
		bSizer2 = wx.BoxSizer( wx.VERTICAL )
		sbSizer1 = wx.StaticBoxSizer( wx.StaticBox( self, wx.ID_ANY, u"输入信息" ), wx.VERTICAL )
		bSizer3 = wx.BoxSizer( wx.HORIZONTAL )
		self.m_staticText_name = wx.StaticText( sbSizer1.GetStaticBox(), wx.ID_ANY, u"姓名:", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.m_staticText_name.Wrap( -1 )
		bSizer3.Add( self.m_staticText_name, 0, wx.ALL, 5 )
		self.m_textCtrl_name = wx.TextCtrl( sbSizer1.GetStaticBox(), wx.ID_ANY, wx.EmptyString, wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer3.Add( self.m_textCtrl_name, 1, wx.ALL, 5 )
		sbSizer1.Add( bSizer3, 1, wx.EXPAND, 5 )
		bSizer2.Add( sbSizer1, 1, wx.EXPAND, 5 )
		bSizer4 = wx.BoxSizer( wx.VERTICAL )
		bSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
		self.m_button_add = wx.Button( self, wx.ID_ANY, u"增加", wx.DefaultPosition, wx.DefaultSize, 0 )
		bSizer4.Add( self.m_button_add, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 5 )
		bSizer4.Add( ( 0, 0), 1, wx.EXPAND, 5 )
		bSizer2.Add( bSizer4, 1, wx.EXPAND, 5 )
		bSizer1.Add( bSizer2, 0, wx.EXPAND, 5 )
		self.m_staticText2 = wx.StaticText( self, wx.ID_ANY, u"列表:", wx.DefaultPosition, wx.DefaultSize, 0 )
		self.m_staticText2.Wrap( -1 )
		bSizer1.Add( self.m_staticText2, 0, wx.ALL, 5 )
		bSizer5 = wx.BoxSizer( wx.VERTICAL )
		self.m_listCtrl_info = wx.ListCtrl( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, wx.LC_REPORT )
		bSizer5.Add( self.m_listCtrl_info, 1, wx.ALL|wx.EXPAND, 5 )
		bSizer1.Add( bSizer5, 1, wx.EXPAND, 5 )
		self.SetSizer( bSizer1 )
		self.Layout()
		self.Centre( wx.BOTH )
	def __del__( self ):
		pass

为了运用 wxFormBuilder 构建器生成的代码,能够简略修正前面的代码,如下

// main.py

import wx
import w_frame_xrc
app = wx.App()
window = w_frame_xrc.w_frame_xrc(parent=None)
window.Show()
app.MainLoop()

履行程序

python main.py

Python:界面开发,wx入门篇

现在界面看起来有点内容了!

完成逻辑

前面的界面还不具有任何的实践功用,为了让其履行规划的功用,增加额外的逻辑在所难免。

比方,点击按钮 增加,就触发动作把输入框中的姓名增加到下方的列表中,并清空输入框,因而需求在本来的窗口类 w_frame_xrc.w_frame_xrc 基础上增加一些逻辑功用代码。

不过,wxFormBuilder 构建出来的代码一般不主张直接修正,所以先对本来的窗口类 w_frame_xrc.w_frame_xrc 进行派生,再在派生类中补充逻辑功用代码。派生类的代码存在独自的源文件 w_frame.py 中。

// w_frame.py

import wx
import w_frame_xrc
class w_frame(w_frame_xrc.w_frame_xrc):
    def __init__(self, parent):
        super(w_frame, self).__init__(parent)
        self.m_listCtrl_info.ClearAll()
        self.m_listCtrl_info.InsertColumn(0, u'姓名', width=140)
        self.m_button_add.Bind(wx.EVT_BUTTON, self.on_button_add)
    def on_button_add(self, event):
        value = self.m_textCtrl_name.GetValue()
        if not value:
            print("You didn't enter anything!")
        else:
            self.m_listCtrl_info.InsertItem(self.m_listCtrl_info.GetItemCount(), value)
            self.m_textCtrl_name.Clear()

能够看到,当控件有特定的事情需求绑定衔接到处理句柄时,能够通过 Bind() 办法,传入 EVT_xxx 事情类型和处理句柄(可调用方针,比方,函数等)。假如需求将已绑定的某个事情断开衔接,能够将处理句柄方位参数设为 None 即可。

然后,main.py 也需求稍作修正,如下

// main.py

import wx
import w_frame
app = wx.App()
window = w_frame.w_frame(parent=None)
window.Show()
app.MainLoop()

好了,现在再来测验一下刚增加的逻辑,程序发动后往里增加几个名单看看吧。

python main.py

Python:界面开发,wx入门篇

布置发布

目前来看,工程里都是一些以源码文件方式存在的脚本,可是在最终用户运用时,都是习惯于直接双击一个 exe 文件来发动软件进程。

下面就介绍一种对 Python 脚本工程打包的东西,方针是最终输出一个可履行的 exe 文件。

这个东西便是 pyinstaller,运用之前需求承认一下自己的环境里是否已经装置有这个第三方包,还用指令 pip list 即可查看。

假如承认过没有,那么用下面的指令能够装置

pip install pyinstaller

假定已经装置完毕,直接打包。选项 -F 后边输入发动脚本文件

pyinstaller -F main.py

发动打包进程之后,工程目录下面会主动生成一个新目录 dist 用于存放输出的方针文件。因为上面的打包指令没有指明输出的方针文件名,所以默认输出为脚本文件同名,如 main.exe。

假如需求指明输出的方针文件名,能够加上选项 -n。比方要输出方针为 demo.exe,能够这样

pyinstaller -F main.py -n demo

也许有的同学喜爱让打包的输出文件带上图标,那么能够加上选项 -i。比方工程目录里有一份图标文件 logo.ico,需求让打包后输出文件带上这个图标,能够这样

pyinstaller -F main.py -n demo -i logo.ico

打包完毕,双击程序 demo.exe,可能会发现在运行起来的软件布景里,老是有个命令行的窗口,这姿态真的很碍眼!

怎样把终端窗口给躲藏掉呢?打包的时候带上选项 -w,这样

pyinstaller -F main.py -n demo -i logo.ico -w

网上有些同学喜爱吐槽 pyinstaller 打包出来的方针文件体积过大,关于这个问题的处理思路是,工程开发(包含方针文件打包输出)应该在装备好的独自虚拟环境下进行,环境中不应该装置任何不需求的第三方包!

全文到这儿算是完毕了,欢迎你的留言!

​工程代码库房:​git@github.com:ifi-leung/python_gui_wx.git