Wxpython 简明教程

wxPython - Quick Guide

wxPython - Introduction

wxPython 是用于 wxWidgets (用 C++ 编写)的 Python 封装程序,而 wxWidgets 是一个流行的跨平台 GUI 工具包。由 Robin Dunn 和 Harri Pasanen 开发,wxPython 被实现为一个 Python 扩展模块。

wxPython is a Python wrapper for wxWidgets (which is written in C++), a popular cross-platform GUI toolkit. Developed by Robin Dunn along with Harri Pasanen, wxPython is implemented as a Python extension module.

就像 wxWidgets 一样,wxPython 也是一款免费软件。可从官方网站 http://wxpython.org. 下载。该网站上提供了适用于多种操作系统平台的二进制文件和源代码可供下载。

Just like wxWidgets, wxPython is also a free software. It can be downloaded from the official website http://wxpython.org. Binaries and source code for many operating system platforms are available for download on this site.

wxPython API 中的主要模块包含一个核心模块。该模块由 wxObject 类组成,它是 API 中所有类的基础。控件模块包含 GUI 应用程序开发中使用到的所有小部件。例如,wx.Button、wx.StaticText(类似于标签)、wx.TextCtrl(可编辑文本控件)等。

Principal modules in wxPython API include a core module. It consists of wxObject class, which is the base for all classes in the API. Control module contains all the widgets used in GUI application development. For example, wx.Button, wx.StaticText (analogous to a label), wx.TextCtrl (editable text control), etc.

wxPython API 具有 GDI(图形设备接口)模块。它是一组用于在小部件上绘制的类。字体、颜色、画笔等类都是它的组成部分。所有容器窗口类都在 Windows 模块中定义。

wxPython API has GDI (Graphics Device Interface) module. It is a set of classes used for drawing on widgets. Classes like font, color, brush, etc. are a part of it. All the container window classes are defined in Windows module.

wxPython 的官方网站还托管着 Project Phoenix - 一种为 Python 3.* 实现的 wxPython。它专注于提高速度、可维护性和可扩展性。该项目始于 2012 年,仍处于测试阶段。

Official website of wxPython also hosts Project Phoenix – a new implementation of wxPython for Python 3.*. It focuses on improving speed, maintainability, and extensibility. The project began in 2012 and is still in beta stage.

wxPython - Environment

Windows

适用于 Windows 操作系统的(32 位和 64 位)预编译二进制文件均可在 http://www.wxpython.org/download.php 页面上获取。可用的安装程序的最新版本为: wxPython3.0-win32-3.0.2.0-py27.exe (适用于 32 位 Python 2.7) wxPython3.0-win64-3.0.2.0-py27.exe (适用于 64 位 Python 2.7)

Prebuilt binaries for Windows OS (both 32 bit and 64 bit) are available on http://www.wxpython.org/download.php page. Latest versions of installers available are − wxPython3.0-win32-3.0.2.0-py27.exe for 32-bit Python 2.7 wxPython3.0-win64-3.0.2.0-py27.exe for 64-bit Python 2.7

wxPython 演示、示例和 wxWidgets 文档还可以从同一页面下载。

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

Linux

适用于多种 Linux发行版的 wxPython 二进制文件可以在其各自的存储库中找到。需要使用相应的包管理器来下载和安装。例如,在 Debian Linux 上,以下命令应该可以安装 wxPython。

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

适用于 MacOS 的磁盘映像格式的预编译二进制文件可在官方网站的下载页面上获得。

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

wxPython - Hello World

使用以下步骤构建一个显示“Hello World”消息的简单 GUI 应用程序:

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

  1. Import wx module.

  2. Define an object of Application class.

  3. Create a top level window as object of wx.Frame class. Caption and size parameters are given in constructor.

  4. Although other controls can be added in Frame object, their layout cannot be managed. Hence, put a Panel object into the Frame.

  5. Add a StaticText object to display ‘Hello World’ at a desired position inside the window.

  6. Activate the frame window by show() method.

  7. 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 是最常用的顶级窗口。它派生自 wxWindow class 。框架是一个窗口,其大小和位置可以由用户更改。它具有标题栏和控制按钮。如果需要,还可以启用其他组件(如菜单栏、工具栏和状态栏)。wxFrame 窗口可以包含除对话框或其他框架外的任何框架。

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

通过手动编码创建出色的 GUI 可能很繁琐。一个可视化 GUI 设计器工具总是很方便的。针对 wxPython 的许多 GUI 开发 IDE 都可用。下面是其中一些 −

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 −

  1. wxFormBuilder

  2. wxDesigner

  3. wxGlade

  4. BoaConstructor

  5. gui2py

wxFormBuilder 是一个开源、跨平台的所见即所得 (WYSIWYG) GUI 构建器,可以将 wxWidget GUI 设计转换为 C++、Python、PHP 或 XML 格式。此处给出了有关 wxFormBuilder 用法的简要介绍。

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.

首先,需要从 http://sourceforge.net/projects/wxformbuilder/. 下载并安装 wxFormBuilder 的最新版本。打开应用程序后,会出现一个新项目,中间有一个空白灰色区域。

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

为项目提供一个合适的名称,并将 Python 选择为代码生成语言。这是在对象属性窗口中完成的,如下图所示 −

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

然后,从组件选板的“Forms”选项卡,选择 Frame。

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

frame

从“Layouts”选项卡添加垂直的 wxBoxSizer。

Add a vertical wxBoxSizer from ‘Layouts’ tab.

wxboxsizer

在 Box 中添加带有合适标题的必要控件。在此,添加了一个 StaticText(标签)、两个 TextCtrl 对象(文本框)和一个 wxButton 对象。框架类似于以下图片:

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

对这三个控件启用“Expand and Stretch”。在 wxButton 对象的对象属性中,为 OnButtonClick 事件指定一个函数 findsquare()。

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

three controls

保存项目并按 F8 以生成已开发 GUI 的 Python 代码。生成的代码命名为 Demo.py

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

在可执行 Python 脚本中,导入 demo.py 并定义 FindSquare() 函数。声明 Application 对象并启动一个主事件循环。以下为可执行代码:

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 −

tools output

wxPython - Major Classes

原始的 wxWidgets(用 C 语言编写)是一个庞大的类库。此库中的 GUI 类已通过 wxPython 模块移植到 Python,该模块尝试尽可能镜像原始 wxWidgets 库。因此,wxPython 中的 wx.Frame 类的作用与 C 版本中的 wxFrame 类非常相似。

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 是大多数类的基础。wxApp(wxPython 中的 wx.App)的对象表示应用程序本身。在生成 GUI 后,应用程序通过 MainLoop() 方法进入事件循环。以下图表描绘了 wxPython 中包含的最常用 GUI 类的类层次结构。

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 class hierarchy
wxgdiobject class hierarchy
wxsizer class hierarchy
wxbutton class hierarchy

S.N.

Classes & Description

1

wx.Framewx.Frame Class has a default constructor with no arguments.

2

wx.Panelwx.Panel class is usually put inside a wxFrame object. This class is also inherited from wxWindow class.

3

wx.StaticTextwx.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

TextCtrlIn wxPython, an object of wx.TextCtrl class serves this purpose. It is a control in which the text can be displayed and edited.

5

RadioButton & RadioBoxEach 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

wx.CheckBoxA checkbox displays a small labeled rectangular box. When clicked, a checkmark appears inside the rectangle to indicate that a choice is made.

7

ComboBox & Choice ClassA 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.GaugeWx.Gauge class object shows a vertical or horizontal bar, which graphically shows incrementing quantity.

9

wx.SliderwxPython 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

wx.MenuBarA 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

wx.ToolbarIf 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

Wx.DialogAlthough 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.Notebookwx.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

wx.SplitterWindowObject 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

HTMLWindowwxHTML 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

ListBox & ListCtrlA 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

与按顺序执行的控制台模式应用程序不同,基于GUI的应用程序是事件驱动的。函数或方法根据用户的动作(如单击按钮、从集合中选择项目或单击鼠标等,称为事件)执行。

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.

在应用程序运行时发生的事件相关的数据存储为从 wx.Event 派生的子类的对象。显示控件(例如按钮)是特定类型事件的源并生成与之关联的Event类对象。例如,单击按钮会发出wx.CommandEvent。此事件数据将调度给程序中的事件处理程序方法。wxPython具有许多预定义的事件绑定程序。一个 Event binder 将特定小部件(控件)、其关联的事件类型以及事件处理程序方法之间的关系封装起来。

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.

例如,要在按钮的单击事件上调用程序的 OnClick() 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 由 wx.EvtHandler 类中的所有显示对象继承。此处 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

在以下示例中,MoveEvent 由拖动顶级窗口(本例中为一个 wx.Frame 对象)而引起,使用 wx.EVT_MOVE 绑定器连接至 OnMove() method 。此代码显示一个窗口。如果使用鼠标移动窗口,其瞬时坐标将显示在控制台上。

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

当前窗口位置 x = 562 y = 309

current window position x = 562 y = 309

当前窗口位置 x = 562 y = 309

current window position x = 562 y = 309

当前窗口位置 x = 326 y = 304

current window position x = 326 y = 304

当前窗口位置 x = 384 y = 240

current window position x = 384 y = 240

当前窗口位置 x = 173 y = 408

current window position x = 173 y = 408

当前窗口位置 x = 226 y = 30

current window position x = 226 y = 30

当前窗口位置 x = 481 y = 80

current window position x = 481 y = 80

从 wx.Event 继承的一些子类在下表中列出 −

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

WxPython 中的事件有两种类型:基本事件和命令事件。基本事件只存在于其源头的窗口中。大多数 wxWidget 会生成命令事件。一个 command event 可以传播到位于类层次结构中源窗口之上的窗口。

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

在以上代码中,有两个类。 MyPanel ,一个 wx.Panel 子类和 Example,一个 wx.Frame 子类,它是该程序的顶级窗口。一个按钮放置在面板中。

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.

这个 Button 对象绑定到一个事件处理程序 btnclk(),它将事件传播到父类(在这个例子中是 MyPanel)。按钮单击会生成一个 CommandEvent , 它可以通过 Skip() 方法传播到它的父对象。

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 类对象也把接收到的事件绑定到另一个处理程序 OnButtonClicked()。该函数又依次把事件发送给它的父对象,也就是 Example 类。以上代码会产生以下输出 −

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

可以通过指定 GUI 组件在容器窗口中的绝对坐标(以像素为单位)把它放在容器窗口里面。该坐标与窗口的尺寸相关,由窗口的构造函数的 size 参数定义。组件在窗口中的位置由其构造函数的 pos 参数定义。

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

然而,这个 Absolute Positioning 由于以下原因不可行 −

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

  1. The position of the widget does not change even if the window is resized.

  2. The appearance may not be uniform on different display devices with different resolutions.

  3. Modification in the layout is difficult as it may need redesigning the entire form.

wxPython API 提供了 Layout 类来更优雅地管理容器中组件的位置。布局管理器在绝对定位方面有以下优点 −

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 −

  1. Widgets inside the window are automatically resized.

  2. Ensures uniform appearance on display devices with different resolutions.

  3. Adding or removing widgets dynamically is possible without having to redesign.

布局管理器在 wxPython 中被称为 Sizer。Wx.Sizer 是所有 sizer 子类的基类。让我们讨论一些重要的 sizer,例如 wx.BoxSizer、wx.StaticBoxSizer、wx.GridSizer、wx.FlexGridSizer 和 wx.GridBagSizer。

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

BoxSizerThis 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

GridSizerAs 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

FlexiGridSizerThis sizer also has a two dimensional grid. However, it provides little more flexibility in laying out the controls in the cells.

4

GridBagSizerGridBagSizer is a versatile sizer. It offers more enhancements than FlexiGridSizer. Child widget can be added to a specific cell within the grid.

5

StaticBoxSizerA 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

按钮组件在任何 GUI 界面中都使用最广泛。它捕获用户生成的单击事件。它最明显的使用是触发绑定到它的一个处理程序函数。

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 类库提供了不同类型的按钮。有一个简单的传统按钮, wx.Button 类对象,它的标题带有一些文本。也有一个二状态按钮,名为 wx.ToggleButton 。它的按下或松开状态可以通过事件处理程序函数来识别。

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.

另一种类型的按钮 wx.BitmapButton ,它的表面显示一个位图(图像)作为图标。

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

wx.Button 类和 wx.ToggleButton 类的构造函数接收以下参数 −

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

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

以下是 wx.Button 类的一些重要方法 −

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

wx.ToggleButton 类的两个重要方法是:

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.

以下 wx.Bitmap 类构造函数的变体最常用:

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

该位图对象用作 wx.BitmapButton 类构造函数的参数之一。

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

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

在某些操作系统平台上,位图按钮可以同时显示位图和标签。SetLabel() 方法分配标题。在其他平台上,它充当内部标签。

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.

普通按钮以及位图按钮都会发出 wx.CommandEvent。EVT_BUTTON 绑定器会将处理程序功能关联到它。

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

另一方面,切换按钮使用 wx.TOGGLEBUTTON 绑定器进行事件处理。

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 ——由于 wx.EXPAND 标志,切换按钮占据了框架的整个宽度。

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

使用 EVT_BUTTON 和 EVT_TOGGLEBUTTON 绑定器,它们与各自的处理程序相关联。

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

这三个按钮的单击事件被定向到 OnClicked() 方法。

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)

分别将这些按钮的内部标签设置为 NEW、OPEN 和 SAVE。

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

OnClicked() 事件处理函数会检索导致单击事件的源按钮的标签。该标签会打印在控制台上。

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() 事件处理函数会在单击切换按钮时触发。它的状态由 GetValue() 方法读取,按钮的标题会相应地设置。

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 是 wxWidgets API 中包含的高级用户界面库。Wx.aui.AuiManager 是 AUI 框架中的中央类。

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

AuiManager 使用 wx.aui.AuiPanelInfo 对象中的每个面板信息来管理与特定框架相关联的面板。让我们了解该 PanelInfo 对象控件停靠和浮动行为的各种属性。

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 −

首先,创建一个 AuiManager 对象。

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)

设置 AuiPanelInfo 的以下参数:

The following parameters of AuiPanelInfo are set.

  1. Direction − Top, Bottom, Left, Right, or Center

  2. Position − More than one pane can be placed inside a dockable region. Each is given a position number.

  3. Row − More than one pane appears in one row. Just like more than one toolbar appearing in the same row.

  4. Layer − Panes can be placed in layers.

使用此 PanelInfo,将设计的面板添加到管理器对象中。

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

典型的 GUI 应用程序可能有多个窗口。标签式和小部件可随时激活一个这样的窗口。但是,很多时候此方法可能没有用,因为其他窗口的视图被隐藏了。

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.

同时显示多个窗口的一种方式是将它们创建为独立的窗口。这称为 SDI ( Single Document Interface )。这样做需要更多内存资源,因为每个窗口可能都有其自己的菜单系统、工具栏等。

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.

wxPython 中的 MDI 框架提供了一个 wx.MDIParentFrame 类。其对象用作多个子窗口的容器,每个都是 wx.MDIChildFrame 类的对象。

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.

子窗口位于父框架的 MDIClientWindow 区域中。一旦添加一个子框架,父框架的菜单栏就会显示一个窗口菜单,其中包含按钮以级联或平铺方式排列子窗口。

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

以下示例说明了 MDIParentFrame 作为顶级窗口的用法。名为 NewWindow 的菜单按钮会在客户端区域添加一个子窗口。可以添加多个窗口,然后以级联或平铺顺序排列。

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 + (图形绘制界面)、 CoreGraphicsCairo libraries 构成了 wxPython 中绘制 API 的框架。wx.GraphicsContext 是主要的绘图对象,使用它可以创建各种设备上下文对象。

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 是一个抽象类。它的派生类用于在不同设备上渲染图形和文本。设备上下文类为 -

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

  1. wx.ScreenDC − Use this to paint on the screen, as opposed to an individual window.

  2. 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.

  3. wx.PaintDC − Use this to paint on the client area of the window, but only from within a wxPaintEvent.

  4. wx.WindowDC − Use this to paint on the whole area of the window, including decorations. This may not be available on non-Windows platforms.

wxPython 绘图 API 提供用于绘制形状、文本和图像的不同函数。用于绘制目的的对象(比如颜色、笔、画笔和字体)也可以使用 GDI 类进行构建。

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

Color 对象表示 RGB(红、绿和蓝)强度值的组合,每个都在 0-255 的范围内。有一些预定义的颜色对象,例如:

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 −

  1. wxBLACK

  2. wxBLUE

  3. wxCYAN

  4. wxGREEN

  5. wxYELLOW

  6. wxLIGHT_GREY

  7. wxRED

  8. wxWHITE

以 RGB 值自定义组合形成颜色 为 wx.Colour object

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

wx.Colour(r,g,b)

wx.Pen Class

Pen 对象决定图形形状的颜色、宽度和样式,如线、矩形、圆形等。

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

Predefined Pen objects 为:

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 为:

Predefined Pen styles are −

wx.SOLID

wx.DOT

wx.LONG_DASH

wx.SHORT_DASH

wx.DOT_DASH

wx.TRANSPARENT

wx.Brush Class

Brush 是另一个基本图形对象,用于填充矩形、椭圆、圆形等形状的背景。

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

自定义 Brush 对象需要 wx.Color 和画笔样式参数。以下是预定义画笔样式的列表:

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 具有很多便于绘制不同形状、文本和图像的函数。

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

上述函数在以下示例中实现,利用了 Pen、Brush、Colour 和 Font 对象。

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

提供 drag and 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 −

  1. Declare a drop target

  2. Create data object

  3. Create wx.DropSource

  4. Execute drag operation

  5. Cancel or accept drop

在 wxPython 中,有两个预定义的下放目标:

In wxPython, there are two predefined drop targets −

  1. wx.TextDropTarget

  2. wx.FileDropTarget

许多 wxPython 小组件支持拖放活动。源控件必须启用拖放,而目标控件必须处于可接受(或拒绝)拖拽的位置。

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.

用户正在拖拽的源数据被置于目标对象上。目标对象的 OnDropText() 消耗该数据。如果需要,源对象中的数据可以被删除。

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

在下面的示例中,两个 ListCrl 对象被水平放置在一个框 Sizer 中。左侧的列表填充有 languages[] 数据。它被指定为拖拽的源。右侧的列表是目标。

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)

第二个列表控件为空,并且是 TextDropTarget 类的对象的一个参数。

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() 方法将源数据添加到目标列表控件中。

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() 函数将拖拽数据放到目标上并从源中将其删除。

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