Python:界面開發,wx入門篇

来源:https://www.cnblogs.com/englyf/archive/2022/12/15/16984135.html
-Advertisement-
Play Games

聽說過使用python在網站爬蟲,或者數據清洗,或者人工智慧原型驗證,但是用在GUI開發上倒是頭一回。今兒就來瞧瞧怎麼個玩法! ...


以下內容為本人的學習筆記,如需要轉載,請聲明原文鏈接 微信公眾號「englyf」https://mp.weixin.qq.com/s/3Yb_YAKiMte_f5HanetXiA


本文大概 3617 個字,閱讀需花 10 分鐘
內容不多,但也花了一些精力
如要交流,歡迎評論區留言
謝謝你的點贊收藏分享

如果你接觸過桌面 GUI 軟體開發,那麼你一定會對 MFC、WPF、Qt 等有或多或少的瞭解。

那麼什麼是 GUI 軟體呢?GUI 軟體是帶有用戶交互界面的軟體,有按鈕,有視窗,還有很多其它用於和用戶交互的小部件。常見的例子是,比如各個廠家推出的瀏覽器,上面有標簽,有按鈕,有網址輸入欄,有網頁內容展示視窗和狀態欄等等。

不過,這裡打算為大家介紹一下使用 Python 怎麼去做 GUI 開發,因為會 Python 的人更多,相信其中也有很多人對開發界面軟體頗有興趣。好,看下文。

Python 的 GUI 開發框架有好幾種,比較主流的有 wxPython、PyQt、Tkinter,這三種都是跨平臺方案。

wxPython 是 Python 的第三方庫,代碼實現基於 C++ 的 wxWidgets 庫封裝,呈現的界面風格和系統本地風格一致。其許可協議規定如果直接引用 wxPython 的二進位庫文件,則可以隨便使用。

可以看看在 linux 系統下基於 wxPython 的界面程式是什麼樣子

wx.png

PyQt 是 Qt 平臺的 Python 版本,自繪的界面風格,許可協議對商業應用不太友好。雖然和原生風格已經很接近了,但還是有人能挑出刺來。

可以看看在 linux 系統下基於 PyQt 的界面程式是什麼樣子

pyqt.png

Tkinter 是 Python 自帶的 GUI 開發框架,但也是自繪的界面風格。

可以看看在 linux 系統下基於 Tkinter 的界面程式是什麼樣子

tk.png

值得一提的是,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

1.JPG

通過顯示的程式視窗,可看到整個程式只做了很基本的 UI 視窗顯示,但是代碼結構也相對簡單。如果需要實現更複雜的視窗界面呢?往下看。

使用 wxFormBuilder 設計複雜 UI

從上一節的 demo 代碼中,看到要實現顯示一個視窗是很簡單的,但是如果視窗內部包含了很多其它部件呢?

繼續手堆代碼嗎?不是不可以,但是這樣子的做法對工程或者項目後期維護是很不利的。

那麼怎麼辦?很巧,wxWidgets 框架提供了一個 GUI 構建器 wxFormBuilder。

2.JPG

打開 wxFormBuilder,可以看到提供了非常多的工具,而且自動創建一個空白工程。為了設計需要的界面,開發者可以通過手動點擊組件面板(Component Palette)中不同種類的各種控制項來佈局界面,同時在編輯器(Editor)中生成設計圖和各種開發語言的代碼,支持 C++, Python, XRC, Lua 和 PHP 等。設計完成後,開發者只需要把對應頁面的目標語言代碼拷貝到自己的工程源文件中即可直接使用。

如需要安裝 wxFormBuilder,建議前往官方下載頁面獲取對應平臺安裝包

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

下麵就使用 wxFormBuilder 來設計一個簡單的界面。

一般界面都以 Frame 為底,所以在空白工程基礎上添加一個 Frame 視窗。點擊工作空間頂部的組件面板(Component Palette) -> Forms 類型 -> Frame 控制項,如圖

4.jpg

先在左邊的控制項樹(Object Tree)面板里點擊剛添加的 Frame 控制項,然後在右邊的對象屬性(Object Properties)面板中就可以修改這個控制項的屬性了。這裡修改控制項的屬性 name 為 w_frame_xrc,title 為 hello Python GUI APP!。最終輸出代碼會以一個視窗類的形式輸出,而最底層視窗的 name 屬性會決定這個視窗類的類名。

5.JPG

打算設計一個簡單的名單錄,為演示簡單起見,只添加人員名稱,而不編輯或者刪除。按照元素控制項的層次逐個添加,設計圖最終效果圖如下

6.JPG

如需要獲取本工程所有源文件,包括設計文件等,可查看文末的鏈接。

設計界面完成後,點擊編輯器(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

9.JPG

現在界面看起來有點內容了!

實現邏輯

前面的界面還不具備任何的實際功能,為了讓其執行設計的功能,添加額外的邏輯在所難免。

比如,點擊按鈕 添加,就觸發動作把輸入框中的名字添加到下方的列表中,並清空輸入框,因此需要在原來的視窗類 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

10.JPG

部署發佈

目前來看,工程里都是一些以源碼文件形式存在的腳本,但是在最終用戶使用時,都是習慣於直接雙擊一個 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 打包出來的目標文件體積過大,關於這個問題的解決思路是,工程開發(包括目標文件打包輸出)應該在配置好的單獨虛擬環境下進行,環境中不應該安裝任何不需要的第三方包!

全文到這裡算是結束了,歡迎你的留言!

​工程代碼倉庫:​[email protected]:ifi-leung/python_gui_wx.git


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 華為應用市場在2022年HDC大會期間發佈了一款3D水流主題,基於華為HMS Core Scene Kit服務能力,展現立體靈動的水流島嶼,可跟隨用戶指尖實現實時流體波動效果,既趣味又解壓。 讓變幻莫測的物質來實現我們在影視和游戲等多種應用場景中的奇思妙想,從早期步驟繁重的特效製作演變到如今,已經有 ...
  • 本文是 CSS Houdini 之 CSS Painting API 系列第三篇。 現代 CSS 之高階圖片漸隱消失術 現代 CSS 高階技巧,像 Canvas 一樣自由繪圖構建樣式! 在上兩篇中,我們詳細介紹了 CSS Painting API 是如何一步一步,實現自定義圖案甚至實現動畫效果的! ...
  • 好家伙, 在上一篇中,我們知道了, JS的數組中每個槽位可以存儲任意類型的數據 那麼,我們能通過數組去模仿某些數據結構嗎? 答案是肯定的 1.棧方法 ECMAScript 給數組提供幾個方法,讓它看起來像是另外一種數據結構。 數組對象可以像棧一樣,也就是一種限制插人和刪除項的數據結構。 棧是一種後進 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 最近APP項目開發完成,在評審會上老闆提了一個需求,想在開發的APP上添加一個鏈接,可以跳轉公司的小程式商城。 原以為會很複雜,結果只有短短的幾行代碼。 plus.share.getServices(function(res){ var ...
  • 🏆一、HTML是什麼又不是什麼? 👤1.1、HTML是什麼 超文本標記語言(Hypertext Markup Language, HTML)是一種用於創建網頁的標記語言。 本質上是瀏覽器可識別的規則,我們按照規則寫網頁,瀏覽器根據規則渲染我們的網頁。對於不同的瀏覽器,對同一個標簽可能會有不同的解 ...
  • 前端界有兩個“教派”,一個叫 Vue,一個叫 React。Vue 的成員看不起 React,React 成員鄙視 Vue,他們認為手中的“教義”就是真理,可以消滅世界一切苦難。 但正如沒有絕對的真理,也沒有絕對完美的系統框架,我們需要一雙明辨是非的眼睛去解析所面對的難題,帶我們找到正確的方法,解決所... ...
  • 摘要:多線程訪問了共用的數據,會產生線程安全問題。 本文分享自華為雲社區《多線程安全問題原理和解決辦法Synchronized和ReentrantLock使用與區別》,作者:共飲一杯無。 線程安全問題概述 賣票問題分析 單視窗賣票 一個視窗(單線程)賣100張票沒有問題單線程程式是不會出現線程安全問 ...
  • Spring Boot 應用程式在服務註冊與發現方面提供和 Nacos 的無縫集成。 通過一些簡單的註解,您可以快速來註冊一個服務,並使用經過雙十一考驗的 Nacos 組件來作為大規模分散式系統的服務註冊中心。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...