Học wxPython – hướng dẫn nhanh Làm dự án nhận lương – Trung tâm đào tạo Toidayhoc

Học wxPython – hướng dẫn nhanh Làm dự án nhận lương

wxPython – Quick Guide



wxPython là một trình bao bọc Python cho wxWidgets (được viết bằng C++), một bộ công cụ GUI đa nền tảng phổ biến. Được phát triển bởi Robin Dunn cùng với Harri Pasanen, wxPython được triển khai dưới dạng một mô-đun mở rộng Python. Giống như wxWidgets, wxPython cũng là một phần mềm miễn phí. Bạn có thể tải xuống từ trang web chính thức. Có thể tải xuống các tệp nhị phân và mã nguồn cho nhiều nền tảng hệ điều hành trên trang web này. Các mô-đun chính trong API wxPython bao gồm một mô-đun cốt lõi. Mô-đun này bao gồm lớp wxObject, là cơ sở cho tất cả các lớp trong API. Mô-đun điều khiển chứa tất cả các tiện ích được sử dụng trong phát triển ứng dụng GUI. Ví dụ: wx.Button, wx.StaticText (tương tự như nhãn), wx.TextCtrl (điều khiển văn bản có thể chỉnh sửa), v.v. API wxPython có mô-đun GDI (Giao diện thiết bị đồ họa). Đây là một tập hợp các lớp được sử dụng để vẽ trên các tiện ích. Các lớp như phông chữ, màu sắc, cọ vẽ, v.v. là một phần của nó. Tất cả các lớp cửa sổ chứa đều được định nghĩa trong mô-đun Windows. Trang web chính thức của wxPython cũng lưu trữ Project Phoenix – một triển khai mới của wxPython cho Python 3.*. Nó tập trung vào việc cải thiện tốc độ, khả năng bảo trì và khả năng mở rộng. Dự án bắt đầu vào năm 2012 và vẫn đang trong giai đoạn beta.

wxPython – Environment

Windows

Prebuilt binaries for Windows OS (both 32 bit and 64 bit) are available on page. Latest versions of installers available are − for 32-bit Python 2.7 for 64-bit Python 2.7

wxPython demo, samples and wxWidgets documentation is also available for download on the same page.

Linux

wxPython binaries for many Linux distros can be found in their respective repositories. Corresponding package managers will have to be used to download and install. For instance on Debian Linux, following command should be able to install wxPython.

sudo apt-get install python-wxgtk3.0

MacOS

Prebuilt binaries for MacOS in the form of disk images are available on the download page of the official website.

wxPython – Hello World

A simple GUI application displaying Hello World message is built using the following steps −

  • Import wx module.
  • Define an object of Application class.
  • Create a top level window as object of wx.Frame class. Caption and size parameters are given in constructor.
  • Although other controls can be added in Frame object, their layout cannot be managed. Hence, put a Panel object into the Frame.
  • Add a StaticText object to display ‘Hello World’ at a desired position inside the window.
  • Activate the frame window by show() method.
  • Enter the main event loop of Application object.
import wx 
 
app = wx.App() 
window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 
panel = wx.Panel(window) 
label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 
window.Show(True) 
app.MainLoop()

The above code produces the following output −

Hello World

wxFrame object is the most commonly employed top level window. It is derived from wxWindow class. A frame is a window whose size and position can be changed by the user. It has a title bar and control buttons. If required, other components like menu bar, toolbar and status bar can be enabled. A wxFrame window can contain any frame that is not a dialog or another frame.

wxPython – GUI Builder Tools

Creating a good looking GUI by manual coding can be tedious. A visual GUI designer tool is always handy. Many GUI development IDEs targeted at wxPython are available. Following are some of them −

  • wxFormBuilder
  • wxDesigner
  • wxGlade
  • BoaConstructor
  • gui2py

wxFormBuilder is an open source, cross-platform WYSIWYG GUI builder that can translate the wxWidget GUI design into C++, Python, PHP or XML format. A brief introduction to usage of wxFormBuilder is given here.

First of all the latest version of wxFormBuilder needs to be downloaded and installed from On opening the application, a new project with blank grey area at the center appears.

Give a suitable name to the project and choose Python as code generation language. This is done in the Object properties window as shown in the following image −

Object Properties

Then from ‘Forms’ tab of components palette, choose Frame.

Choose Frame

Add a vertical wxBoxSizer from ‘Layouts’ tab.

Add wxBoxSizer

Add necessary controls in the Box with suitable captions. Here, a StaticText (label), two TextCtrl objects (text boxes) and a wxButton object are added. The frame looks like the following image −

Add Controls

Enable Expand and Stretch on these three controls. In the object properties for wxButton object, assign a function findsquare() to OnButtonClick event.

Three Controls

Save the project and press F8 to generate Python code for developed GUI. Let the generated file be named as Demo.py

In the executable Python script, import demo.py and define FindSquare() function. Declare Application object and start a main event loop. Following is the executable code −

import wx 
  
#import the newly created GUI file 
import demo  
class CalcFrame(demo.MyFrame1): 
   def __init__(self,parent): 
      demo.MyFrame1.__init__(self,parent)  
		
   def FindSquare(self,event): 
      num = int(self.m_textCtrl1.GetValue()) 
      self.m_textCtrl2.SetValue (str(num*num)) 
        
app = wx.App(False) 
frame = CalcFrame(None) 
frame.Show(True) 
#start the applications 
app.MainLoop() 

The above code produces the following output −

GUI Builder Output

wxPython – Major Classes

Original wxWidgets (written in C++) is a huge class library. GUI classes from this library are ported to Python with wxPython module, which tries to mirror the original wxWidgets library as close as possible. So, wx.Frame class in wxPython acts much in the same way as wxFrame class in its C++ version.

wxObject is the base for most of the classes. An object of wxApp (wx.App in wxPython) represents the application itself. After generating the GUI, application enters in an event loop by MainLoop() method. Following diagrams depict the class hierarchy of most commonly used GUI classes included in wxPython.

wxWindow Hierarchy wxGDIObject Hierarchy wxSizer Hierarchy wxButton Hierarchy

S.N. Classes & Description
1 wx.Frame Class has a default constructor with no arguments.
2 wx.Panel class is usually put inside a wxFrame object. This class is also inherited from wxWindow class.
3 wx.StaticText class object presents a control holding such read-only text. It can be termed as a passive control since it doesn’t produce any event.
4 In wxPython, an object of wx.TextCtrl class serves this purpose. It is a control in which the text can be displayed and edited.
5 Each button, an object of wx.RadioButton class carries a text label next to a round button. wxPython API also consists of wx.RadioBox class. Its object offers a border and label to the group.
6 A checkbox displays a small labeled rectangular box. When clicked, a checkmark appears inside the rectangle to indicate that a choice is made.
7 A wx.ComboBox object presents a list of items to select from. It can be configured to be a dropdown list or with permanent display. wxPython API contains a wx.Choice class, whose object is also a dropdown list, which is permanently read-only.
8 Wx.Gauge class object shows a vertical or horizontal bar, which graphically shows incrementing quantity.
9 wxPython API contains wx.Slider class. It offers same functionality as that of Scrollbar. Slider offers a convenient way to handle dragging the handle by slider specific wx.EVT_SLIDER event binder.
10 A horizontal bar just below the title bar of a top level window is reserved to display a series of menus. It is an object of wx.MenuBar class in wxPython API.
11 If the style parameter of wx.Toolbar object is set to wx.TB_DOCKABLE, it becomes dockable. A floating toolbar can also be constructed using wxPython’s AUIToolBar class.
12 Although a Dialog class object appears like a Frame, it is normally used as a pop-up window on top of a parent frame. The objective of a Dialog is to collect some data from the user and send it to the parent frame.
13 wx.Notebook widget presents a tabbed control. One Notebook object in a frame has one or more tabs (called Pages), each of them having a panel showing the layout of controls.
14 Object of this class is a layout manager, which holds two subwindows whose size can be changed dynamically by dragging the boundaries between them. The Splitter control gives a handle that can be dragged to resize the controls.
15 wxHTML library contains classes for parsing and displaying HTML content. Although this is not intended to be a full-featured browser, wx.HtmlWindow object is a generic HTML viewer.
16 A wx.ListBox widget presents a vertically scrollable list of strings. By default, a single item in the list is selectable. ListCtrl widget is a highly enhanced list display and selection tool. List of more than one column can be displayed in Report view, List view or Icon view.

wxPython – Event Handling

Unlike a console mode application, which is executed in a sequential manner, a GUI based application is event driven. Functions or methods are executed in response to user’s actions like clicking a button, selecting an item from collection or mouse click, etc., called events.

Data pertaining to an event which takes place during the application’s runtime is stored as object of a subclass derived from wx.Event. A display control (such as Button) is the source of event of a particular type and produces an object of Event class associated to it. For instance, click of a button emits a wx.CommandEvent. This event data is dispatched to event handler method in the program. wxPython has many predefined event binders. An Event binder encapsulates relationship between a specific widget (control), its associated event type and the event handler method.

For example, to call OnClick() method of the program on a button’s click event, the following statement is required −

self.b1.Bind(EVT_BUTTON, OnClick)

Bind() method is inherited by all display objects from wx.EvtHandler class. EVT_.BUTTON here is the binder, which associates button click event to OnClick() method.

Example

In the following example, the MoveEvent, caused by dragging the top level window – a wx.Frame object in this case – is connected to OnMove() method using wx.EVT_MOVE binder. The code displays a window. If it is moved using mouse, its instantaneous coordinates are displayed on the console.

import wx
  
class Example(wx.Frame): 
            
   def __init__(self, *args, **kw): 
      super(Example, self).__init__(*args, **kw)  
      self.InitUI() 
           
   def InitUI(self): 
      self.Bind(wx.EVT_MOVE, self.OnMove) 
      self.SetSize((250, 180)) 
      self.SetTitle(''Move event'') 
      self.Centre() 
      self.Show(True)
		   
   def OnMove(self, e): 
      x, y = e.GetPosition() 
      print "current window position x = ",x," y= ",y 
         
ex = wx.App() 
Example(None) 
ex.MainLoop()   

The above code produces the following output −

Move Event

current window position x = 562 y = 309

current window position x = 562 y = 309

current window position x = 326 y = 304

current window position x = 384 y = 240

current window position x = 173 y = 408

current window position x = 226 y = 30

current window position x = 481 y = 80

Some of the subclasses inherited from wx.Event are listed in the following table −

S.N. Events & Description
1 wxKeyEvent

Occurs when a key is presses or released

2 wxPaintEvent

Is generated whenever contents of the window needs to be redrawn

3 wxMouseEvent

Contains data about any event due to mouse activity like mouse button pressed or dragged

4 wxScrollEvent

Associated with scrollable controls like wxScrollbar and wxSlider

5 wxCommandEvent

Contains event data originating from many widgets such as button, dialogs, clipboard, etc.

6 wxMenuEvent

Different menu-related events excluding menu command button click

7 wxColourPickerEvent

wxColourPickerCtrl generated events

8 wxDirFilePickerEvent

Events generated by FileDialog and DirDialog

Events in wxPython are of two types. Basic events and Command events. A basic event stays local to the window in which it originates. Most of the wxWidgets generate command events. A command event can be propagated to window or windows, which are above the source window in class hierarchy.

Example

Following is a simple example of event propagation. The complete code is −

import wx
  
class MyPanel(wx.Panel): 
     
   def __init__(self, parent): 
      super(MyPanel, self).__init__(parent)
		
      b = wx.Button(self, label = ''Btn'', pos = (100,100)) 
      b.Bind(wx.EVT_BUTTON, self.btnclk) 
      self.Bind(wx.EVT_BUTTON, self.OnButtonClicked) 
		
   def OnButtonClicked(self, e): 
         
      print ''Panel received click event. propagated to Frame class'' 
      e.Skip()  
		
   def btnclk(self,e): 
      print "Button received click event. propagated to Panel class" 
      e.Skip()
		
class Example(wx.Frame):

   def __init__(self,parent): 
      super(Example, self).__init__(parent)  
         
      self.InitUI() 

   def InitUI(self):
	
      mpnl = MyPanel(self) 
      self.Bind(wx.EVT_BUTTON, self.OnButtonClicked)
		
      self.SetTitle(''Event propagation demo'') 
      self.Centre() 
      self.Show(True)
		
   def OnButtonClicked(self, e): 
         
      print ''click event received by frame class'' 
      e.Skip()
		
ex = wx.App() 
Example(None) 
ex.MainLoop()

In the above code, there are two classes. MyPanel, a wx.Panel subclass and Example, a wx.Frame subclass which is the top level window for the program. A button is placed in the panel.

This Button object is bound to an event handler btnclk() which propagates it to parent class (MyPanel in this case). Button click generates a CommandEvent which can be propagated to its parent by Skip() method.

MyPanel class object also binds the received event to another handler OnButtonClicked(). This function in turn transmits to its parent, the Example class. The above code produces the following output −

Event Handling Output

Button received click event. Propagated to Panel class. 
Panel received click event. Propagated to Frame class. 
Click event received by frame class.

wxPython – Layout Management

A GUI widget can be placed inside the container window by specifying its absolute coordinates measured in pixels. The coordinates are relative to the dimensions of the window defined by size argument of its constructor. Position of the widget inside the window is defined by pos argument of its constructor.

import wx  

app = wx.App() 
window = wx.Frame(None, title = "wxPython Frame", size = (300,200)) 
panel = wx.Panel(window) 
label = wx.StaticText(panel, label = "Hello World", pos = (100,50)) 
window.Show(True) 
app.MainLoop()

This Absolute Positioning however is not suitable because of the following reasons −

  • The position of the widget does not change even if the window is resized.
  • The appearance may not be uniform on different display devices with different resolutions.
  • Modification in the layout is difficult as it may need redesigning the entire form.

wxPython API provides Layout classes for more elegant management of positioning of widgets inside the container. The advantages of Layout managers over absolute positioning are −

  • Widgets inside the window are automatically resized.
  • Ensures uniform appearance on display devices with different resolutions.
  • Adding or removing widgets dynamically is possible without having to redesign.

Layout manager is called Sizer in wxPython. Wx.Sizer is the base class for all sizer subclasses. Let us discuss some of the important sizers such as wx.BoxSizer, wx.StaticBoxSizer, wx.GridSizer, wx.FlexGridSizer, and wx.GridBagSizer.

S.N. Sizers & Description
1 This sizer allows the controls to be arranged in row-wise or column-wise manner. BoxSizer’s layout is determined by its orientation argument (either wxVERTICAL or wxHORIZONTAL).
2 As the name suggests, a GridSizer object presents a two dimensional grid. Controls are added in the grid slot in the left-to-right and top-to-bottom order.
3 This sizer also has a two dimensional grid. However, it provides little more flexibility in laying out the controls in the cells.
4 GridBagSizer is a versatile sizer. It offers more enhancements than FlexiGridSizer. Child widget can be added to a specific cell within the grid.
5 A StaticBoxSizer puts a box sizer into a static box. It provides a border around the box along with a label at the top.

wxPython – Buttons

Button widget is most widely used in any GUI interface. It captures the click event generated by the user. Its most obvious use is to trigger a handler function bound to it.

wxPython class library provides different types of buttons. There is a simple, traditional button, wx.Button class object, which carries some text as its caption. A two-state button is also available, which is named as wx.ToggleButton. Its pressed or depressed state can be identified by eventhandler function.

Another type of button, wx.BitmapButton displays a bitmap (image) as icon on its face.

Constructor for wx.Button class and wx.ToggleButton class takes the following arguments −

Wx.Button(parent, id, label, pos, size, style)

These are some important methods of wx.Button class −

S.N. Methods & Description
1 SetLabel()

Sets the button’s caption programmatically

2 GetLabel()

Returns the button’s caption

3 SetDefault()

Button is set to default for the top level window. Emulates the click event on pressing Enter key

Two important methods of wx.ToggleButton class are −

S.N. Methods & Description
1 GetValue()

Returns the state of toggle button (on/off)

2 SetValue()

Sets the state of button programmatically

In order to create a bitmap button, firstly, a bitmap object needs to be constructed out of an image file.

The following variation of wx.Bitmap class constructor is most commonly used −

Wx.Bitmap(fiiename, wx.BITMAP_TYPE)

Some of the predefined bitmap type constants are −

wx.BITMAP_TYPE_BMP
wx.BITMAP_TYPE_ICO
wx.BITMAP_TYPE_CUR
wx.BITMAP_TYPE_TIFF
wx.BITMAP_TYPE_TIF
wx.BITMAP_TYPE_GIF
wx.BITMAP_TYPE_PNG
wx.BITMAP_TYPE_JPEG
wx.BITMAP_TYPE_PCX
wx.BITMAP_TYPE_ICON
wx.BITMAP_TYPE_ANY

This bitmap object is used as one of the parameters for wx.BitmapButton class constructor.

Wx.BitmapButton(parent, id, bitmap, pos, size, style)

On some OS platforms, the bitmap button can display both bitmap and label. SetLabel() methods assign the caption. On other platforms, it serves as an internal label.

The normal button as well bitmap button emits a wx.CommandEvent. EVT_BUTTON binder associates a handler function to it.

The toggle button on the other hand uses wx.TOGGLEBUTTON binder for event handling.

In the following example, buttons of all three types are placed in a vertical box sizer of a panel.

Simple button object is created using the statement −

self.btn = wx.Button(panel, -1, "click Me")

Toggle button is constructed by following statement −

self.tbtn = wx.ToggleButton(panel , -1, "click to on")

These buttons are added into vertical sizer using the following statements −

vbox.Add(self.btn,0,wx.ALIGN_CENTER) 
vbox.Add(self.tbtn,0,wx.EXPAND|wx.ALIGN_CENTER)

Note − Because of wx.EXPAND flag, the toggle button occupies the entire width of the frame.

Using EVT_BUTTON and EVT_TOGGLEBUTTON binders they are associated with the respective handlers.

self.btn.Bind(wx.EVT_BUTTON,self.OnClicked) 
self.tbtn.Bind(wx.EVT_TOGGLEBUTTON,self.OnToggle)

Three bitmap buttons are added into a horizontal box sizer. These buttons display an image as icon as their caption.

bmp = wx.Bitmap("NEW.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
  
bmp1 = wx.Bitmap("OPEN.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn1 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp1,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
  
bmp2 = wx.Bitmap("SAVE.BMP", wx.BITMAP_TYPE_BMP) 
self.bmpbtn2 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp2,
   size = (bmp.GetWidth()+10, bmp.GetHeight()+10))

Click event of these three buttons is directed to OnClicked() method.

self.bmpbtn.Bind(wx.EVT_BUTTON, self.OnClicked) 
self.bmpbtn1.Bind(wx.EVT_BUTTON, self.OnClicked) 
self.bmpbtn2.Bind(wx.EVT_BUTTON, self.OnClicked)

Internal labels of these buttons are set to NEW, OPEN and SAVE respectively.

OnClicked() event handler function retrieves the label of source button, which caused the click event. That label is printed on the console.

def OnClicked(self, event): 
   btn = event.GetEventObject().GetLabel() 
   print "Label of pressed button = ",btn 

OnToggle() event handler is triggered when the toggle button is clicked. Its state is read by GetValue() method and accordingly, the button’s caption is set.

def OnToggle(self,event): 
   state = event.GetEventObject().GetValue() 
   if state == True: 
      print "off" 
      event.GetEventObject().SetLabel("click to off") 
   else: 
      print "on" 
      event.GetEventObject().SetLabel("click to on")

The complete code listing is as follows −

import wx 
class Mywin(wx.Frame): 
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (200,150))  
      panel = wx.Panel(self) 
      vbox = wx.BoxSizer(wx.VERTICAL) 
         
      self.btn = wx.Button(panel,-1,"click Me") 
      vbox.Add(self.btn,0,wx.ALIGN_CENTER) 
      self.btn.Bind(wx.EVT_BUTTON,self.OnClicked) 
         
      self.tbtn = wx.ToggleButton(panel , -1, "click to on") 
      vbox.Add(self.tbtn,0,wx.EXPAND|wx.ALIGN_CENTER) 
      self.tbtn.Bind(wx.EVT_TOGGLEBUTTON,self.OnToggle) 
         
      hbox = wx.BoxSizer(wx.HORIZONTAL) 
         
      bmp = wx.Bitmap("NEW.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10)) 
			
      hbox.Add(self.bmpbtn,0,wx.ALIGN_CENTER) 
      self.bmpbtn.Bind(wx.EVT_BUTTON,self.OnClicked) 
      self.bmpbtn.SetLabel("NEW") 
         
      bmp1 = wx.Bitmap("OPEN.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn1 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp1,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10)) 
			
      hbox.Add(self.bmpbtn1,0,wx.ALIGN_CENTER) 
      self.bmpbtn1.Bind(wx.EVT_BUTTON,self.OnClicked) 
      self.bmpbtn1.SetLabel("OPEN") 
         
      bmp2 = wx.Bitmap("SAVE.BMP", wx.BITMAP_TYPE_BMP) 
      self.bmpbtn2 = wx.BitmapButton(panel, id = wx.ID_ANY, bitmap = bmp2,
         size = (bmp.GetWidth()+10, bmp.GetHeight()+10))
			
      hbox.Add(self.bmpbtn2,0,wx.ALIGN_CENTER) 
      self.bmpbtn2.Bind(wx.EVT_BUTTON,self.OnClicked)
      self.bmpbtn2.SetLabel("SAVE") 
         
      vbox.Add(hbox,1,wx.ALIGN_CENTER) 
      panel.SetSizer(vbox) 
        
      self.Centre() 
      self.Show() 
      self.Fit()  
		
   def OnClicked(self, event): 
      btn = event.GetEventObject().GetLabel() 
      print "Label of pressed button = ",btn 
		
   def OnToggle(self,event): 
      state = event.GetEventObject().GetValue() 
		
      if state == True: 
         print "Toggle button state off" 
         event.GetEventObject().SetLabel("click to off") 
      else: 
         print " Toggle button state on" 
         event.GetEventObject().SetLabel("click to on") 
             
app = wx.App() 
Mywin(None,  ''Button demo'') 
app.MainLoop()

The above code produces the following output −

Buttons Output

Label of pressed button = click Me

Toggle button state off

Toggle button state on

Label of pressed button = NEW

Label of pressed button = OPEN

Label of pressed button = SAVE

wxPython – Dockable Windows

wxAui is an Advanced User Interface library incorporated in wxWidgets API. Wx.aui.AuiManager the central class in AUI framework.

AuiManager manages the panes associated with a particular frame using each panel’s information in wx.aui.AuiPanelInfo object. Let us learn about various properties of PanelInfo object control docking and floating behavior.

Putting dockable windows in the top level frame involves the following steps −

First, create an AuiManager object.

self.mgr = wx.aui.AuiManager(self)

Then, a panel with required controls is designed.

pnl = wx.Panel(self) 
pbox = wx.BoxSizer(wx.HORIZONTAL) 
text1 = wx.TextCtrl(pnl, -1, "Dockable", style = wx.NO_BORDER | wx.TE_MULTILINE) 
pbox.Add(text1, 1, flag = wx.EXPAND) 
pnl.SetSizer(pbox)

The following parameters of AuiPanelInfo are set.

  • Direction − Top, Bottom, Left, Right, or Center
  • Position − More than one pane can be placed inside a dockable region. Each is given a position number.
  • Row − More than one pane appears in one row. Just like more than one toolbar appearing in the same row.
  • Layer − Panes can be placed in layers.

Using this PanelInfo, the designed panel is added into the manager object.

info1 = wx.aui.AuiPaneInfo().Bottom() 
self.mgr.AddPane(pnl,info1)

Rest of the top level window may have other controls as usual.

The complete code is as follows −

import wx 
import wx.aui
  
class Mywin(wx.Frame):
  
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title, size = (300,300)) 
		
      self.mgr = wx.aui.AuiManager(self)
		
      pnl = wx.Panel(self) 
      pbox = wx.BoxSizer(wx.HORIZONTAL)
      text1 = wx.TextCtrl(pnl, -1, "Dockable", style = wx.NO_BORDER | wx.TE_MULTILINE) 
      pbox.Add(text1, 1, flag = wx.EXPAND) 
      pnl.SetSizer(pbox) 
         
      info1 = wx.aui.AuiPaneInfo().Bottom() 
      self.mgr.AddPane(pnl, info1) 
      panel = wx.Panel(self) 
      text2 = wx.TextCtrl(panel, size = (300,200), style =  wx.NO_BORDER | wx.TE_MULTILINE) 
      box = wx.BoxSizer(wx.HORIZONTAL) 
      box.Add(text2, 1, flag = wx.EXPAND) 
         
      panel.SetSizerAndFit(box) 
      self.mgr.Update() 
		
      self.Bind(wx.EVT_CLOSE, self.OnClose) 
      self.Centre() 
      self.Show(True) 
		
   def OnClose(self, event): 
      self.mgr.UnInit() 
      self.Destroy() 
		
app = wx.App()
Mywin(None,"Dock Demo")  
app.MainLoop()

The above code produces the following output −

Dock Demo

wxPython – Multiple Document Interface

A typical GUI application may have multiple windows. Tabbed and stacked widgets allow to activate one such window at a time. However, many a times this approach may not be useful as view of other windows is hidden.

One way to display multiple windows simultaneously is to create them as independent windows. This is called as SDI (Single Document Interface). This requires more memory resources as each window may have its own menu system, toolbar, etc.

MDI framework in wxPython provides a wx.MDIParentFrame class. Its object acts as a container for multiple child windows, each an object of wx.MDIChildFrame class.

Child windows reside in the MDIClientWindow area of the parent frame. As soon as a child frame is added, the menu bar of the parent frame shows a Window menu containing buttons to arrange the children in a cascaded or tiled manner.

Example

The following example illustrates the uses of MDIParentFrame as top level window. A Menu button called NewWindow adds a child window in the client area. Multiple windows can be added and then arranged in a cascaded or tiled order.

The complete code is as follows −

import wx 
 
class MDIFrame(wx.MDIParentFrame): 
   def __init__(self): 
      wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", size = (600,400)) 
      menu = wx.Menu() 
      menu.Append(5000, "&New Window") 
      menu.Append(5001, "&Exit") 
      menubar = wx.MenuBar() 
      menubar.Append(menu, "&File") 
		
      self.SetMenuBar(menubar) 
      self.Bind(wx.EVT_MENU, self.OnNewWindow, id = 5000) 
      self.Bind(wx.EVT_MENU, self.OnExit, id = 5001) 
		
   def OnExit(self, evt): 
      self.Close(True)  
		
   def OnNewWindow(self, evt): 
      win = wx.MDIChildFrame(self, -1, "Child Window")
      win.Show(True) 
		
app = wx.App() 
frame = MDIFrame() 
frame.Show() 
app.MainLoop()

The above code produces the following output −

MDI output

wxPython – Drawing API

GDI+ (Graphics Drawing Interface), CoreGraphics and Cairo libraries form the framework of drawing API in wxPython. wx.GraphicsContext is the primary drawable object, using which various Device Context objects are created.

wx.DC is an abstract class. Its derived classes are used to render graphics and text on different devices. The Device Context classes are −

  • wx.ScreenDC − Use this to paint on the screen, as opposed to an individual window.
  • wx.ClientDC − Use this to paint on the client area of the window (the part without borders and other decorations), but do not use it from within an wxPaintEvent.
  • wx.PaintDC − Use this to paint on the client area of the window, but only from within a wxPaintEvent.
  • wx.WindowDC − Use this to paint on the whole area of the window, including decorations. This may not be available on non-Windows platforms.

Drawing API of wxPython offers different functions for drawing shape, text and image. Objects required for drawing purpose, like Colour, Pen, Brush and Font can also be constructed using GDI classes.

wx.Colour Class

Colour object represents combination of RGB (RED, Green and Blue) intensity values, each on the scale of 0-255. There are a few predefined colour objects like −

  • wxBLACK
  • wxBLUE
  • wxCYAN
  • wxGREEN
  • wxYELLOW
  • wxLIGHT_GREY
  • wxRED
  • wxWHITE

Color with custom combination of RGB values is formed as wx.Colour object.

wx.Colour(r,g,b)

wx.Pen Class

Pen object determines the colour, width and style of the shape of graphics like line, rectangle, circle etc.

Predefined Pen objects are −

wxBLACK_DASHED_PEN
wxBLACK_PEN
wxBLUE_PEN
wxCYAN_PEN
wxGREEN_PEN
wxYELLOW_PEN
wxGREY_PEN
wxLIGHT_GREY_PEN
wxMEDIUM_GREY_PEN
wxRED_PEN
wxTRANSPARENT_PEN
wxWHITE_PEN

Predefined Pen styles are −

wx.SOLID
wx.DOT
wx.LONG_DASH
wx.SHORT_DASH
wx.DOT_DASH
wx.TRANSPARENT

wx.Brush Class

Brush is another elementary graphics object required to fill the backgrounds of shapes such as rectangle, ellipse, circle etc.

A custom Brush object requires wx.Colour and Brush style parameters. The following is a list of predefined brush styles −

wx.SOLID
wx.STIPPLE
wx.BDIAGONAL_HATCH
wx.CROSSDIAG_HATCH
wx.FDIAGONAL_HATCH
wx.CROSS_HATCH
wx.HORIZONTAL_HATCH
wx.VERTICAL_HATCH
wx.TRANSPARENT

wxPython has a number of functions that facilitate drawing different shapes, text and image.

S.N. Functions & Description
1 DrawRectangle()

Draws a rectangle of given dimensions

2 DrawCircle()

Draws a circle at the given point as center and radius

3 DrawEllipse()

Draws an ellipse with the given x and y radius

4 DrawLine()

Draws a line beween two wx.Point objects

5 DrawBitmap()

Draw an image at the given position

6 DrawText()

Displays the given text at the specified position

Example

The above functions are implemented in the following example, making use of Pen, Brush, Colour and Font objects.

The complete code is as follows −

import wx 
 
class Mywin(wx.Frame): 
            
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (500,300))  
      self.InitUI() 
         
   def InitUI(self): 
      self.Bind(wx.EVT_PAINT, self.OnPaint) 
      self.Centre() 
      self.Show(True)
		
   def OnPaint(self, e): 
      dc = wx.PaintDC(self) 
      brush = wx.Brush("white")  
      dc.SetBackground(brush)  
      dc.Clear() 
        
      dc.DrawBitmap(wx.Bitmap("python.jpg"),10,10,True) 
      color = wx.Colour(255,0,0)
      b = wx.Brush(color) 
		
      dc.SetBrush(b) 
      dc.DrawCircle(300,125,50) 
      dc.SetBrush(wx.Brush(wx.Colour(255,255,255))) 
      dc.DrawCircle(300,125,30) 
		
      font = wx.Font(18, wx.ROMAN, wx.ITALIC, wx.NORMAL) 
      dc.SetFont(font) 
      dc.DrawText("Hello wxPython",200,10) 
		
      pen = wx.Pen(wx.Colour(0,0,255)) 
      dc.SetPen(pen) 
      dc.DrawLine(200,50,350,50) 
      dc.SetBrush(wx.Brush(wx.Colour(0,255,0), wx.CROSS_HATCH)) 
      dc.DrawRectangle(380, 15, 90, 60) 
		
ex = wx.App() 
Mywin(None,''Drawing demo'') 
ex.MainLoop()

The above code produces the following output −

Drawing Demo

wxPython – Drag & Drop

Provision of drag and drop is very intuitive for the user. It is found in many desktop applications where the user can copy or move objects from one window to another just by dragging it with the mouse and dropping on another window.

Drag and drop operation involves the following steps −

  • Declare a drop target
  • Create data object
  • Create wx.DropSource
  • Execute drag operation
  • Cancel or accept drop

In wxPython, there are two predefined drop targets −

  • wx.TextDropTarget
  • wx.FileDropTarget

Many wxPython widgets support drag and drop activity. Source control must have dragging enabled, whereas target control must be in a position to accept (or reject) drag.

Source Data that the user is dragging is placed on the the target object. OnDropText() of target object consumes the data. If so desired, data from the source object can be deleted.

Example

In the following example, two ListCrl objects are placed horizontally in a Box Sizer. List on the left is populated with a languages[] data. It is designated as the source of drag. One on the right is the target.

languages = [''C'', ''C++'', ''Java'', ''Python'', ''Perl'', ''JavaScript'', ''PHP'', ''VB.NET'',''C#''] 
self.lst1 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
self.lst2 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 

   for lang in languages: 
      self.lst1.InsertStringItem(0,lang)

The second list control is empty and is an argument for object of TextDropTarget class.

class MyTextDropTarget(wx.TextDropTarget):
   def __init__(self, object): 
      wx.TextDropTarget.__init__(self) 
      self.object = object
		
   def OnDropText(self, x, y, data): 
      self.object.InsertStringItem(0, data)

OnDropText() method adds source data in the target list control.

Drag operation is initialized by the event binder.

wx.EVT_LIST_BEGIN_DRAG(self, self.lst1.GetId(), self.OnDragInit)

OnDragInit() function puts drag data on the target and deletes from the source.

def OnDragInit(self, event): 
   text = self.lst1.GetItemText(event.GetIndex()) 
   tobj = wx.PyTextDataObject(text) 
   src = wx.DropSource(self.lst1) 
   src.SetData(tobj) 
   src.DoDragDrop(True) 
   self.lst1.DeleteItem(event.GetIndex())

The complete code is as follows −

import wx
  
class MyTarget(wx.TextDropTarget): 
   def __init__(self, object): 
      wx.TextDropTarget.__init__(self) 
      self.object = object  
		
   def OnDropText(self, x, y, data): 
      self.object.InsertStringItem(0, data)  
		
class Mywin(wx.Frame): 
            
   def __init__(self, parent, title): 
      super(Mywin, self).__init__(parent, title = title,size = (-1,300))   
      panel = wx.Panel(self) 
      box = wx.BoxSizer(wx.HORIZONTAL)  
      languages = [''C'', ''C++'', ''Java'', ''Python'', ''Perl'', ''JavaScript'',
         ''PHP'', ''VB.NET'',''C#'']
			
      self.lst1 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
      self.lst2 = wx.ListCtrl(panel, -1, style = wx.LC_LIST) 
      for lang in languages: 
      self.lst1.InsertStringItem(0,lang) 
             
      dt = MyTarget(self.lst2) 
      self.lst2.SetDropTarget(dt) 
      wx.EVT_LIST_BEGIN_DRAG(self, self.lst1.GetId(), self.OnDragInit)
		
      box.Add(self.lst1,0,wx.EXPAND) 
      box.Add(self.lst2, 1, wx.EXPAND) 
		
      panel.SetSizer(box) 
      panel.Fit() 
      self.Centre() 
      self.Show(True)  
     
   def OnDragInit(self, event): 
      text = self.lst1.GetItemText(event.GetIndex()) 
      tobj = wx.PyTextDataObject(text) 
      src = wx.DropSource(self.lst1) 
      src.SetData(tobj) 
      src.DoDragDrop(True) 
      self.lst1.DeleteItem(event.GetIndex()) 
		
ex = wx.App() 
Mywin(None,''Drag&Drop Demo'') 
ex.MainLoop()

The above code produces the following output −

Drag Drop Output

Vừa học vừa làm vừa nhận lương tại trung tâm Toidayhoc

Leave a Reply

Your email address will not be published. Required fields are marked *

Translate »