☰
python实战项目:界面开发
2026/11/3 19:33:00 网站建设 项目流程

界面开发

  • wxPython桌面GUI实战两篇|抽奖器 + 简易计算器,新手友好的桌面小工具合集
    • 一、升级版抽奖器:修复频闪Bug,自带中奖弹窗
      • 源码
      • 分段解答
        • 1. 模块导入与窗口类定义
        • 2. __init__ 初始化窗口与控件
        • 3. 开始抽奖回调 onclick 与定时器逻辑
        • 4. 名字刷新函数 update_name
        • 5. 结束抽奖回调 stop
        • 6. 程序入口与GUI主循环
        • 7. 本案例注意事项
    • 二、简易计算器:Sizer网格自适应布局实战
      • 源码
      • 分段解答
        • 1. 模块导入与计算器窗口类定义
        • 2. 初始化布局容器与输入框
        • 3. GridSizer网格布局、批量生成按钮
        • 4. 统一回调函数 on_btn_click
        • 5. try-except异常捕获与eval计算
        • 6. 程序入口和主循环
        • 7. 本案例注意事项
    • 三、打包为独立exe程序
      • 源码(打包命令)
      • 分段解答
        • 1. 命令参数说明
        • 2. 注意事项
    • 四、总结

wxPython桌面GUI实战两篇|抽奖器 + 简易计算器,新手友好的桌面小工具合集

哈喽各位小伙伴!今天我们一起来上手wxPython,亲手打造两个实用的桌面小程序。一个是带滚动效果的抽奖器,一个是经典的四则运算计算器。

两个案例各有侧重,覆盖了GUI开发里非常核心的知识点:组件摆放、事件绑定、定时器动画、Sizer自适应布局。不需要前端知识,纯Python代码就能生成可以直接在电脑上运行的窗口程序,非常适合GUI入门练习。

wxPython 是 Python 生态中老牌的桌面GUI库,上手简单,适合快速开发自用小工具和功能原型。

运行前先安装依赖:

pipinstallwxPython

一、升级版抽奖器:修复频闪Bug,自带中奖弹窗

源码

# 导入随机模块,用来随机抽取名单中的名字importrandom# 导入wxPython核心库,所有GUI组件都来自wximportwx# 自定义窗口类,继承wx.Frame(Frame代表一个独立窗口)classMyFrame(wx.Frame):# 抽奖名单,在这里修改参与抽奖的人员名称NameList=['mia','tom','jack']def__init__(self):# 调用父类Frame的构造方法# None:没有父窗口;title:窗口标题;size:窗口宽高 800*600wx.Frame.__init__(self,None,title='抽奖器',size=(800,600))# 创建Panel面板,Panel是窗口内部承载按钮、文字等控件的画布self.pl=wx.Panel(self,size=(800,600),pos=(100,100))# 设置窗口背景颜色为白色self.SetBackgroundColour('white')# 定义定时器变量,初始为None,用来控制名字滚动self.timer=None# 创建静态文本控件,用来展示滚动的名字# label:初始展示随机选取的一个名字;pos:控件在面板上的坐标位置self.staticText=wx.StaticText(self.pl,label=random.choice(self.NameList),pos=(300,150))# 创建字体对象:字号40,无衬线字体,正常样式,加粗font=wx.Font(40,wx.FONTFAMILY_SWISS,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_BOLD)# 将字体应用到静态文本上self.staticText.SetFont(font)# 创建【开始抽奖】按钮self.btn1=wx.Button(self.pl,label='开始抽奖',pos=(100,10))# 创建【结束抽奖】按钮self.btn2=wx.Button(self.pl,label='结束抽奖',pos=(200,10))# 绑定按钮点击事件:点击btn1时,执行onclick函数self.Bind(wx.EVT_BUTTON,self.onclick,self.btn1)# 绑定按钮点击事件:点击btn2时,执行stop函数self.Bind(wx.EVT_BUTTON,self.stop,self.btn2)# 【开始抽奖】按钮对应的回调函数defonclick(self,_event):# 判断:如果定时器已经存在并且正在运行,直接return,禁止重复开启定时器# 解决连续点击开始,多个定时器叠加,名字越闪越快的bugifself.timerisnotNoneandself.timer.IsRunning():return# 实例化定时器对象,绑定到当前窗口self.timer=wx.Timer(self)# 绑定定时器事件:定时器触发时执行update_name函数self.Bind(wx.EVT_TIMER,self.update_name,self.timer)# 启动定时器,参数单位是毫秒,100=0.1秒触发一次刷新self.timer.Start(100)# 定时器触发的回调函数:更新显示的名字defupdate_name(self,_event):# 从名单中随机挑选一个名字,设置给文本控件self.staticText.SetLabelText(random.choice(self.NameList))# 【结束抽奖】按钮对应的回调函数defstop(self,_event):# 先判断定时器是否有效且正在运行ifself.timerisnotNoneandself.timer.IsRunning():# 停止定时器,名字停止滚动self.timer.Stop()# 获取当前文本控件上显示的名字,即为中奖者winner=self.staticText.GetLabelText()# 弹出消息弹窗,展示中奖结果# wx.OK:弹窗带确定按钮;wx.ICON_INFORMATION:弹窗自带信息图标wx.MessageBox(f"🎉 恭喜{winner}中奖!","抽奖结果",wx.OK|wx.ICON_INFORMATION)# 程序入口,当直接运行该py文件时,执行下方代码if__name__=='__main__':# 创建wx应用程序实例,一个GUI程序有且仅有一个App对象app=wx.App()# 实例化我们自定义的窗口frm=MyFrame()# 显示窗口frm.Show()# 启动GUI主消息循环,持续监听点击、定时器等事件,保持窗口打开app.MainLoop()

分段解答

1. 模块导入与窗口类定义

首先导入两个依赖模块,random负责随机选取名字,wx是wxPython的核心库。
我们新建类MyFrame并继承wx.Frame。wx.Frame就是一个标准窗口模板,继承之后我们就可以在里面添加文字、按钮、定时器等控件。
静态属性NameList存放所有参与抽奖的名字,想要增减人员,直接修改这个列表即可。

2.init初始化窗口与控件

__init__是类的构造函数,创建窗口对象的时候会自动执行这一段代码。

  • 先调用父类构造,设置窗口标题、窗口尺寸;
  • wx.Panel相当于一块画布,所有按钮、文字都需要放在Panel上;
  • wx.StaticText静态文本,专门用来展示文字,这里用来显示滚动的姓名;
  • wx.Font自定义字体样式,放大文字,投屏抽奖的时候看得更清楚;
  • wx.Button创建两个功能按钮;
  • Bind()是事件绑定方法,作用是:当按钮被点击时,自动执行我们指定的回调函数。
3. 开始抽奖回调 onclick 与定时器逻辑

这是本程序最核心的部分,滚动效果依靠wx.Timer定时器实现。
增加状态判断,检测定时器是否正在运行。如果已经在运行,直接退出函数,避免多次点击生成多个定时器,出现名字越闪越快的bug。
timer.Start(100)代表每100毫秒触发一次定时器事件,单位是毫秒。

4. 名字刷新函数 update_name

定时器每一次触发,都会执行这个函数。
调用random.choice在名单里随机挑选一个名字,然后使用SetLabelText更新界面上显示的文字,营造滚动摇号的视觉效果。

5. 结束抽奖回调 stop

点击结束按钮后,先判断定时器状态,确认正在运行才执行停止操作。
定时器停止,文字就不再刷新。读取当前界面上的文字作为中奖人,调用wx.MessageBox弹出弹窗展示中奖信息。

6. 程序入口与GUI主循环

if __name__ == '__main__'是Python脚本入口判断,只有直接运行这个文件,里面代码才会执行。
每一个wxPython程序必须有且仅有一个 wx.App。app.MainLoop()开启GUI主循环,持续监听鼠标点击、定时器事件,窗口才能保持打开状态。

7. 本案例注意事项
  1. 这个案例使用固定坐标pos=(x,y)摆放控件,写法简单直观;缺点是拖动窗口放大缩小时,控件位置不会自动跟着适配。
  2. GUI界面中严禁使用while死循环刷新画面,死循环会抢占主线程,阻塞主循环,窗口直接卡死无响应,定时刷新优先使用wx.Timer。
  3. wx.MessageBox属于模态弹窗,弹窗弹出之后,无法操作主窗口,必须点击确定关闭弹窗之后,才能继续操作。
  4. 名单里面的文本使用英文逗号分隔,名字可以是中文、英文。

二、简易计算器:Sizer网格自适应布局实战

源码

# 导入wxPython核心库importwx# 自定义计算器窗口类,继承wx.FrameclassCalcFrame(wx.Frame):def__init__(self):# 父类初始化:无父窗口,窗口标题,窗口初始宽高 300*420super().__init__(None,title="简易计算器 wxPython",size=(300,420))# 创建面板,作为所有按钮、输入框的容器panel=wx.Panel(self)# 创建垂直布局盒子,控件从上到下依次排列vbox=wx.BoxSizer(wx.VERTICAL)# 创建文本输入框# wx.TE_RIGHT:文字右对齐;wx.TE_READONLY:输入框只读,不能键盘直接输入,只能点按钮self.display=wx.TextCtrl(panel,style=wx.TE_RIGHT|wx.TE_READONLY)# 设置输入框字体:字号24,默认字体族,正常样式,加粗self.display.SetFont(wx.Font(24,wx.FONTFAMILY_DEFAULT,wx.FONTSTYLE_NORMAL,wx.FONTWEIGHT_BOLD))# 将输入框加入垂直布局# wx.EXPAND:控件自动拉伸填充;wx.ALL:四周都设置内边距;border:边距大小vbox.Add(self.display,flag=wx.EXPAND|wx.ALL,border=10)# 创建网格布局:4行4列,控件横向间距5px,纵向间距5pxgrid=wx.GridSizer(4,4,5,5)# 定义所有按钮上显示的文字,顺序对应4×4网格排布buttons=["7","8","9","/","4","5","6","*","1","2","3","-","0","C","=","+"]# 循环遍历按钮文字列表,批量创建按钮fortxtinbuttons:# 创建按钮,文字为循环取出的txtbtn=wx.Button(panel,label=txt)# 所有按钮统一绑定同一个点击回调函数btn.Bind(wx.EVT_BUTTON,self.on_btn_click)# 将按钮加入网格布局,wx.EXPAND让按钮自动填满格子grid.Add(btn,flag=wx.EXPAND)# 将整个按钮网格,添加到外层垂直布局中vbox.Add(grid,flag=wx.EXPAND|wx.ALL,border=10)# 给面板设置布局管理器,布局才会生效panel.SetSizer(vbox)# 窗口在屏幕居中显示self.Centre()# 所有按钮共用的点击回调函数defon_btn_click(self,event):# 获取被点击按钮上的文字标签label=event.GetEventObject().GetLabel()# 获取当前输入框里面已经存在的文本text=self.display.GetValue()# 如果点击的是 C 按钮:清空输入框iflabel=="C":self.display.SetValue("")# 如果点击的是 = 按钮:执行计算eliflabel=="=":# try-except捕获计算过程中的异常,防止程序崩溃try:# eval函数把字符串表达式转为代码执行,计算结果转为字符串res=str(eval(text))# 将计算结果放回输入框self.display.SetValue(res)exceptException:# 表达式非法(除0、语法错误等),输入框显示Errorself.display.SetValue("Error")# 其余数字、运算符按钮:把字符追加到输入框末尾else:self.display.SetValue(text+label)# 程序入口if__name__=="__main__":# 创建应用实例app=wx.App()# 实例化计算器窗口frame=CalcFrame()# 显示窗口frame.Show()# 开启GUI主循环,持续监听事件app.MainLoop()

分段解答

1. 模块导入与计算器窗口类定义

只需要导入wx库,新建CalcFrame类继承wx.Frame。
这个案例重点学习Sizer自动布局,不再使用固定坐标定位控件,是wxPython项目里推荐的标准写法。

2. 初始化布局容器与输入框

wx.BoxSizer(wx.VERTICAL)垂直盒子布局,控件自上而下摆放。
wx.TextCtrl文本输入框,通过style参数设置两个特性:wx.TE_RIGHT文字靠右(符合计算器习惯),wx.TE_READONLY只读,禁止键盘直接输入。
使用vbox.Add()把控件加入布局,flag参数控制填充方式与边距。wx.EXPAND代表控件会自动拉伸填满可用空间。

3. GridSizer网格布局、批量生成按钮

wx.GridSizer(4,4,5,5)创建4行4列网格,后两个参数是格子横向、纵向间隙。
我们把所有按钮文字放到列表,通过for循环批量创建按钮、绑定事件、加入网格布局。
所有按钮绑定同一个回调函数,减少大量重复代码,是GUI开发很经典的写法。
网格布局添加完成之后,把网格整体放进外层垂直盒子,最后调用panel.SetSizer(vbox)布局才会生效,这一步很容易被小白漏掉。

4. 统一回调函数 on_btn_click

event.GetEventObject()获取触发事件的控件对象,再调用GetLabel()拿到按钮文字,以此区分不同按钮的功能:

  • 点击C:清空输入框;
  • 点击=:执行计算;
  • 数字和运算符:直接追加到输入框字符串末尾。
5. try-except异常捕获与eval计算

eval可以直接把数学字符串表达式运算出结果。
外面包裹try except,用来捕获除零错误、表达式语法错误等异常。一旦出错,界面展示Error而不是直接闪退。

6. 程序入口和主循环

和抽奖器结构保持一致:创建App、创建窗口、显示窗口、启动主循环。
wxPython所有GUI程序都遵循这套固定模板。

7. 本案例注意事项
  1. Sizer布局和固定pos布局不要混用,布局逻辑容易混乱;正式开发优先选择Sizer。
  2. eval存在极大安全风险,它可以执行任意Python代码,仅限学习Demo使用,线上、正式项目禁止直接接收外部输入交给eval执行。
  3. 只读输入框只是限制键盘输入,代码依然可以调用SetValue修改里面的文字,二者不冲突。
  4. 计算连续运算符、除以0等非法表达式都会触发异常,依靠try-except实现容错。

三、打包为独立exe程序

源码(打包命令)

# 抽奖器打包pyinstaller-F-wlottery.py# 计算器打包pyinstaller-F-wcalc.py

分段解答

1. 命令参数说明
  • -F:打包为单个独立exe文件,方便拷贝分发;
  • -w:运行程序时,隐藏黑色控制台小黑窗。
2. 注意事项
  1. 需要提前安装pyinstaller:pip install pyinstaller;
  2. 打包完成后,exe文件会生成在dist文件夹内;
  3. 如果代码中加载外部图片、txt资源,打包时需要额外配置资源路径。

四、总结

这两个小案例刚好对应wxPython入门里两类典型场景:
抽奖器侧重定时器动画、动态文字刷新和弹窗交互;计算器侧重Sizer自适应布局、统一事件分发。

GUI开发的核心就是三件事:界面组件、事件监听、布局管理。从这种注释详尽的小Demo入手,理解窗口主循环的运行逻辑,是非常轻松的入门路线。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询