侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程

Windows  /  管理员 发布于 5年前   256

Python是支持可视化编程,即编写gui程序,你可以用它来编写自己喜欢的桌面程序。使用wxPython来做界面非常的简单,只是不能像C#一样拖动控件,需要自行写代码布局。在完成编写之后,由于直接的py文件不能再没有安装python的电脑上运行,能否有一个打包成在任意电脑都能运行的工具,网上找找发现了py2exe正好可以完成这个功能。wxPython和py2exe都是开源免费软件。

环境配置
wxPython: sourceforge项目页https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/
下载后双击安装即可,安装程序会自动安装到对应python\Scripts下。
py2exe:官方下载主页https://www.wxpython.org/download.php
同样双击即可安装,注意下载要对应使用的Python版本。
下面分别示例说明wxPython和py2exe的简单使用。

基本示例
文件名:wxTest.py:

# -*- coding: cp936 -*-'''MainWindow类完成最简单的编辑功能,添加一个主菜单,两个子菜单(about和exit)'''import wx class MainWindow(wx.Frame): '''定义一个窗口类''' def __init__(self, parent, title):  wx.Frame.__init__(self, parent, title=title, size=(300, 300))  self.control = wx.TextCtrl(self, style=wx.TE_MULTILINE)   self.setupMenuBar()  self.Show(True)  def setupMenuBar(self):  self.CreateStatusBar()   menubar = wx.MenuBar()  menufile = wx.Menu()   mnuabout = menufile.Append(wx.ID_ABOUT, '&About', 'about this shit')  mnuexit = menufile.Append(wx.ID_EXIT, 'E&xit', 'end program')   menubar.Append(menufile, '&File')   #事件绑定  self.Bind(wx.EVT_MENU, self.onAbout, mnuabout)  self.Bind(wx.EVT_MENU, self.onExit, mnuexit)     self.SetMenuBar(menubar)  def onAbout(self, evt):   '''点击about的事件响应'''   dlg = wx.MessageDialog(self, 'This app is a simple text editor', 'About my app', wx.OK)   dlg.ShowModal()   dlg.Destroy()  def onExit(self, evt):   '''点击退出'''   self.Close(True)app = wx.App(False)frame = MainWindow(None, 'Small Editor')app.MainLoop() #循环监听事件

编辑好改文件后,使用py2exe将Python脚本编译成Windows可执行文件,这样就不需要Python解释器了。要使用py2exe,首先要编写一个编译脚本,然后通过Python运行编译脚本即可将其他的脚本编译成可执行文件。以下实例是将要编译成可执行文件的脚本,文件名:setup.py

import distutilsimport py2exedistutils.core.setup(windows=['wxTest.py'])

在setup.py中除了导入必需的模块以外,只有一条语句:

distutils.core.setup(windows=['wxTest.py'])

方括号中就是要编译的脚本名,前边的windows 表示将其编译成GUI程序。如果要编译命令行界面的可执行文件,只要将windows改为console,如果需要将脚本编译成Windows服务,则可以使用service选项。
都编辑好之后,将wxTest.py和setup.py放在同一个路径下,cmd进入该路径,输入:

setup.py py2exe
如果在运行时报以下错误:
error: MSVCP90.dll: No such file or directory
是因为没有找到MSVCP90.dll,在windows目录下搜索MSVCP90.dll这个文件,然后拷到python安装目录的DLLs下就可以了。
当打包PyQt项目时,可能会报以下错误
ImportError: No module named sip
这时只需要在打包时加上--includes sip就行啦,如:
setup.py py2exe --includes sip

运行结束之后,会在路径下生成dist和 build两个目录。其中dist目录中就是编译生成的文件。如果要在其他未安装Python的机器上运行编译好的程序,只要将dist目录复制到其他机器上即可。双击运行wxTest.exe,如图:

使用wxPython建立一个计算文件md5的GUI工具
小工具最终是下面这个样子,将文件拖到上面会自动计算其md5与size

下面是全部的代码

#coding:gbkimport wximport optparseimport time,hashlibimport threadingimport osdef checkMD5(pefile):  try:    f = open(pefile,'rb')    data = f.read()    m = hashlib.md5()    m.update(data)    f.close()    return m.hexdigest()  except:    return 'error'  def getFileSize(filename):  try:    size = int(os.path.getsize(filename))    return size  except:    return 'error'   #线程函数class FuncThread(threading.Thread):  def __init__(self, func, *params, **paramMap):    threading.Thread.__init__(self)    self.func = func    self.params = params    self.paramMap = paramMap    self.rst = None    self.finished = False  def run(self):    self.rst = self.func(*self.params, **self.paramMap)    self.finished = True  def getResult(self):    return self.rst  def isFinished(self):    return self.finisheddef doInThread(func, *params, **paramMap):  t_setDaemon = None  if 't_setDaemon' in paramMap:    t_setDaemon = paramMap['t_setDaemon']    del paramMap['t_setDaemon']  ft = FuncThread(func, *params, **paramMap)  if t_setDaemon != None:    ft.setDaemon(t_setDaemon)  ft.start()  return ftclass FileDropTarget(wx.FileDropTarget):  def __init__(self, filetext,md5tx,filesizetx):    wx.FileDropTarget.__init__(self)    self.filepath = filetext    self.md5tx = md5tx    self.filesizetx = filesizetx     def OnDropFiles(self, x, y, fileNames):    filename = fileNames[0].encode('gbk')    print filename    print type(filename)    self.filepath.SetValue(filename)    md5 = doInThread(checkMD5,filename)    filesize = doInThread(getFileSize,filename)    while True:      if not md5.isFinished():        time.sleep(0.5)      else:        self.md5tx.SetValue(md5.getResult())        break            while True:      if not filesize.isFinished():        time.sleep(0.5)      else:        self.filesizetx.SetValue(str(filesize.getResult()))        breakclass Frame(wx.Frame): #Frame 进行初始化  def __init__(self,title):    wx.Frame.__init__(self,None,title=title,size = (400,300))    boxSizer = wx.BoxSizer(wx.VERTICAL)        self.panel = wx.Panel(self)        # boxSizer.Add(self.panel,1,wx.EXPAND|wx.ALL) #wx.ALL 周围的距离,EXPAND扩充到全部        filepath = wx.StaticText(self.panel,-1,"FileDir(请将文件拖到本对话框中)")    filetext = wx.TextCtrl(self.panel,-1,"",size=(350,20))        md5st = wx.StaticText(self.panel,-1,"MD5")    md5tx = wx.TextCtrl(self.panel,-1,size=(250,20))        filesizest = wx.StaticText(self.panel,-1,'FileSize')    filesizetx = wx.TextCtrl(self.panel,-1,size=(250,20))        # hashst = wx.StaticText(self.panel,-1,'Hash')    # hashtx = wx.TextCtrl(self.panel,-1,size=(250,20))        boxSizer.Add(filepath,0,wx.EXPAND|wx.LEFT|wx.TOP,border=10)    boxSizer.Add(filetext,0,wx.LEFT|wx.TOP,border=10)    boxSizer.Add((-1,20))    boxSizer.Add(md5st,0,wx.LEFT|wx.TOP,border=10)    boxSizer.Add(md5tx,0,wx.LEFT|wx.TOP,border=10)    boxSizer.Add((-1,10))    boxSizer.Add(filesizest,0,wx.LEFT|wx.TOP,border=10)    boxSizer.Add(filesizetx,0,wx.LEFT|wx.TOP,border=10)    # boxSizer.Add((-1,10))    # boxSizer.Add(hashst,0,wx.LEFT|wx.TOP,border=10)    # boxSizer.Add(hashtx,0,wx.LEFT|wx.TOP,border=10)        dropTarget = FileDropTarget(filetext,md5tx,filesizetx)    self.panel.SetDropTarget( dropTarget )        self.panel.SetSizer(boxSizer)     class App(wx.App): ##继承wx.App  def OnInit(self): ##还没有调起来的时候读取初始化    self.frame = Frame('MD5&size信息')        self.frame.Centre()    self.frame.Show(True)        return Truedef killSelf(evt = None):  os.system('taskkill /F /T /PID %d >NUL 2>NUL' % win32process.GetCurrentProcessId())if __name__ == '__main__':  parser = optparse.OptionParser()  parser.add_option('-x', '--no-update', dest = 'test', action = 'store_true', help = 'start without update')  parser.add_option('-t', '--no-update-test', dest = 'test2', action = 'store_true', help = 'start without update debug')  options, args = parser.parse_args()  if options.test:    print("-x param")  if options.test2:    print("-t param")  App(redirect = False).MainLoop()

一点点的解释:

class App与App().MainLoop()是固定写法,在class App下有一个def OnInit方法来初始化主的Frame,将其居中并且Show()出来,没什么好说的,主要看一下Frame的定义

这个小工具使用的是boxSizer来布局,为了简单我只使用了一个boxSizer,将里面的所有控件采用VERTICAL(垂直)的方式来布局,如果想要将MD5与后面的文本框放在同一行,那么就需要添加一个水平的boxSizer,然后那将这个水平的boxSizer再放入主的boxSizer

boxSizer = wx.BoxSizer(wx.VERTICAL) #初始化一个垂直的boxSizer,也是整个框架的主Sizerself.panel = wx.Panel(self) #初始化一个panel,这个panel是放了放之后的控件的filepath = wx.StaticText(self.panel,-1,"FileDir(请将文件拖到本对话框中)") filetext = wx.TextCtrl(self.panel,-1,"",size=(350,20)) md5st = wx.StaticText(self.panel,-1,"MD5") md5tx = wx.TextCtrl(self.panel,-1,size=(250,20)) filesizest = wx.StaticText(self.panel,-1,'FileSize') filesizetx = wx.TextCtrl(self.panel,-1,size=(250,20))

上面是初始化相应的静态文本与文本框,方法中的第一个参数是其所在的父类窗口,这里也就是self.panel,其实也可以不用panel,而是将其直接放入到boxSizer中
boxSizer.Add(filepath,0,wx.EXPAND|wx.LEFT|wx.TOP,border=10) 

将filepath加入到主的boxSizer中,这里一开始我有一些困惑,一开始我一直以为先将所有的控件放入到panel中,然后再将panel放入到boxSizer中,但是这样是不对的,而应该是直接就入到boxSizer中,将该控件的父类设置为panel,之后就没有将panel放入boxSizer这一步操作,wx.LEFT|wx.TOP,border=10 这个参数表示的是该控件距离上来左各有10个像素的距离,再使用wx.EXPAND来使其充分的填充其所在的区域,我曾经想,可否设置成距离上10px,左20px,但是貌似不能这样设置,Add函数里只能有一个border参数,换句话说只能设置相同的数值,之后我再找找是否可以实现。

boxSizer.Add((-1,20)) #这个是添加一个空距离,距离上20pxdropTarget = FileDropTarget(filetext,md5tx,filesizetx) self.panel.SetDropTarget( dropTarget )

这个是放该窗口类添加一个拖拽方法,也是比较固定的写法

上面的class FileDropTarget中的__init__与OnDropFiles方法也是固定的方法,只是里面的处理函数不同。

wxPython中的一些style与flag等参数在布局中使用需要一些经验,还有它的很多控件和与之绑定的方法,要想熟练掌握还需要下一些工夫,下面两个网站算是介绍比较详细,要多多查阅

您可能感兴趣的文章:

  • wxPython:python首选的GUI库实例分享
  • python GUI图形化编程wxpython的使用
  • 基于wxPython的GUI实现输入对话框(2)
  • 基于wxPython的GUI实现输入对话框(1)
  • 在Ubuntu系统下安装使用Python的GUI工具wxPython
  • 基于wxpython开发的简单gui计算器实例
  • 基于wxpython实现的windows GUI程序实例
  • python图形开发GUI库wxpython使用方法详解


  • 上一条:
    python在Windows下安装setuptools(easy_install工具)步骤详解
    下一条:
    Lua中的__index和__newindex实例
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • Windows 10的告别:2025年10月14日,一段时代的终结(0个评论)
    • windows 11激活_Win11 KMS激活流程步骤(1个评论)
    • 安装Windows 11系统的注意了,看看你的cpu是否在微软兼容列表排除中(1个评论)
    • 微软将于2022年9月20日推送Windows11 22H2新版本,推测2024发布windows 12(0个评论)
    • windows11系统中可以关闭禁止的服务及介绍(1个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • Laravel从Accel获得5700万美元A轮融资(0个评论)
    • 在go + gin中gorm实现指定搜索/区间搜索分页列表功能接口实例(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2018-01
    • 2018-06
    • 2020-06
    • 2021-06
    • 2021-07
    • 2022-01
    • 2022-04
    • 2022-08
    • 2023-08
    • 2023-10
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客