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

发表于 5年以前  | 总阅读数:868 次

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 distutils
    import py2exe
    distutils.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,如图:

2016711164500179.jpg \(300×300\)

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

2016711164609816.png \(443×334\)

下面是全部的代码


    #coding:gbk
    import wx
    import optparse
    import time,hashlib
    import threading
    import os

    def 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.finished

    def 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 ft

    class 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()))
            break

    class 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 True

    def 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,也是整个框架的主Sizer

    self.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)) #这个是添加一个空距离,距离上20px

    dropTarget = FileDropTarget(filetext,md5tx,filesizetx) 
    self.panel.SetDropTarget( dropTarget )

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

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

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

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录