Heim  >  Artikel  >  Backend-Entwicklung  >  Beispiel-Tutorial zur Entwicklung von Python-GUI-Programmen in Windows mit wxPython und py2exe

Beispiel-Tutorial zur Entwicklung von Python-GUI-Programmen in Windows mit wxPython und py2exe

WBOY
WBOYOriginal
2016-08-04 08:55:541559Durchsuche

Python unterstützt die visuelle Programmierung, also das Schreiben von GUI-Programmen. Sie können damit Ihre bevorzugten Desktop-Programme schreiben. Die Verwendung von wxPython zum Erstellen einer Schnittstelle ist sehr einfach, Sie können jedoch keine Steuerelemente wie C# ziehen und müssen das Codelayout selbst schreiben. Gibt es nach Abschluss des Schreibens ein Tool, das für die Ausführung auf jedem Computer gepackt werden kann, da die direkte py-Datei nicht auf einem Computer ausgeführt werden kann, auf dem Python nicht installiert ist? Ich habe festgestellt, dass py2exe diese Funktion einfach ausführen kann. Sowohl wxPython als auch py2exe sind freie Open-Source-Software.

Umgebungskonfiguration
wxPython: Sourceforge-Projektseite https://sourceforge.net/projects/py2exe/files/py2exe/0.6.9/
Doppelklicken Sie nach dem Herunterladen zum Installieren. Das Installationsprogramm wird automatisch in den entsprechenden Python-Skripten installiert.
py2exe: Offizielle Download-Homepage https://www.wxpython.org/download.php
Sie können es auch installieren, indem Sie darauf doppelklicken. Achten Sie auf die Python-Version, die Sie herunterladen möchten.
Die folgenden Beispiele veranschaulichen die einfache Verwendung von wxPython und py2exe.

Grundlegendes Beispiel
Dateiname: 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() #循环监听事件

Nachdem Sie die geänderte Datei bearbeitet haben, kompilieren Sie das Python-Skript mit py2exe in eine ausführbare Windows-Datei, sodass kein Python-Interpreter erforderlich ist. Um py2exe verwenden zu können, müssen Sie zunächst ein Kompilierungsskript schreiben und dann das Kompilierungsskript über Python ausführen, um andere Skripts in ausführbare Dateien zu kompilieren. Das folgende Beispiel ist ein Skript, das in eine ausführbare Datei kompiliert wird: Dateiname: setup.py

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

Neben dem Import der notwendigen Module gibt es in setup.py nur eine Anweisung:

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

Die eckigen Klammern geben den Namen des zu kompilierenden Skripts an, und die Fenster davor bedeuten, dass es in ein GUI-Programm kompiliert wird. Wenn Sie eine ausführbare Datei für die Befehlszeilenschnittstelle kompilieren möchten, ändern Sie einfach Windows in die Konsole. Wenn Sie das Skript in einen Windows-Dienst kompilieren müssen, können Sie die Service-Option verwenden.
Nachdem Sie alles bearbeitet haben, legen Sie wxTest.py und setup.py im selben Pfad ab, geben Sie den Pfad mit cmd ein und geben Sie Folgendes ein:

setup.py py2exe

Wenn beim Ausführen der folgende Fehler auftritt:
error: MSVCP90.dll: No such file or directory
Das liegt daran, dass MSVCP90.dll nicht gefunden wurde. Suchen Sie im Windows-Verzeichnis nach der Datei MSVCP90.dll und kopieren Sie sie dann in die DLLs im Python-Installationsverzeichnis.
Beim Packen eines PyQt-Projekts wird möglicherweise der folgende Fehler gemeldet
ImportError: No module named sip
Zu diesem Zeitpunkt müssen Sie beim Verpacken nur --includes sip hinzufügen, z. B.:
setup.py py2exe --includes sip

Nach der Ausführung werden im Pfad zwei Verzeichnisse, dist und build, generiert. Das Verzeichnis dist enthält die durch die Kompilierung generierten Dateien. Wenn Sie das kompilierte Programm auf anderen Computern ausführen möchten, auf denen Python nicht installiert ist, kopieren Sie einfach das Verzeichnis dist auf andere Computer. Doppelklicken Sie, um wxTest.exe auszuführen, wie in der Abbildung gezeigt:

2016711164500179.jpg (300×300)

Verwenden Sie wxPython, um ein GUI-Tool zur Berechnung der Datei md5 zu erstellen
Das Gadget sieht schließlich so aus. Ziehen Sie die Datei darauf und ihr MD5 und ihre Größe werden automatisch berechnet

2016711164609816.png (443×334)

Das Folgende ist der vollständige Code

#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()

Eine kleine Erklärung:

Klasse App und App().MainLoop() sind feste Schreibmethoden. Unter der Klasse App gibt es eine definierte OnInit-Methode, um den Hauptrahmen zu initialisieren, ihn zu zentrieren und ihn anzuzeigen die Rahmendefinition

Dieses Gadget verwendet boxSizer für das Layout. Der Einfachheit halber verwende ich nur einen boxSizer und ordne alle darin enthaltenen Steuerelemente VERTIKAL (vertikal) an. Wenn Sie MD5 und das folgende Textfeld in dasselbe einfügen möchten, ist dies der Fall. Dann müssen Sie einen horizontalen BoxSizer hinzufügen und diesen horizontalen BoxSizer dann in den Haupt-BoxSizer einfügen

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))



Das Obige dient dazu, den entsprechenden statischen Text und das Textfeld zu initialisieren. Der erste Parameter in der Methode ist das Fenster der übergeordneten Klasse, nämlich self.panel. Tatsächlich können Sie das Panel nicht verwenden, sondern direkt einfügen der boxSizer
boxSizer.Add(filepath,0,wx.EXPAND|wx.LEFT|wx.TOP,border=10) 

Dateipfad zum Haupt-BoxSizer hinzufügen Ich war zunächst etwas verwirrt. Zuerst dachte ich, ich würde zuerst alle Steuerelemente in das Panel einfügen und dann das Panel in den BoxSizer einfügen, aber das ist falsch. , sollte aber direkt in den boxSizer eingegeben werden, setzen Sie die übergeordnete Klasse des Steuerelements auf Panel, und dann ist es nicht erforderlich, das Panel in den boxSizer einzufügen. Der Parameter wx.LEFT|wx.TOP, border=10 repräsentiert das Steuerelement 10 Pixel von oben und links entfernt ist, und dann wx.EXPAND verwenden, um den Bereich, in dem es sich befindet, vollständig auszufüllen. Ich habe einmal darüber nachgedacht, ob es auf 10 Pixel von oben und 20 Pixel von links eingestellt werden könnte, aber es scheint so Es kann nicht auf diese Weise festgelegt werden. Es kann nur einen Randparameter in der Funktion geben. Mit anderen Worten, ich werde sehen, ob er später implementiert werden kann.

boxSizer.Add((-1,20)) #这个是添加一个空距离,距离上20px

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

Dies dient dazu, der Fensterklasse eine Drag-and-Drop-Methode hinzuzufügen, was ebenfalls eine relativ feste Schreibweise ist

Die Methoden __init__ und OnDropFiles in der obigen Klasse FileDropTarget sind ebenfalls feste Methoden, aber die Verarbeitungsfunktionen darin sind unterschiedlich.

Einige Stil- und Flag-Parameter in wxPython erfordern einige Erfahrung im Layout, ebenso wie viele seiner Steuerelemente und Methoden, um sie kompetent zu beherrschen. Die folgenden beiden Websites sind detaillierter , bitte lesen Sie mehr

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn