wxFormBuilder + wxPython手撸丑陋计算器

目录

前言

一、设计计算器图形界面

1、建Project

2、设计主体框的属性

3、设计计算器页面布局

二、代码架构设计

1、将计算器运行起来

 2、添加按钮事件

3、代码实现

4、运行计算器

三、测试计算器逻辑


前言

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下载

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

魂尾ac

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值