Wxpython learning notes of recommended view
- 2020-04-02 13:44:18
- OfStack
A list,
WxPython is a GUI toolkit for the Python programming language. It makes it easy for Python programmers to create programs with robust, powerful graphical user interfaces. It is the Python language's binding to the popular wxWidgets cross-platform GUI library. WxWidgets is written in C++. Like the Python language and the wxWidgets GUI library, wxPython is open source software. This means that anyone can use it for free and can view and modify its source code, or contribute patches and add features. WxPython is cross-platform. This means that the same program can run unmodified on multiple platforms. The platforms supported today are 32-bit Microsoft Windows, most Unix or unix-like systems, and apple Mac OS X. With Python as the programming language, wxPython is easy to write and easy to understand.
Two, basic use
I don't need to repeat the basic use words to this address is already very detailed, I don't need to repeat:
(link: http://wiki.wxpython.org/Getting%20Started)
Common controls
1. The menu (menu)
(link: http://wiki.wxpython.org/Getting%20Started#head-33e6dc36df2a89db146142e9a97b6e36b956875f)
This east east USES quite troublesome, consult the following page:
(link: http://wiki.wxpython.org/Getting%20Started#head-7455553d71be4fad208480dffd53b7c68da1a982)
(link: http://purpen.javaeye.com/blog/92130)
(link: http://purpen.javaeye.com/blog/92313)
3. Tab notebook
(link: http://wiki.wxpython.org/Getting%20Started#head-b20d2fc488722cdb3f6193150293d1e118734db8)
This control is more powerful and one of my favorite controls to use. It's in chapter 13 of the wxpythoninon (if you want the electronic version and the source code, ask me)
Here is a simple usage provided in list_report.py:
import wx
import sys, glob, random
import data
class DemoFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1,
"wx.ListCtrl in wx.LC_REPORT mode",
size=(600,400))
il = wx.ImageList(16,16, True)
for name in glob.glob("smicon??.png"):
bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
il_max = il.Add(bmp)
self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)
# Add some columns
for col, text in enumerate(data.columns):
self.list.InsertColumn(col, text)
# add the rows
for item in data.rows:
index = self.list.InsertStringItem(sys.maxint, item[0])
for col, text in enumerate(item[1:]):
self.list.SetStringItem(index, col+1, text)
# give each item a random image
img = random.randint(0, il_max)
self.list.SetItemImage(index, img, img)
# set the width of the columns in various ways
self.list.SetColumnWidth(0, 120)
self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)
app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()
For the ListCtrl control, a few things I'll add are:
1. How to get the selected item?
The most common method is to get the first Item selected: GetFirstSelected(), which returns an int, the ID of the Item (Item) in ListCtrl.
Another method is GetNextSelected(itemid), which gets the first selected item after the specified itemid, and also returns the itemid.
With these two methods, we can iterate over all the selected items:
GetNextSelecteditemid = self.list.GetFirstSelected()
while itemid <> -1:
#Do something
itemid = self.list.GetNextSelected(itemid)
If you want to get the value of a row or a column, use the following method:
# For the first 0 Ok, the first 1 The value of the column
itemtext = self.list.GetItem(0, 1).Text
2. How to add right-click menu after selected item?
In the function with the following event binding added:
Self. List.Bind(wx.evt_context_menu, self.OnContextMenu) then add the OnContextMenu method:
def OnContextMenu(self, event):
if not hasattr(self, "popupStop"):
self.popupStop = wx.NewId()
self.popupPropery = wx.NewId()
self.Bind(wx.EVT_MENU, self.OnPopupStop, id = self.popupStop)
self.Bind(wx.EVT_MENU, self.OnPopupProperty, id = self.popupPropery)
# Create a menu
menu = wx.Menu()
itemStop = wx.MenuItem(menu, self.popupStop, "Stop")
itemProperty = wx.MenuItem(menu, self.popupPropery, 'Property')
menu.AppendItem(itemStop)
menu.AppendItem(itemProperty)
itemProperty.Enable(False)# By default, the property button becomes invalid
if itemid == -1:# If nothing is selected
itemStop.Enable(False)
else:
itemStop.Enable(False)
itemProperty.Enable(True)
# That's where the menu pops up
self.PopupMenu(menu)
# Finally, notice the destruction of the previously created menu
menu.Destroy()
5. Select the FileDialog
Very simple to use:
dlg = wx.FileDialog(self,
message="Yes, select a place ",
wildcard="PNG(*.png)|*.png" ,
style=wx.SAVE
)
savefile = ''
if dlg.ShowModal() == wx.ID_OK:
savefile = dlg.GetPath()
try:
os.remove(self.filename)
except:
pass
self.img.SaveFile(savefile, wx.BITMAP_TYPE_PNG)
self.filename = savefile
dlg.Destroy()
6. Select folder dialog box
dialog = wx.DirDialog(None, 'Choose a directory: ',
style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
if dialog.ShowModal() == wx.ID_OK:
for itemid in range(self.list.GetItemCount()):
self.savechart(itemid, graphpath)
dialog.Destroy()
Four, some skills
1. Set shortcut keys
For example, if you want to press F5 to perform an operation, you can use the following method with the function of s/s:
acceltbl = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_F5, self.btnrun.GetId())])
self.SetAcceleratorTable(acceltbl)
Another very common situation is to press the ESC key to close a window. As we know, a very simple way is to use the SetId(wx.id_cancel) method, such as:
self.btncancel = wx.Button(self.panel1, -1, 'Cancel', wx.Point(380, 280))
self.btncancel.SetId(wx.ID_CANCEL)
This will close the current Dialog when the ESC key is pressed, note! In this case, Dialog, which is a window object inherited from wx.dialog, does not seem to work with SetId for wx.frame.
2. Use a timer timer
There is an example of this in chapter 18 of wxpythonina-which is as follows:
import wx
import time
class ClockWindow(wx.Window):
def __init__(self, parent):
wx.Window.__init__(self, parent)
self.Bind(wx.EVT_PAINT, self.OnPaint)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(1000)
def Draw(self, dc):
t = time.localtime(time.time())
st = time.strftime("%I:%M:%S", t)
w, h = self.GetClientSize()
dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
dc.Clear()
dc.SetFont(wx.Font(30, wx.SWISS, wx.NORMAL, wx.NORMAL))
tw, th = dc.GetTextExtent(st)
dc.DrawText(st, (w-tw)/2, (h)/2 - th/2)
def OnTimer(self, evt):
dc = wx.BufferedDC(wx.ClientDC(self))
self.Draw(dc)
def OnPaint(self, evt):
dc = wx.BufferedPaintDC(self)
self.Draw(dc)
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="wx.Timer")
ClockWindow(self)
app = wx.PySimpleApp()
frm = MyFrame()
frm.Show()
app.MainLoop()
3. What you must know when using multithreading: wx.callafter
In particular, when writing multithreading cases in wxpython, you must use wx.callafter to notify the window object in the thread to update its status. The same example from chapter 18:
import wx
import threading
import random
class WorkerThread(threading.Thread):
"""
This just simulates some long-running task that periodically sends
a message to the GUI thread.
"""
def __init__(self, threadNum, window):
threading.Thread.__init__(self)
self.threadNum = threadNum
self.window = window
self.timeToQuit = threading.Event()
self.timeToQuit.clear()
self.messageCount = random.randint(10,20)
self.messageDelay = 0.1 + 2.0 * random.random()
def stop(self):
self.timeToQuit.set()
def run(self):
msg = "Thread %d iterating %d times with a delay of %1.4fn"
% (self.threadNum, self.messageCount, self.messageDelay)
wx.CallAfter(self.window.LogMessage, msg)
for i in range(1, self.messageCount+1):
self.timeToQuit.wait(self.messageDelay)
if self.timeToQuit.isSet():
break
msg = "Message %d from thread %dn" % (i, self.threadNum)
wx.CallAfter(self.window.LogMessage, msg)
else:
wx.CallAfter(self.window.ThreadFinished, self)
class MyFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Multi-threaded GUI")
self.threads = []
self.count = 0
panel = wx.Panel(self)
startBtn = wx.Button(panel, -1, "Start a thread")
stopBtn = wx.Button(panel, -1, "Stop all threads")
self.tc = wx.StaticText(panel, -1, "Worker Threads: 00")
self.log = wx.TextCtrl(panel, -1, "",
style=wx.TE_RICH|wx.TE_MULTILINE)
inner = wx.BoxSizer(wx.HORIZONTAL)
inner.Add(startBtn, 0, wx.RIGHT, 15)
inner.Add(stopBtn, 0, wx.RIGHT, 15)
inner.Add(self.tc, 0, wx.ALIGN_CENTER_VERTICAL)
main = wx.BoxSizer(wx.VERTICAL)
main.Add(inner, 0, wx.ALL, 5)
main.Add(self.log, 1, wx.EXPAND|wx.ALL, 5)
panel.SetSizer(main)
self.Bind(wx.EVT_BUTTON, self.OnStartButton, startBtn)
self.Bind(wx.EVT_BUTTON, self.OnStopButton, stopBtn)
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
self.UpdateCount()
def OnStartButton(self, evt):
self.count += 1
thread = WorkerThread(self.count, self)
self.threads.append(thread)
self.UpdateCount()
thread.start()
def OnStopButton(self, evt):
self.StopThreads()
self.UpdateCount()
def OnCloseWindow(self, evt):
self.StopThreads()
self.Destroy()
def StopThreads(self):
while self.threads:
thread = self.threads[0]
thread.stop()
self.threads.remove(thread)
def UpdateCount(self):
self.tc.SetLabel("Worker Threads: %d" % len(self.threads))
def LogMessage(self, msg):
self.log.AppendText(msg)
def ThreadFinished(self, thread):
self.threads.remove(thread)
self.UpdateCount()
app = wx.PySimpleApp()
frm = MyFrame()
frm.Show()
app.MainLoop()
4. Need to launch another GUI program in the program without losing focus on the main window?
In general, we have no problem calling os.popen to run other external programs. But in wxpython, wx will lose focus, even if the program that has to be opened becomes a modal dialog. To solve this problem, use the method that comes with wx, wx.execute.
wx.Execute('notepad')
V. learning resources
1. The official: (link: http://wiki.wxpython.org/FrontPage)
2. The WIKI: woodpeckers (link: http://wiki.woodpecker.org.cn/moin/WxPythonInAction)
Author: CoderZh
Reference: http://coderzh.cnblogs.com