Windows中使用wxPython和py2exe開發Python的GUI程式的執行個體教程,wxpythonpy2exe

來源:互聯網
上載者:User

Windows中使用wxPython和py2exe開發Python的GUI程式的執行個體教程,wxpythonpy2exe

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等參數在布局中使用需要一些經驗,還有它的很多控制項和與之綁定的方法,要想熟練掌握還需要下一些工夫,下面兩個網站算是介紹比較詳細,要多多查閱

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.