目录
前言
wxPtyhon它是Python语言的跨平台GUI工具包。使用wxPython软件开发人员可以为他们的Python应用程序创建真正的本地用户界面。
wxFormBuilder是一个图片界面生成器,其生成的界面可以翻译成为C++、python、PHP、Lua、XRC代码。本文开源,跨平台,自动生成生成代码,提高开发效率的特性,用不用它,仁者见仁,智者见智。用熟悉了,什么工具都可达到最终目的,也可以不用工具,直接使用GUI库手撸客户端工具,大神一般是这么做的。所以本文适合刚上手wxPython,但又急于想开发客户端工具的人看。
本文会仔细描述wxFormBuilder如何拖拽出一个丑陋的计算器,生成wxPython代码;然后在这个基础上再描述实现计算器的计算功能的过程
代码编器使用PyCharm,阅读本文需要有Python基础,略微了解wxPython。
丑陋的计算器呈现效果如下(后期可能更丑~~~~)
一、设计计算器图形界面
1、建Project
打开wxFormBuilder,
在Object Tree树下选择MyProject1:Project、
点击Component Palotte 下Forms 的Tab页,点击Frame按钮(第一个),
按下图数字标识,生成一个Frame框。这将会是计算器的主体。
2、设计主体框的属性
属性Object Properties------ProperTies
去掉标题栏
Frame-----style 下的wxDEFAULT_FRAME_STYLE 取消勾选,
标题栏去掉,最大化、最小化、关闭按钮跟着一并去掉了
设置size
最小为宽400px;长500px
wxWindow-----minimum_size设置400;500,
size 宽为400px:可横向摆上4例按钮 ,
size 高为500px:可竖向摆上1个显示屏与5行按钮
3、设计计算器页面布局
先将计算器画一下,明确布局,使用WxBoxSize布局
上图标1是显示屏,占WxBoxSize一栏
上图标2是按钮区,占WxBoxSize一栏
上图标3是按钮分区,在2栏里嵌套一个WxBoxSize
1)添加布局、显示
在Object Tree选择MyFrame1:Frame,然后在Component Palatte里选择Layout布局Tab页,选择WxBoxSize添加
按图中数字顺序操作
在bSizer1:wxBoxSize第一栏添加一个Text,
Common 页中选择编辑框
按图中数字顺序操作
在BSizer1中添加一个wxBoxsize
选择BSizer1:wxBoxSizer,进入Layout 页,添加一个WxBoxSizer,将这个WxBoxSizer的orient设置为WxHORIZONTAL (横向)
按图中数字顺序操作
在bSizer2中添加四个WxBoxSizer,
操作方法与上面一样,只是添加一个,orient默认不动,此时主体框还看不出什么
按图中数字顺序操作
添加按钮,在BSizer3、BSizer4、BSizer5、BSizer6下,各添加5个按钮,
调整所有按钮最小Size为70px; 60px
按图中数字顺序操作
设置显示屏属性与按钮字符修改
显示屏样式
Size设置:Minimum_size:370;80
只读:wxREADONLY
靠右:wxTE_RIGHT
多行:wxTE_MULTILINE
自行展示滚动条:wxTE_RICH --------行数超过显示屏展示滚动条,未超过不展示
显示屏中字体大小样式,因为这个wxFormBuilder可能没装好,无法设置,后期在代码里修改
修改按钮展示字符,点击目标按钮,在Properties里找到label,改变其值,如下图
按图中数字顺序操作
注意:修改属性时,切换控件请勿直接点击另一个控件,大概率会导致wxFormBuilder崩溃。可以先点击上图3处空白地段,再点击另一个控件,这样就不会使wxFormBuilder崩溃。
修改完按钮字符后,
将第四列按钮删除一个,=号按钮高度调整为125px
再将主体框高度调整为450px
这里只给描述没给操作步骤,请自行按照前面的操作修改对应参数。
计算器框效果图如下
wxFormBuilder部分完成,接下来将将Editer由Designer切换到下图Python页,复制其中的py代码到下个章节开始做计算器后台逻辑的开发
生成的代码重新给了相关注释,输出如下:
# -*- coding: utf-8 -*-
###########################################################################
## Python code generated with wxFormBuilderormBuilder (version Jun 17 2015)
## http://www.wxFormBuilderormbuilder.org/
##
## PLEASE DO "NOT" EDIT THIS FILE!
###########################################################################
#导入wxPython相关的库
import wx
import wx.xrc
###########################################################################
## Class MyFrame1
###########################################################################
class MyFrame1 ( wx.Frame ):
#初始化构造框体,
def __init__( self, parent ):
#初始化父类,构造Frame框体,传入了父类对象,框体id,框体title,位置pos,大小size,风格style
wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( -1,-1 ), style = 0|wx.TAB_TRAVERSAL )
#设置框体大小,这里正式使用时要将self.SetSizeHintsSz改为self.SetSizeHints,国为self.SetSizeHintsSz是比较老版本wxPython中的方法了,新方法去掉了末尾Sz
self.SetSizeHintsSz( wx.Size( 400,450 ), wx.DefaultSize )
#创建第一个布局BoxSizer 为 bSizer1,纵向的
bSizer1 = wx.BoxSizer( wx.VERTICAL )
#创建编辑框
self.m_textCtrl1 = wx.TextCtrl( self, wx.ID_ANY, u"1+2=\n3", wx.DefaultPosition, wx.DefaultSize, wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH|wx.TE_RIGHT )
#设置编辑框的大小
self.m_textCtrl1.SetMinSize( wx.Size( 370,80 ) )
#将编辑框加入到 bSizer1中去
bSizer1.Add( self.m_textCtrl1, 0, wx.ALL, 5 )
#创建第二个布局BoxSizer 为 bSizer2,横向的
bSizer2 = wx.BoxSizer( wx.HORIZONTAL )
#创建第三个布局BoxSizer 为 bSizer3,纵向的
bSizer3 = wx.BoxSizer( wx.VERTICAL )
#创建第一个button按钮为m_button1
self.m_button1 = wx.Button( self, wx.ID_ANY, u"C", wx.DefaultPosition, wx.DefaultSize, 0 )
#设置按钮的大小
self.m_button1.SetMinSize( wx.Size( 70,60 ) )
#将m_button1加入后bSizer3中
bSizer3.Add( self.m_button1, 0, wx.ALL, 5 )
self.m_button2 = wx.Button( self, wx.ID_ANY, u"7", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button2.SetMinSize( wx.Size( 70,60 ) )
bSizer3.Add( self.m_button2, 0, wx.ALL, 5 )
self.m_button3 = wx.Button( self, wx.ID_ANY, u"4", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button3.SetMinSize( wx.Size( 70,60 ) )
bSizer3.Add( self.m_button3, 0, wx.ALL, 5 )
self.m_button4 = wx.Button( self, wx.ID_ANY, u"1", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button4.SetMinSize( wx.Size( 70,60 ) )
bSizer3.Add( self.m_button4, 0, wx.ALL, 5 )
self.m_button17 = wx.Button( self, wx.ID_ANY, u"%", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button17.SetMinSize( wx.Size( 70,60 ) )
bSizer3.Add( self.m_button17, 0, wx.ALL, 5 )
#将纵向的bSizer3加入到横向的bSizer2中,实现例。后面还有三个纵向的bSizer要加入bSizer2中,实现四例的按钮组合
bSizer2.Add( bSizer3, 1, wx.EXPAND, 5 )
#创建第四个布局BoxSizer 为 bSizer4,纵向的
bSizer4 = wx.BoxSizer( wx.VERTICAL )
self.m_button5 = wx.Button( self, wx.ID_ANY, u"+", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button5.SetMinSize( wx.Size( 70,60 ) )
bSizer4.Add( self.m_button5, 0, wx.ALL, 5 )
self.m_button6 = wx.Button( self, wx.ID_ANY, u"8", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button6.SetMinSize( wx.Size( 70,60 ) )
bSizer4.Add( self.m_button6, 0, wx.ALL, 5 )
self.m_button7 = wx.Button( self, wx.ID_ANY, u"5", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button7.SetMinSize( wx.Size( 70,60 ) )
bSizer4.Add( self.m_button7, 0, wx.ALL, 5 )
self.m_button8 = wx.Button( self, wx.ID_ANY, u"2", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button8.SetMinSize( wx.Size( 70,60 ) )
bSizer4.Add( self.m_button8, 0, wx.ALL, 5 )
self.m_button18 = wx.Button( self, wx.ID_ANY, u"0", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button18.SetMinSize( wx.Size( 70,60 ) )
bSizer4.Add( self.m_button18, 0, wx.ALL, 5 )
bSizer2.Add( bSizer4, 1, wx.EXPAND, 5 )
#创建第五个布局BoxSizer 为 bSizer5,纵向的
bSizer5 = wx.BoxSizer( wx.VERTICAL )
self.m_button9 = wx.Button( self, wx.ID_ANY, u"-", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button9.SetMinSize( wx.Size( 70,60 ) )
bSizer5.Add( self.m_button9, 0, wx.ALL, 5 )
self.m_button10 = wx.Button( self, wx.ID_ANY, u"9", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button10.SetMinSize( wx.Size( 70,60 ) )
bSizer5.Add( self.m_button10, 0, wx.ALL, 5 )
self.m_button11 = wx.Button( self, wx.ID_ANY, u"6", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button11.SetMinSize( wx.Size( 70,60 ) )
bSizer5.Add( self.m_button11, 0, wx.ALL, 5 )
self.m_button12 = wx.Button( self, wx.ID_ANY, u"3", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button12.SetMinSize( wx.Size( 70,60 ) )
bSizer5.Add( self.m_button12, 0, wx.ALL, 5 )
self.m_button19 = wx.Button( self, wx.ID_ANY, u".", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button19.SetMinSize( wx.Size( 70,60 ) )
bSizer5.Add( self.m_button19, 0, wx.ALL, 5 )
bSizer2.Add( bSizer5, 1, wx.EXPAND, 5 )
bSizer6 = wx.BoxSizer( wx.VERTICAL )
self.m_button13 = wx.Button( self, wx.ID_ANY, u"<<", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button13.SetMinSize( wx.Size( 70,60 ) )
bSizer6.Add( self.m_button13, 0, wx.ALL, 5 )
self.m_button14 = wx.Button( self, wx.ID_ANY, u"*", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button14.SetMinSize( wx.Size( 70,60 ) )
bSizer6.Add( self.m_button14, 0, wx.ALL, 5 )
self.m_button15 = wx.Button( self, wx.ID_ANY, u"/", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button15.SetMinSize( wx.Size( 70,60 ) )
bSizer6.Add( self.m_button15, 0, wx.ALL, 5 )
self.m_button16 = wx.Button( self, wx.ID_ANY, u"=", wx.DefaultPosition, wx.DefaultSize, 0 )
self.m_button16.SetMinSize( wx.Size( 70,125 ) )
bSizer6.Add( self.m_button16, 0, wx.ALL, 5 )
bSizer2.Add( bSizer6, 1, wx.EXPAND, 5 )
#将横向的bSizer2加入bSizer1中第二个格子中,第一个格式是编辑框,第二个格子是按钮组全布局
bSizer1.Add( bSizer2, 1, wx.EXPAND, 5 )
self.SetSizer( bSizer1 )
self.Layout()
bSizer1.Fit( self )
self.Centre( wx.BOTH )
#析构函数 与 __init__相反,一个创造,一个毁灭
def __del__( self ):
pass
二、代码架构设计
1、将计算器运行起来
1)建工程目录
随便新增一个目录,将此目录取为GUIDEMO目录
使用pycharm ---file---Open 打开这个目录
在目录下新增一个Python Package目录,命名为:Calculator
2)复制图形界面Python代码
在Calculator下新增一个python文件MainFarme.py
将图形界面的python代码复制过来
没有安装wxPython库的,代码中的import wx 会提示红色波浪线,
使用命令安装:pip install wxpython
注意,复制过来的代码中,有异常代码,会运行报错,整理一下
找到self.SetSizeHintsSz改为:self.SetSizeHints
在Calculator下新增一个python文件runMain.py
在其中添加代码
import wx
from MainFarme import MyFrame1
'''
新建一个类,继承MyFrame1,
'''
class newWindow(MyFrame1):
pass
'''
运行入口
添加wx对象
添加NewWindow对象
newWindow显示(show)
'''
if __name__=='__main__':
app = wx.App()
win = newWindow(None)
win.Show()
app.MainLoop()
运行代码,出现了计算器窗口
此时,发现在。显示器中的字符未消失,且按钮响应事件未设置。
所以插入一拨wxFormBuilder的操作
一般我们写运行代码时,不直接使用MyFrame1创建对象,而是再用一个类继承MyFarme1。好处:就是在子类里修改代码不影响父类,如果我们调整图形界面,生成的新代码直接Copy过来用,无任何影响
2、添加按钮事件
回到wxFormBuilder点击按钮,在OjbectProperties下找到Events事件编辑,给OnButtonClick添加响应函数
如C按钮,添加响应函数OnClear
下面Bind方法就是绑定函数的方法
自动生成OnClear函数,里面有事件跳过的代码。
照模样将所有按钮都添加上事件如下。
将最新代码Copy到MainFarme.py中来
3、代码实现
之前我们做了newWindow继承MyFrame1的操作,是为了隔离图形界面修改,这算初步的封闭开发架构
如果是真实开发一个中大型项目,肯定不只是一个框体,所以有可能有很多个MyFrame文件与类,如果是都放在同一个目录下面,那么管理起来会很麻烦。
用目录分类管理代码文件,即使扩展再多的页面,也能条理清楚
mainFarme.py是图形界面代码,这里便不展示了
newWindow.py
#先继承MyFrame1,然后将所有按钮的点击事件覆盖,因为功能是要在这边实现
#定义了计算器算术式变量 self.formula_Text 计算结果self.result_Text
#实现的功能中使用到了re正则表达式,导入正则表达式,导入
import re #导入正则表达式
from MainFarme import MyFrame1 #导入计算器图形代码类
class NewWindow(MyFrame1):
def __init__(self, parent):
'''
初始化
:param parent:
'''
#计算器算术式
self.formula_Text = ''
#计算结果
self.result_Text = ''
super().__init__(parent)
按照逻辑与显示屏展示逻辑实现:
1)显示器展示
def set_Calculator_Text(self):
'''
设置显示器算式与计算结果
:return:
'''
if self.result_Text != '':
self.formula_Text += '\n' + self.result_Text
self.m_textCtrl1.SetValue(self.formula_Text)
2)清空按钮功能
def clear_Calculator_Text(self):
'''
清空显示屏
:return:
'''
self.result_Text = ''
self.formula_Text = ''
self.m_textCtrl1.SetValue('')
3)其他按钮实现 里面有使用到正则表达式,记录在最前面导入
def btn_Response(self, btn_value):
'''
实现按钮的功能
:param btn_value: 按钮符号
:return:
'''
if self.result_Text != '' and btn_value != '<<':
self.clear_Calculator_Text()
# 运算符
operation = ('+', '-', '*', '/', '%')
# 如果已有内容是以小数点开头的,在前面加 0
if self.formula_Text.startswith('.'):
self.formula_Text = '0' + self.formula_Text # 字符串可以直接用+来增加字符
# 根据不同的按钮作出不同的反应
if btn_value in '0123456789':
# 按下 0-9 在 content 中追加
self.formula_Text += btn_value
elif btn_value == '.':
# 将 content 从 +-*/ 这些字符的地方分割开来
lastPart = re.split(r'\+|-|\*|/|%', self.formula_Text)[-1]
if '.' in lastPart:
# 信息提示对话框
return
elif len(lastPart) == 0:
btn_value = '0' + btn_value
self.formula_Text += btn_value
elif btn_value == 'C':
# 清除文本框
self.formula_Text = ''
elif btn_value == '<<':
if self.result_Text != '':
self.result_Text = ''
self.formula_Text = self.formula_Text.split('\n')[0]
self.formula_Text = self.formula_Text[:-1]
elif btn_value == '=':
try:
# 对输入的表达式求值
self.result_Text = str(eval(self.formula_Text))
self.formula_Text += btn_value
except Exception as e:
return
elif btn_value in operation:
if self.formula_Text.endswith(operation):
return
self.formula_Text += btn_value
self.set_Calculator_Text()
按钮逻辑实现完成后了,再实现按钮点击响应函数,子类实现覆盖父类响应函数
def OnClear(self, event):
'''
清空
:param event:
:return:
'''
self.btn_Response('C')
def OnSeven(self, event):
'''
数字7
:param event:
:return:
'''
self.btn_Response('7')
def OnFour(self, event):
'''
数字4
:param event:
:return:
'''
self.btn_Response('4')
def OnOne(self, event):
'''
数字1
:param event:
:return:
'''
self.btn_Response('1')
def OnMorethan(self, event):
'''
按钮%
:param event:
:return:
'''
self.btn_Response('%')
def OnAdd(self, event):
'''
按钮+
:param event:
:return:
'''
self.btn_Response('+')
def Oneight(self, event):
'''
数字8
:param event:
:return:
'''
self.btn_Response('8')
def OnFive(self, event):
'''
数字5
:param event:
:return:
'''
self.btn_Response('5')
def OnTwo(self, event):
'''
数字2
:param event:
:return:
'''
self.btn_Response('2')
def OnZero(self, event):
'''
数字0
:param event:
:return:
'''
self.btn_Response('0')
def OnReduce(self, event):
'''
按钮-
:param event:
:return:
'''
self.btn_Response('-')
def OnNine(self, event):
'''
数字9
:param event:
:return:
'''
self.btn_Response('9')
def Onsix(self, event):
'''
数字6
:param event:
:return:
'''
self.btn_Response('6')
def Onthree(self, event):
'''
数字3
:param event:
:return:
'''
self.btn_Response('3')
def OnDecimal(self, event):
'''
小数点。
:param event:
:return:
'''
self.btn_Response('.')
def OnDel(self, event):
'''
退格 <<
:param event:
:return:
'''
self.btn_Response('<<')
def OnRide(self, event):
'''
按钮*
:param event:
:return:
'''
self.btn_Response('*')
def OnExcept(self, event):
'''
按钮/
:param event:
:return:
'''
self.btn_Response('/')
def OnEqualto(self, event):
'''
按钮=
:param event:
:return:
'''
self.btn_Response('=')
4、运行计算器
在runMain.py文件里编写运行代码i
import wx
from Calculator.manage.newWindow import NewWindow
'''
运行入口
添加wx对象
添加NewWindow对象
newWindow显示(show)
'''
if __name__=='__main__':
app = wx.App()
win = NewWindow(None)
win.Show()
app.MainLoop()
运行
三、测试计算器逻辑
5+2=
2+2*4=
1+3+56=
1111+2222=
9/3=
123123123 C
还可以做很多测试,有很多BUG
不过本文结束啦
代码打包下载路径
wxFormBuilder+wxPython+Python实现的简易计算器小项目代码-Python文档类资源-CSDN下载