Cross platform GUI Tool library , The more famous one is GTK+、Qt and wxWidgets 了 .GTK+ yes C Realized , because C Language itself does not support OOP, thus GTK+ It's quite difficult to get started , It is also complicated and difficult to write .Qt and wxWidgets It is C++ Realized , Each has a huge user base . Although I like it wxWidgets, But I collected as objectively as possible about Qt and wxWidgets A comparative evaluation of .
About LICENSE
Qt Originally from Finland TrollTech Company R & D , It was sold to Nokia( No mistake , Nokia, the famous mobile phone giant ),2012 year Digia From Nokia QT Technology platform and intellectual property rights of .QT It's been backed by commercial companies , It pursues double license Strategy , One is the commercial version , One is the free version . This strategy severely limits Qt Users of . It is said that Nokia After the acquisition, I realized the problem , since 4.5 After the release, the LGPL, Developers can publish based on free Qt Library's commercial software .wxWidgets It started with Edinburgh (Edinburgh) Developed by the College of artificial intelligence application in University , stay 1992 In open source , Always follow LGPL.wxWidgets From the beginning, it was a free lunch for programmers .
About compatibility
because Qt The use of right and wrong standards C++, Compatibility with other libraries can be problematic , The graphical interface on each platform is not entirely native ( Native GUI), Just through theme To simulate the standards on the system GUI, So it looks like , In some places, the flaw is obvious . Qt The slow and large execution of is another problem .wxWidgets Using standards C++, Seamless connection with various existing tool Libraries , It's also completely... On different platforms Native GUI, It's really cross platform .2019 year 11 month 4 Day after day : Net friend donwmufromdying A reminder ,Qt There is no compatibility issue at present . To avoid misleading , This is the explanation .
About service and support
because Nokia The connection of ,Qt Provides a complete set of documentation and RAD Tools , And provide the most complete platform support , The most perfect support for mobile terminals .Qt The library is all GUI The most object-oriented tool library , It's also the most stable .wxWidgets Because of the lack of good commercial support , Developing documents 、 Resources are relatively scarce . Because of the emphasis on consideration MFC Cross platform migration of programs ,wxWidgets The encapsulation is not good enough .
wxWidgets The subject of is by C++ Built , But you don't have to pass C++ To use it .wxWidgets There are many other language bindings (binding), such as wxPerl,wxJava,wxBasic,wxJavaScript,wxRuby wait ,wxPython Namely Python Linguistic wxWidgets Tool library .
Whether it's py2 still py3,python Installation has become very simple in the world of . If you work in windows platform , I suggest installing at the same time pywin32 modular .pywin32 Allow you to look like VC Same use python Development win32 application , what's more , We can use it directly to control win32 Program , Capture the current window 、 Get focus, etc .
pip install wxpyhton
Only 5 Line code , We can create a window program . But it is of no damn use , It's just another manifestation of python It's just sharp and concise .
import wx
app = wx.App()
frame = wx.Frame(None, -1, "Hello, World!")
frame.Show(True)
app.MainLoop()
Here is a really practical window program framework , Any window program can be developed on this basis . Please note that , The code uses an icon file , If you want to run this code , Please help yourself. icon file .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
APP_TITLE = u' Basic framework '
APP_ICON = 'res/python.ico' # Please replace it with yours icon
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
def __init__(self):
''' Constructors '''
wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
# Default style It's a combination of the following :wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((800, 600))
self.Center()
# The following code handles icons
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
# You can add various types of controls below
pass
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame()
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp(redirect=True, filename="debug.txt")
app.MainLoop()
By inheritance wx.Frame, We constructed mainFrame class , Can be in mainFrame Add any panel to the constructor of the class 、 Text 、 picture 、 Various controls and so on .
differ Qt Signal and slot mechanism of ,wx Using the event driven programming mechanism . The so-called event , It's what happens when our program is running . Events can be low-level user actions , Such as moving the mouse or pressing the key , It can also be advanced user actions ( It's defined in wxPython In the widget of ), For example, click the button or menu selection . Events can be generated from the system , Such as shutdown . You can even create your own objects to generate your own events . The event triggers the corresponding behavior , The event function . The programmer's job is to define event functions , And the relationship between binding events and event functions .
stay wxPython in , I'm used to dividing events into 4 class :
in fact , This classification method is not rigorous enough . such as ,wx.frame As a control , Closing and resizing are also control events , However, this kind of event is usually bound by the system . Based on this , I can redefine what I call control events , Refers to what happens on a control 、 Events that the system does not predefine behavior .
The following example shows how to define event functions , And the relationship between binding events and event functions .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
APP_TITLE = u' Control events 、 Mouse events 、 Keyboard events 、 system event '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((520, 220))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
wx.StaticText(self, -1, u' The first line of input box :', pos=(40, 50), size=(100, -1), style=wx.ALIGN_RIGHT)
wx.StaticText(self, -1, u' The second line of input box :', pos=(40, 80), size=(100, -1), style=wx.ALIGN_RIGHT)
self.tip = wx.StaticText(self, -1, u'', pos=(145, 110), size=(150, -1), style=wx.ST_NO_AUTORESIZE)
self.tc1 = wx.TextCtrl(self, -1, '', pos=(145, 50), size=(150, -1), name='TC01', style=wx.TE_CENTER)
self.tc2 = wx.TextCtrl(self, -1, '', pos=(145, 80), size=(150, -1), name='TC02', style=wx.TE_PASSWORD|wx.ALIGN_RIGHT)
btn_mea = wx.Button(self, -1, u' Left mouse button event ', pos=(350, 50), size=(100, 25))
btn_meb = wx.Button(self, -1, u' Mouse all events ', pos=(350, 80), size=(100, 25))
btn_close = wx.Button(self, -1, u' close window ', pos=(350, 110), size=(100, 25))
# Control events
self.tc1.Bind(wx.EVT_TEXT, self.EvtText)
self.tc2.Bind(wx.EVT_TEXT, self.EvtText)
self.Bind(wx.EVT_BUTTON, self.OnClose, btn_close)
# Mouse events
btn_mea.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
btn_mea.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
btn_mea.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
btn_meb.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
# Keyboard events
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
# system event
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Bind(wx.EVT_SIZE, self.On_size)
#self.Bind(wx.EVT_PAINT, self.On_paint)
#self.Bind(wx.EVT_ERASE_BACKGROUND, lambda event: None)
def EvtText(self, evt):
''' Input function event box '''
obj = evt.GetEventObject()
objName = obj.GetName()
text = evt.GetString()
if objName == 'TC01':
self.tc2.SetValue(text)
elif objName == 'TC02':
self.tc1.SetValue(text)
def On_size(self, evt):
''' Change window size event function '''
self.Refresh()
evt.Skip() # Experience the effect
def OnClose(self, evt):
''' Close window event function '''
dlg = wx.MessageDialog(None, u' Are you sure you want to close this window ?', u' Operation hint ', wx.YES_NO | wx.ICON_QUESTION)
if(dlg.ShowModal() == wx.ID_YES):
self.Destroy()
def OnLeftDown(self, evt):
''' Left click the event function '''
self.tip.SetLabel(u' Left key press ')
def OnLeftUp(self, evt):
''' Left click to pop up the event function '''
self.tip.SetLabel(u' Click pop-up ')
def OnMouseWheel(self, evt):
''' Mouse wheel event function '''
vector = evt.GetWheelRotation()
self.tip.SetLabel(str(vector))
def OnMouse(self, evt):
''' Mouse event function '''
self.tip.SetLabel(str(evt.EventType))
def OnKeyDown(self, evt):
''' Keyboard event function '''
key = evt.GetKeyCode()
self.tip.SetLabel(str(key))
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
Two input fields , A plaintext is centered , A cipher right Qi , But the content is always in sync . When the input focus is not in the input box , Tap the keyboard , The interface displays the corresponding key value . The top button responds to the press and bounce of the left mouse button , The middle button responds to all mouse events , The button below responds to the event that the button was pressed . in addition , The program also binds the window closing event , Redefined the close function , Added confirmation options .
Usually , A complete window program generally has a menu bar 、 Toolbar and status bar . The following code demonstrates how to create a menu bar 、 Toolbar and status bar , By the way, it demonstrates the definition and usage of static properties of a class . however , Tell the truth ,wx The toolbar is a little ugly , fortunately ,wx One more AUI The toolbar is more beautiful , I'll demonstrate its usage in the following examples .
in addition , Please note that , The code uses 4 individual 16x16 Tool button for , Please help yourself. 4 A picture file , To save the path, please check the comments in the code .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
APP_TITLE = u' menu 、 The toolbar 、 status bar '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
id_open = wx.NewId()
id_save = wx.NewId()
id_quit = wx.NewId()
id_help = wx.NewId()
id_about = wx.NewId()
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((800, 600))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
self.Maximize()
self.SetWindowStyle(wx.DEFAULT_FRAME_STYLE)
self._CreateMenuBar() # menu bar
self._CreateToolBar() # The toolbar
self._CreateStatusBar() # status bar
def _CreateMenuBar(self):
''' Create menu bar '''
self.mb = wx.MenuBar()
# File menu
m = wx.Menu()
m.Append(self.id_open, u" Open file ")
m.Append(self.id_save, u" Save the file ")
m.AppendSeparator()
m.Append(self.id_quit, u" Exit the system ")
self.mb.Append(m, u" file ")
self.Bind(wx.EVT_MENU, self.OnOpen, id=self.id_open)
self.Bind(wx.EVT_MENU, self.OnSave, id=self.id_save)
self.Bind(wx.EVT_MENU, self.OnQuit, id=self.id_quit)
# In the help menu
m = wx.Menu()
m.Append(self.id_help, u" Help topics ")
m.Append(self.id_about, u" About ...")
self.mb.Append(m, u" help ")
self.Bind(wx.EVT_MENU, self.OnHelp,id=self.id_help)
self.Bind(wx.EVT_MENU, self.OnAbout,id=self.id_about)
self.SetMenuBar(self.mb)
def _CreateToolBar(self):
''' Create toolbars '''
bmp_open = wx.Bitmap('res/open_16.png', wx.BITMAP_TYPE_ANY) # Please bring your own picture of the button
bmp_save = wx.Bitmap('res/save_16.png', wx.BITMAP_TYPE_ANY) # Please bring your own picture of the button
bmp_help = wx.Bitmap('res/help_16.png', wx.BITMAP_TYPE_ANY) # Please bring your own picture of the button
bmp_about = wx.Bitmap('res/about_16.png', wx.BITMAP_TYPE_ANY) # Please bring your own picture of the button
self.tb = wx.ToolBar(self)
self.tb.SetToolBitmapSize((16,16))
self.tb.AddLabelTool(self.id_open, u' Open file ', bmp_open, shortHelp=u' open ', longHelp=u' Open file ')
self.tb.AddLabelTool(self.id_save, u' Save the file ', bmp_save, shortHelp=u' preservation ', longHelp=u' Save the file ')
self.tb.AddSeparator()
self.tb.AddLabelTool(self.id_help, u' help ', bmp_help, shortHelp=u' help ', longHelp=u' help ')
self.tb.AddLabelTool(self.id_about, u' About ', bmp_about, shortHelp=u' About ', longHelp=u' About ...')
#self.Bind(wx.EVT_TOOL_RCLICKED, self.OnOpen, id=self.id_open)
self.tb.Realize()
def _CreateStatusBar(self):
''' Create status bar '''
self.sb = self.CreateStatusBar()
self.sb.SetFieldsCount(3)
self.sb.SetStatusWidths([-2, -1, -1])
self.sb.SetStatusStyles([wx.SB_RAISED, wx.SB_RAISED, wx.SB_RAISED])
self.sb.SetStatusText(u' State information 0', 0)
self.sb.SetStatusText(u'', 1)
self.sb.SetStatusText(u' State information 2', 2)
def OnOpen(self, evt):
''' Open file '''
self.sb.SetStatusText(u' Open file ', 1)
def OnSave(self, evt):
''' Save the file '''
self.sb.SetStatusText(u' Save the file ', 1)
def OnQuit(self, evt):
''' Exit the system '''
self.sb.SetStatusText(u' Exit the system ', 1)
self.Destroy()
def OnHelp(self, evt):
''' help '''
self.sb.SetStatusText(u' help ', 1)
def OnAbout(self, evt):
''' About '''
self.sb.SetStatusText(u' About ', 1)
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
stay “ Events and event driven ” In the case of , Input box 、 The layout of controls such as buttons , Absolute positioning is used , I used to call it static layout . The static layout is very intuitive , But it doesn't automatically adapt to the size of the window . More time , We use what's called the layout manager wx.Sizer To achieve dynamic layout .wx.Sizer There are many kinds of , I can't remember , So I just like to use wx.BoxSizer, The simplest layout manager .
Different from general controls , The layout manager is like a magic pocket : It's invisible , But you can load an unlimited number of any kind of controls —— Including other layout managers . Of course , Magic bags are not everything , It has one limitation : What's in it , Or it's horizontal , Either it's vertical , You can't square up . Fortunately, programmers can use magic pockets freely , When we need to square up , You can use a magic bag for each line first , And then put all the lines in a magic bag .
Create a magic pocket , Put in a few things , And then the pseudo code displayed in the window looks like this :
Magic pocket = wx.BoxSizer() # The default is horizontal , Want to put things vertically , Need to add wx.VERTICAL This parameter
Magic pocket .add( confirm button , 0, wx.ALL, 0) # Load confirm button
Magic pocket .add( Cancel button , 0, wx.ALL, 0) # Load cancel button
window .SetSizer( Magic pocket ) # Put the magic bag on the window
window .Layout() # Window rearrangement
Magic pocket add() There are a total of 4 Parameters : The first 1 The parameters are easy to understand , It's something to put in your pocket ; The first 2 Parameters and all add() Methods the first 2 The ratio of the sum of the parameters , Indicates the proportion of space occupied by items packed into the pocket ,0 It means that the size of the item takes up as much space as possible , No extra space ; The first 3 Parameters are relatively complicated , In addition to the horizontal and vertical alignment of the items in the pocket in the space they occupy , You can also specify white space in one or more of the four directions (padding); The first 4 One parameter is the number of pixels left blank .
Here is a complete example .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
APP_TITLE = u' Dynamic layout '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(240, 240, 240))
self.SetSize((800, 600))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
preview = wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
preview.SetBackgroundColour(wx.Colour(0, 0, 0))
btn_capture = wx.Button(self, -1, u' Taking pictures ', size=(100, -1))
btn_up = wx.Button(self, -1, u'↑', size=(30, 30))
btn_down = wx.Button(self, -1, u'↓', size=(30, 30))
btn_left = wx.Button(self, -1, u'←', size=(30, 30))
btn_right = wx.Button(self, -1, u'→', size=(30, 30))
tc = wx.TextCtrl(self, -1, '', style=wx.TE_MULTILINE)
sizer_arrow_mid = wx.BoxSizer()
sizer_arrow_mid.Add(btn_left, 0, wx.RIGHT, 16)
sizer_arrow_mid.Add(btn_right, 0, wx.LEFT, 16)
#sizer_arrow = wx.BoxSizer(wx.VERTICAL)
sizer_arrow = wx.StaticBoxSizer(wx.StaticBox(self, -1, u' Direction key '), wx.VERTICAL)
sizer_arrow.Add(btn_up, 0, wx.ALIGN_CENTER|wx.ALL, 0)
sizer_arrow.Add(sizer_arrow_mid, 0, wx.TOP|wx.BOTTOM, 1)
sizer_arrow.Add(btn_down, 0, wx.ALIGN_CENTER|wx.ALL, 0)
sizer_right = wx.BoxSizer(wx.VERTICAL)
sizer_right.Add(btn_capture, 0, wx.ALL, 20)
sizer_right.Add(sizer_arrow, 0, wx.ALIGN_CENTER|wx.ALL, 0)
sizer_right.Add(tc, 1, wx.ALL, 10)
sizer_max = wx.BoxSizer()
sizer_max.Add(preview, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
sizer_max.Add(sizer_right, 0, wx.EXPAND|wx.ALL, 0)
self.SetAutoLayout(True)
self.SetSizer(sizer_max)
self.Layout()
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
Advanced User Interface, abbreviation AUI, yes wxPython Sub module of , Use AUI You can easily develop beautiful 、 Easy to use user interface . from 2.8.9.2 After the version ,wxPython Added an advanced common parts library Advanced Generic Widgets, abbreviation AGW library . I'll start with AGW The library also provides AUI modular wx.lib.agw.aui, and wx.aui And it's still there .
AUI The layout can be summarized as the following four steps :
The following code shows how to use AUI Layout manager creates and manages window interfaces .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
import wx.lib.agw.aui as aui
APP_TITLE = u' Use AUI Layout manager '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
id_open = wx.NewId()
id_save = wx.NewId()
id_quit = wx.NewId()
id_help = wx.NewId()
id_about = wx.NewId()
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((800, 600))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
self.tb1 = self._CreateToolBar()
self.tb2 = self._CreateToolBar()
self.tbv = self._CreateToolBar('V')
p_left = wx.Panel(self, -1)
p_center0 = wx.Panel(self, -1)
p_center1 = wx.Panel(self, -1)
p_bottom = wx.Panel(self, -1)
btn = wx.Button(p_left, -1, u' Switch ', pos=(30,200), size=(100, -1))
btn.Bind(wx.EVT_BUTTON, self.OnSwitch)
text0 = wx.StaticText(p_center0, -1, u' I am the first 1 page ', pos=(40, 100), size=(200, -1), style=wx.ALIGN_LEFT)
text1 = wx.StaticText(p_center1, -1, u' I am the first 2 page ', pos=(40, 100), size=(200, -1), style=wx.ALIGN_LEFT)
self._mgr = aui.AuiManager()
self._mgr.SetManagedWindow(self)
self._mgr.AddPane(self.tb1,
aui.AuiPaneInfo().Name("ToolBar1").Caption(u" Toolbars ").ToolbarPane().Top().Row(0).Position(0).Floatable(False)
)
self._mgr.AddPane(self.tb2,
aui.AuiPaneInfo().Name("ToolBar2").Caption(u" Toolbars ").ToolbarPane().Top().Row(0).Position(1).Floatable(True)
)
self._mgr.AddPane(self.tbv,
aui.AuiPaneInfo().Name("ToolBarV").Caption(u" Toolbars ").ToolbarPane().Right().Floatable(True)
)
self._mgr.AddPane(p_left,
aui.AuiPaneInfo().Name("LeftPanel").Left().Layer(1).MinSize((200,-1)).Caption(u" Operation area ").MinimizeButton(True).MaximizeButton(True).CloseButton(True)
)
self._mgr.AddPane(p_center0,
aui.AuiPaneInfo().Name("CenterPanel0").CenterPane().Show()
)
self._mgr.AddPane(p_center1,
aui.AuiPaneInfo().Name("CenterPanel1").CenterPane().Hide()
)
self._mgr.AddPane(p_bottom,
aui.AuiPaneInfo().Name("BottomPanel").Bottom().MinSize((-1,100)).Caption(u" Message area ").CaptionVisible(False).Resizable(True)
)
self._mgr.Update()
def _CreateToolBar(self, d='H'):
''' Create toolbars '''
bmp_open = wx.Bitmap('res/open_16.png', wx.BITMAP_TYPE_ANY)
bmp_save = wx.Bitmap('res/save_16.png', wx.BITMAP_TYPE_ANY)
bmp_help = wx.Bitmap('res/help_16.png', wx.BITMAP_TYPE_ANY)
bmp_about = wx.Bitmap('res/about_16.png', wx.BITMAP_TYPE_ANY)
if d.upper() in ['V', 'VERTICAL']:
tb = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, agwStyle=aui.AUI_TB_TEXT|aui.AUI_TB_VERTICAL)
else:
tb = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, agwStyle=aui.AUI_TB_TEXT)
tb.SetToolBitmapSize(wx.Size(16, 16))
tb.AddSimpleTool(self.id_open, u' open ', bmp_open, u' Open file ')
tb.AddSimpleTool(self.id_save, u' preservation ', bmp_save, u' Save the file ')
tb.AddSeparator()
tb.AddSimpleTool(self.id_help, u' help ', bmp_help, u' help ')
tb.AddSimpleTool(self.id_about, u' About ', bmp_about, u' About ')
tb.Realize()
return tb
def OnSwitch(self, evt):
''' Switch information display window '''
p0 = self._mgr.GetPane('CenterPanel0')
p1 = self._mgr.GetPane('CenterPanel1')
p0.Show(not p0.IsShown())
p1.Show(not p1.IsShown())
self._mgr.Update()
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
DC yes Device Context Abbreviation , It literally means device context —— I've never been able to understand DC This Chinese name , There's no better way to put it , therefore , I insist on using DC Not device context .DC You can draw points, lines and surfaces on the screen , Of course, you can also draw text and images . in fact , At the bottom, all controls are drawn as bitmaps on the screen , It means , Once we have mastered DC This tool , We can create our own controls .
DC There are many kinds of ,PaintDC,ClientDC,MemoryDC etc. . Usually , We can use ClientDC and MemoryDC,PaintDC It's a redraw event (wx.EVT_PAINT) When the system uses . Use ClientDC When drawing , Every step of the drawing needs to be recorded , Otherwise , When the system is redrawn, we'll lose everything we've done —— This is the use of DC The easiest mistake to make .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os
APP_TITLE = u' Use DC mapping '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((800, 600))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
self.palette = wx.Panel(self, -1, style=wx.SUNKEN_BORDER)
self.palette.SetBackgroundColour(wx.Colour(0, 0, 0))
btn_base = wx.Button(self, -1, u' The basic method ', size=(100, -1))
sizer_max = wx.BoxSizer()
sizer_max.Add(self.palette, 1, wx.EXPAND|wx.LEFT|wx.TOP|wx.BOTTOM, 5)
sizer_max.Add(btn_base, 0, wx.ALL, 20)
self.SetAutoLayout(True)
self.SetSizer(sizer_max)
self.Layout()
btn_base.Bind(wx.EVT_BUTTON, self.OnBase)
self.palette.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse)
self.palette.Bind(wx.EVT_PAINT, self.OnPaint)
self.xy = None
self.lines = list()
self.img = wx.Bitmap('res/times.png', wx.BITMAP_TYPE_ANY)
self.ReDraw()
def OnMouse(self, evt):
''' Move the mouse to draw lines '''
if evt.EventType == 10032: # Left key press ,py3 In the environment 10030
self.xy = (evt.x, evt.y)
elif evt.EventType == 10033: # Click pop-up ,py3 In the environment 10031
self.xy = None
elif evt.EventType == 10038: # Mouse movement ,py3 In the environment 10036
if self.xy:
dc = wx.ClientDC(self.palette)
dc.SetPen(wx.Pen(wx.Colour(0,224,0), 2))
dc.DrawLine(self.xy[0], self.xy[1], evt.x, evt.y)
self.lines.append((self.xy[0], self.xy[1], evt.x, evt.y))
self.xy = (evt.x, evt.y)
def OnBase(self, evt):
'''DC Basic method demonstration '''
img = wx.Bitmap('res/times.png', wx.BITMAP_TYPE_ANY)
w, h = self.palette.GetSize()
dc = wx.ClientDC(self.palette)
dc.SetPen(wx.Pen(wx.Colour(224,0,0), 1))
dc.SetBrush(wx.Brush(wx.Colour(0,80,80) ))
dc.DrawRectangle(10,10,w-22,h-22)
dc.DrawLine(10,h/2,w-12,h/2)
dc.DrawBitmap(img, 50, 50)
dc.SetTextForeground(wx.Colour(224,224,224))
dc.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, 'Comic Sans MS'))
dc.DrawText(u' Frost heavy leisure sorrow ', 100, 500)
dc.DrawRotatedText(u' The deep spring wind is also sick ', 250, 500, 30)
def OnPaint(self, evt):
''' Redraw event functions '''
dc = wx.PaintDC(self.palette)
self.Paint(dc)
def ReDraw(self):
''' Hand drawn '''
dc = wx.ClientDC(self.palette)
self.Paint(dc)
def Paint(self, dc):
''' mapping '''
w, h = self.palette.GetSize()
dc.Clear()
dc.SetPen(wx.Pen(wx.Colour(224,0,0), 1))
dc.SetBrush(wx.Brush(wx.Colour(0,80,80) ))
dc.DrawRectangle(10,10,w-22,h-22)
dc.DrawLine(10,h/2,w-12,h/2)
dc.DrawBitmap(self.img, 50, 50)
dc.SetTextForeground(wx.Colour(224,224,224))
dc.SetFont(wx.Font(16, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, 'Comic Sans MS'))
dc.DrawText(u' Frost heavy leisure sorrow ', 100, 500)
dc.DrawRotatedText(u' The deep spring wind is also sick ', 250, 500, 30)
dc.SetPen(wx.Pen(wx.Colour(0,224,0), 2))
for line in self.lines:
dc.DrawLine(line[0],line[1],line[2],line[3])
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
In this example, a digital clock is designed , A stopwatch , The stopwatch shows an accuracy of one tenth of a millisecond . There is no difficulty in code design , There are many ways to do this , Can want to achieve a better display effect , But it's not an easy thing . Please pay attention to experience wx.CallAfter() Conditions of use .
#-*- coding: utf-8 -*-
import wx
import win32api
import sys, os, time
import threading
APP_TITLE = u' Timers and threads '
APP_ICON = 'res/python.ico'
class mainFrame(wx.Frame):
''' Program main window class , Inherited from wx.Frame'''
def __init__(self, parent):
''' Constructors '''
wx.Frame.__init__(self, parent, -1, APP_TITLE)
self.SetBackgroundColour(wx.Colour(224, 224, 224))
self.SetSize((320, 300))
self.Center()
if hasattr(sys, "frozen") and getattr(sys, "frozen") == "windows_exe":
exeName = win32api.GetModuleFileName(win32api.GetModuleHandle(None))
icon = wx.Icon(exeName, wx.BITMAP_TYPE_ICO)
else :
icon = wx.Icon(APP_ICON, wx.BITMAP_TYPE_ICO)
self.SetIcon(icon)
#font = wx.Font(24, wx.DECORATIVE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, 'Comic Sans MS')
font = wx.Font(30, wx.DECORATIVE, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL, False, 'Monaco')
self.clock = wx.StaticText(self, -1, u'08:00:00', pos=(50,50), size=(200,50), style=wx.TE_CENTER|wx.SUNKEN_BORDER)
self.clock.SetForegroundColour(wx.Colour(0, 224, 32))
self.clock.SetBackgroundColour(wx.Colour(0, 0, 0))
self.clock.SetFont(font)
self.stopwatch = wx.StaticText(self, -1, u'0:00:00.0', pos=(50,150), size=(200,50), style=wx.TE_CENTER|wx.SUNKEN_BORDER)
self.stopwatch.SetForegroundColour(wx.Colour(0, 224, 32))
self.stopwatch.SetBackgroundColour(wx.Colour(0, 0, 0))
self.stopwatch.SetFont(font)
self.timer = wx.Timer(self)
self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
self.timer.Start(50)
self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
self.sec_last = None
self.is_start = False
self.t_start = None
thread_sw = threading.Thread(target=self.StopWatchThread)
thread_sw.setDaemon(True)
thread_sw.start()
def OnTimer(self, evt):
''' Timer Functions '''
t = time.localtime()
if t.tm_sec != self.sec_last:
self.clock.SetLabel('%02d:%02d:%02d'%(t.tm_hour, t.tm_min, t.tm_sec))
self.sec_last = t.tm_sec
def OnKeyDown(self, evt):
''' Keyboard event function '''
if evt.GetKeyCode() == wx.WXK_SPACE:
self.is_start = not self.is_start
self.t_start= time.time()
elif evt.GetKeyCode() == wx.WXK_ESCAPE:
self.is_start = False
self.stopwatch.SetLabel('0:00:00.0')
def StopWatchThread(self):
''' Thread functions '''
while True:
if self.is_start:
n = int(10*(time.time() - self.t_start))
deci = n%10
ss = int(n/10)%60
mm = int(n/600)%60
hh = int(n/36000)
wx.CallAfter(self.stopwatch.SetLabel, '%d:%02d:%02d.%d'%(hh, mm, ss, deci))
time.sleep(0.02)
class mainApp(wx.App):
def OnInit(self):
self.SetAppName(APP_TITLE)
self.Frame = mainFrame(None)
self.Frame.Show()
return True
if __name__ == "__main__":
app = mainApp()
app.MainLoop()
Recently, a lot of friends have consulted through private letters about Python Learning problems . To facilitate communication , I am here CSDN Of app Created on “Python Homework guidance ” stronghold , oriented Python beginner , Provide consulting services for you 、 Coach Python Homework . Welcome interested students to use wechat code scanning to join .
From blogs to official account , Every article 、 Every question 、 Every sentence 、 Every line of code , All insist on originality , Never copy , This is my principle . If you like , Please pay attention to my WeChat official account “Python Homework counselor ”.