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

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,如图:

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

下面是全部的代码

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

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索python
, windows
, gui
, py2exe
wxpython
python gui wxpython、py2exe wxpython、python gui界面实例、python gui编程实例、wxpython gui builder,以便于您获取更多的相关知识。

时间: 2025-01-21 13:13:30

Windows中使用wxPython和py2exe开发Python的GUI程序的实例教程_python的相关文章

Python实现命令行通讯录实例教程_python

1.实现目标 编写一个命令行通讯录程序,可以添加.查询.删除通讯录好友及电话 2.实现方法 创建一个类来表示一个人的信息.使用字典存储每个人的对象,名字作为键. 使用pickle模块永久地把这些对象存储下来. 使用字典内建的方法添加.删除修改人员信息. 3.思维导图 4.编写伪代码 # 1.创建字典用来存储通讯录信息 # 2.创建人员类,包含姓名.关系.电话三个属性 # 3.创建操作类,包含增加.查询.删除人员,退出,保存并退出五个方法 # 4.程序运行 # 5.判断通讯录文件是否存在 # 6.

使用Python开发windows GUI程序入门实例_python

今天终于可以用wxPython开发GUI程序了,非常高兴.把其中的一些注意点写下来以供参考.在windows XP平台下,首先需要做以下环境的配置: 1. 首先是安装python ,安装完之后将python/bin所在目录添加到path中. 2. 安装wxPython, 此时要注意wxPython的版本要与前面python的版本一致. 3. 安装py2exe, 这是windows平台下一个非常好的python程序发布工具,可以将python程序编译成exe而脱离python环境执行.做完上面的安

Python中zip()函数用法实例教程_python

本文实例讲述了Python中zip()函数的定义及用法,相信对于Python初学者有一定的借鉴价值.详情如下: 一.定义: zip([iterable, ...])zip()是Python的一个内建函数,它接受一系列可迭代的对象作为参数,将对象中对应的元素打包成一个个tuple(元组),然后返回由这些tuples组成的list(列表).若传入参数的长度不等,则返回list的长度和参数中长度最短的对象相同.利用*号操作符,可以将list unzip(解压). 二.用法示例: 读者看看下面的例子,对

Python中apply函数的用法实例教程_python

一.概述: python apply函数的具体含义如下:  apply(func [, args [, kwargs ]]) 函数用于当函数参数已经存在于一个元组或字典中时,间接地调用函数.args是一个包含将要提供给函数的按位置传递的参数的元组.如果省略了args,任何参数都不会被传递,kwargs是一个包含关键字参数的字典.   apply()的返回值就是func()的返回值,apply()的元素参数是有序的,元素的顺序必须和func()形式参数的顺序一致 二.使用示例: 下面给几个例子来详

python中的多线程实例教程_python

本文以实例形式较为详细的讲述了Python中多线程的用法,在Python程序设计中有着比较广泛的应用.分享给大家供大家参考之用.具体分析如下: python中关于多线程的操作可以使用thread和threading模块来实现,其中thread模块在Py3中已经改名为_thread,不再推荐使用.而threading模块是在thread之上进行了封装,也是推荐使用的多线程模块,本文主要基于threading模块进行介绍.在某些版本中thread模块可能不存在,要使用dump_threading来代

WP8 和 Win8 应用程序开发布局的XAML标记语言实例教程

XAML提供了一种便于扩展和定位的语法来定义和程序逻辑分离的用户界面,而这种实现方式和ASP.NET中的"代码后置"模型非常类似.XAML是一种解析性的语言,尽管它也可以被编译.它的优点是简化编程式上的用户创建过程,应用时要添加代码等. XAML 示例 下面是创建按钮的简单 XAML 示例. XAML <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"&

Python多线程实例教程_python

本文以实例形式较为详细的讲解了Python的多线程,是Python程序设计中非常重要的知识点.分享给大家供大家参考之用.具体方法如下: 用过Python的人都会觉得Python的多线程很类似于Java的多线程机制,但是比JAVA的多线程更灵活.在早期的Python多线程实现中,采用了thread模块.例如:   from time import ctime,sleep from thread import start_new_thread def loop1(): print "enter lo

Python中用Spark模块的使用教程_python

 在日常的编程中,我经常需要标识存在于文本文档中的部件和结构,这些文档包括:日志文件.配置文件.定界的数据以及格式更自由的(但还是半结构化的)报表格式.所有这些文档都拥有它们自己的"小语言",用于规定什么能够出现在文档内.我编写这些非正式解析任务的程序的方法总是有点象大杂烩,其中包括定制状态机.正则表达式以及上下文驱动的字符串测试.这些程序中的模式大概总是这样:"读一些文本,弄清是否可以用它来做些什么,然后可能再多读一些文本,一直尝试下去." 解析器将文档中部件和结

Python迭代用法实例教程_python

本文实例讲述了Python中迭代的用法,是一个非常实用的技巧.分享给大家供大家参考借鉴之用.具体分析如下: 如果给定一个list或tuple,我们可以通过for循环来遍历这个list或tuple,这种遍历我们成为迭代(Iteration). 在Python中,迭代是通过for ... in来完成的,而很多语言比如C或者Java,迭代list是通过下标完成的,比如Java代码: for (i=0; i<list.length; i++) { n = list[i]; } 可以看出,Python的f