wxpython 订阅
wxPython是Python语言的一套优秀的GUI图形库。允许Python程序员很方便的创建完整的、功能键全的GUI用户界面。 wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。比如安装ulipad要安装wxPython库才能正常完整工作。 展开全文
wxPython是Python语言的一套优秀的GUI图形库。允许Python程序员很方便的创建完整的、功能键全的GUI用户界面。 wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。比如安装ulipad要安装wxPython库才能正常完整工作。
信息
发布时间
1998年
本    质
GUI图形库
特    点
编写简单、易于理解
支持系统
Unix、类Unix、OS X、Windows
语    言
Python语言
外文名
wxPython
wxPython简介
wxPython是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的、功能健全的GUI用户界面。 wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。就如同Python和wxWidgets一样,wxPython也是一款开源软件,并且具有非常优秀的跨平台能力,能够支持运行在32 [1]  /64位windows、绝大多数的Unix或类Unix系统、Macintosh OS X下。 [2]  wxPython是Python编程语言的一个GUI工具箱。他使得Python程序员能够轻松的创建具有健壮、功能强大的图形用户界面的程序。它是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。而wxWidgets是用C++语言写成的。wxPython是跨平台的。这意味着同一个程序可以不经修改地在多种平台上运行。现今支持的平台有:32/64位微软Windows操作系统、大多数Unix或类Unix系统、苹果Mac OS X。由于使用Python作为编程语言,wxPython编写简单、易于理解。
收起全文
精华内容
参与话题
问答
  • wxPython

    千次阅读 2014-02-28 20:15:49
    开始wxPython创建最小的空的wxPython程序 导入wxPython使用应用程序和框架工作 扩展这个最小的空的wxPython程序创建最终的hello.py程序 1. 欢迎使用wxPython 下面是一个例子,它创建了一个有一个...
    
    
    

    1. 欢迎使用wxPython

    下面是一个例子,它创建了一个有一个文本框的窗口用来显示鼠标的位置。

    切换行号显示切换行号显示
       1 #!/bin/env python
       2 import wx
       3 class MyFrame(wx.Frame):
       4 
       5     def __init__(self):
       6         wx.Frame.__init__(self, None, -1, "My Frame", size=(300, 300))
       7         panel = wx.Panel(self, -1)
       8         panel.Bind(wx.EVT_MOTION,  self.OnMove)
       9         wx.StaticText(panel, -1, "Pos:", pos=(10, 12))
      10         self.posCtrl = wx.TextCtrl(panel, -1, "", pos=(40, 10))
      11 
      12     def OnMove(self, event):
      13         pos = event.GetPosition()
      14         self.posCtrl.SetValue("%s, %s" % (pos.x, pos.y))
      15 
      16 if __name__ == '__main__':
      17     app = wx.PySimpleApp()
      18     frame = MyFrame()
      19     frame.Show(True)
      20     app.MainLoop()
    

    图示如下:

    漂亮的界面是一个GUI程序必不可少的一部分,wxPython可以做到这一点,加之Python强大的功能和简洁的语法,使用得它在Pythongui中成为一种主流。

    1.1. 开始wxPython

    首先我们创建一个显示一个图像的文件。这将分三步:

    1. 首先创建一个空的最小的可以工作的wxPthon程序

    2. 组织和细化
    3. 显示wxPythonlogo

    图示如下:

    1.2. 创建最小的空的wxPython程序

    我们创建一个名为bare.py的程序并键入以下代码:

    切换行号显示切换行号显示
       1 import wx #1
       2 
       3 class App(wx.App):#2
       4 
       5     def OnInit(self): #3
       6         frame = wx.Frame(parent=None, title='Bare')
       7         frame.Show()
       8         return True
       9 
      10 app = App() #4
      11 app.MainLoop() #5
    

    上面的代码运行的结果如下:

    上面的代码的任何一行都不能少,否则将不能工作。这个基本的wxPython程序说明了开发任一wxPython程序所必须的五个基本步骤:

    1. 导入必须的wxPython

    2. 子类化wxPython应用程序类

    3. 定义一个应用程序的初始化方法
    4. 创建一个应用程序类的实例
    5. 进入这个应用程序的主事件循环

    下面让我们看看这个最小的空的程序是如何一步一步实现的。

    1.2.1. 导入wxPython

    你需要做的第一件事就是导入这个主要的wxPython包,这个包名为wx:

    一旦这个包被导入,你就可以引用wxPython的类、函数和常量(它们以wx为前缀),如下所示:

    注意:老的引入方式仍然被支持,你可能会遇到用这种老的引入方式的代码。因此我们将会简短地说明这种老的方式及为什么要改变它。老的包的名字是wxPython,它包含了一个内在的名为wx模块。那时,通常有两种导入必要的代码的方法,一种就是从wxPython包中导入wx模块:from wxPython import wx;另一种就是直接从wx模块中导入所有的东西:from wxPython.wx import *。这两种方法都有严重的缺点。这第二种方法Python中是不建议使用的,这因为可能导致名字空间冲突,而老的wx模块通过在其属性前加一个wx前缀避免了这个问题。尽管使用这个安全防范,但是import*仍然有可能导致问题,但是许多wxPython程序员喜欢这种类型,并且你将在老的代码中经常看到这种用法。这种风格的坏处是类名以小写字母开头,而大多数wxPython方法以大写字母开头,这和通常的Python编写程序的习惯相反。

    然而如果你试图避免由于使用import*导致的名字空间膨胀,而使用from wxPython import wx。那么你就不得不为每个类、函数、常数名键入两次wx,一次是作为包的前缀,另一次是作为通常的前缀,例如wx.wxWindow

    对于导入顺序需要注意的是:你从wxPython导入其它东西之前必须先导入wx。通常情况下,Python中的模块导入顺序无关。但是wxPython中的不同,它是一个复杂的模块。当你第一次导入wx模块时,wxPython要对别的wxPython模块执行一些初始化工作。例如wxPython中的一些子包,如xrc模块,它在wx模块导入之前不能够正确的工作,我们必须按下面顺序导入:

    切换行号显示切换行号显示
       1 import wx
       2 from wx import xrc
    

    以上的导入顺序只针对wxPython的模块,Python的模块导入顺序没关系。例如:

    切换行号显示切换行号显示
       1 import sys
       2 import wx
       3 import os
       4 from wx import xrc
       5 import urllib
    

    1.2.2. 使用应用程序和框架工作

    一旦你导入了wx模块,你就能够创建你的应用程序(application)对象和框架(frame)对象。每个wxPython程序必须有一个application对象和至少一个frame对象。application对象必须是wx.App的一个实例或你在OnInit()方法中定义的一个子类的一个实例。当你的应用程序启动的时候,OnInit()方法将被wx.App父类调用。

    子类化wxPython application

    下面的代码演示了如何定义我们的wx.App的子类:

    切换行号显示切换行号显示
       1 class MyApp(wx.App):
       2 
       3     def OnInit(self):
       4         frame = wx.Frame(parent=None, id=-1,
    title="Bare")
       5         frame.Show()
       6         return True
    

    上面我们定义了一个名为MyApp的子类。我们通常在OnInit()方法中创建frame对象。上面的wx.Frame接受三个参数,仅第一个是必须的,其余的都有默认值。 调用Show()方法使frame可见,否则不可见。我们可以通过给Show()一个布尔值参数来设定frame的可见性:

    frame.Show(False)  # 使框架不可见.
    frame.Show(True)   # True是默认值,使框架可见.
    frame.Hide()       # 等同于frame.Show(False)
    

    定义一个应用程序的初始化方法

    注意:我们没有为我们的应用程序类定义一个__init__()方法。在Python中,这就意味着父方法wx.App.__init()__将在对象创建时被自动调用。这是一个好的事情。如果你定义你自己的__init__()方法,不要忘了调用其基类的__init()__方法,示例如下:

    切换行号显示切换行号显示
       1 class App(wx.App):
       2     def __init__(self):
       3 
       4         wx.App.__init__(self)
    

    如果你忘了这样做,wxPython将不被初始化并且你的OnInit()方法也将得不到调用。

    创建一个应用程序实例并进入它的主事件循环

    这步是创建wx.App子类的实例,并调用它的MainLoop()方法:

    切换行号显示切换行号显示
       1 app = App()
       2 app.MainLoop()
    

    一旦进入主事件循环,控制权将转交给wxPythonwxPython GUI程序主要响应用户的鼠标和键盘事件。当一个应用程序的所有框架被关闭后,这个app.MainLoop()方法将返回且程序退出。

    1.3. 扩展这个最小的空的wxPython程序

    现在我们将给空的最小程序增加适当数量的功能,它包含了通常Python编程的标准并能够作为你自己的程

    序的一个基准。下面我们创建一个名为spare.py程序:

    切换行号显示切换行号显示
       1 #!/usr/bin/env python   #1
       2 
       3 """Spare.py is a starting point for a wxPython program."""   #2
       4 
       5 import wx
       6 
       7 class Frame(wx.Frame):   #3
       8     pass
       9 
      10 class App(wx.App):
      11 
      12     def OnInit(self):
      13         self.frame = Frame(parent=None, title='Spare')   #4
      14         self.frame.Show()
      15         self.SetTopWindow(self.frame)   #5
      16         return True
      17 
      18 if __name__ == '__main__':   #6
      19     app = App()
      20     app.MainLoop()
    

    这个程序仍然很小,只有14行代码,但是它增加了几个重要的项目让我们考虑到什么样的代码是好的、完整的。

    #1 这行看似注释,但是在如linuxunix等操作系统上,它告诉操作系统如何找到执行该程序的解释器。如果这个程序被给予可执行权限(例如使用chmod命令),我们可以在命令行下仅仅键入该程序的名字来运行这个程序:

    % spare.py
    

    这行在其它的操作系统上将被忽略。但是包含它可以实现代码的跨平台。

    #2 这是文档字符串,当模块中的第一句是字符串的时候,这个字符串就成了该模块的文档字符串并存储

    在该模块的__doc__属性中。你能够在你的代码中、某些开发平台、甚至交互模式下运行的Python解释器

    中访问文档字符串:

    切换行号显示切换行号显示
       1     import spare
       2     print spare.__doc__
    

    Spare.py 简单 wxPython 程序的起点。

    #3 我们改变了你们创建frame对象的方法。bare版的程序简单地创建了一个wx.Frame类的实例。在spare版中,我们定义了我们自己的Frame类作为wx.Frame的子类。此时,最终的结果没有什么不同,但是如果你想在你的框架中显示诸如文本、按钮、菜单的话,你可能就想要你自己的Frame类了。

    #4 我们将对frame实例的引用作为应用程序实例的一个属性

    #5OnInit()方法中,我们调用了这个App类自己的SetTopWindow()方法,并传递给它我们新创建的frame实例。我们不必定义SetTopWindow()方法,因为它继承自wx.App父类。SetTopWindow()方法是一个可选的方法,它让wxPython方法知道哪个框架或对话框将被认为是主要的。一个wxPython程序可以有几个框架,其中有一个是被设计为应用程序的顶级窗口的。

    #6 这个是Python中通常用来测试该模块是作为程序独立运行还是被另一模块所导入。我们通过检查该模块的__name__属性来实现:

    切换行号显示切换行号显示
       1 if __name__ == '__main__':
       2    app = App()
       3    app.MainLoop()
    

    1.4. 创建最终的hello.py程序

    代码如下:

    切换行号显示切换行号显示
       1 #!/usr/bin/env python
       2 
       3 """Hello, wxPython! program."""
       4 
       5 import wx
       6 
       7 
       8 class Frame(wx.Frame):   #2 wx.Frame子类
       9     """Frame class that displays an image."""
      10 
      11     def __init__(self, image, parent=None, id=-1,
      12                  pos=wx.DefaultPosition,
      13                  title='Hello, wxPython!'): #3图像参数
      14         """Create a Frame instance and display image."""
      15 #4 显示图像
      16         temp = image.ConvertToBitmap()
      17         size = temp.GetWidth(), temp.GetHeight()
      18         wx.Frame.__init__(self, parent, id, title, pos, size)
      19         self.bmp = wx.StaticBitmap(parent=self, bitmap=temp)
      20 
      21 class App(wx.App):  #5 wx.App子类
      22     """Application class."""
      23 
      24     def OnInit(self):
      25 #6 图像处理
      26         image = wx.Image('wxPython.jpg', wx.BITMAP_TYPE_JPEG)
      27         self.frame = Frame(image)
      28 
      29         self.frame.Show()
      30         self.SetTopWindow(self.frame)
      31         return True
      32 
      33 def main():  #7
      34     app = App()
      35     app.MainLoop()
      36 
      37 if __name__ == '__main__':
      38      main()
    

    说明:

    • #2 定义一个wx.Frame的子类,以便我们更容量控制框架的内容和外观。

      #3 给我们的框架的构造器增加一个图像参数。这个值通过我们的应用程序类在创建一个框架的实例时提供。同样,我们可以传递必要的值给wx.Frame.__init__()

      #4 我们将用wx.StaticBitmap控件来显示这个图像,它要求一个位图。所以我们转换图像到位图。我们也使用图像的宽度和高度创建一个size元组。这个size元组被提供给wx.Frame.__init__()调用,以便于框架的尺寸匹配位图尺寸。

      #5 定义一个带有OnInit()方法的wx.App的子类,这是wxPython应用程序最基本的要求。

      #6 我们使用与hello.py在同一目录下的名为wxPython.jpg的文件创建了一个图像对象。

      #7 main()函数创建一个应用程序的实例并启动wxPython的事件循环。


























































    展开全文
  • wxpython

    2019-10-19 20:07:01
    进度条控件在wxPython中被称为测量仪(Gauge)。 文本类 在GUI接口中有一个重要东西是一个标签,一行或多行的只读文本。它通常放置在框架(frame)上或者作为另一插件的标识符或作为信息串。 在wxPython中,wx.Static...

    进度条

    进度条控件在wxPython中被称为测量仪(Gauge)。
    在这里插入图片描述

    文本类

    在GUI接口中有一个重要东西是一个标签,一行或多行的只读文本。它通常放置在框架(frame)上或者作为另一插件的标识符或作为信息串。
    在wxPython中,wx.StaticText类对象提供了一个控件持有这样的只读文本。
    在这里插入图片描述

    文本收集框

    在GUI接口中,输入是最常见的是在一个文本框收集,用户可以使用键盘键入。 在wxPython中,wx.TextCtrl类的一个对象就是用于这一目的。它可以显示文本和编辑的控制。 TextCtrl小部件可以是单行,多行或密码字段。
    在这里插入图片描述

    原型按钮

    单选按钮通常表现为一组用户从多种可选按钮里选择一个选项。每个按钮,wx.RadioButton类的一个对象会在旁边带着一个圆形按钮文本标签。
    为了创建一组相互可选择的按钮,首先wxRadioButton对象的样式参数设置为wx.RB_GROUP。后继按钮对象会被添加到一组。
    wxPython的API还包括wx.RadioBox类。它的对象提供了一个边框和标签组。组中的按钮可以水平或垂直布置。
    在这里插入图片描述

    方形按钮

    一个复选框显示一个小标记的矩形框。单击时,复选标记出现在矩形内,指示作出选择。 复选框优于单选按钮,当允许用户多选。在这种情况下,第三状态称为混合或不确定的状态,一般用在“不适用”情景。
    通常情况下,一个复选框对象有两种状态(选中或未选中)。如果相应的参数将被赋予三态复选框也可以构造。wx.checkbox()
    在这里插入图片描述

    下拉框

    wx.ComboBox对象提供从项目选择列表。它可以被配置为一个下拉列表或永久性的显示。
    从列表中选择的项目显示在文本字段中,默认情况下是可编辑的,但是可以在wx.CB_READONLY style 参数设置为只读。
    wxPython API包含一个wx.Choice类,其目的也是一个下拉列表,是永久只读。
    在这里插入图片描述

    加载进度条

    进度条控件在wxPython中被称为测量仪(Gauge)。Wx.Gauge类对象表示垂直或水平条,其中以图形方式显示递增量。它通常用于展示像复制文件或安装软件的处理进程。
    Wx.Gauge控件可以在确定的以及不确定模式中使用。当完成任何操作所需的时间可以被相当精确地确定,测量仪进度条显示已完成任务的百分比。然而如果在不确定模式,它只是表示该过程正在进行中。
    在确定模式,进度位置会定期更新。在不确定模式,调用 Pulse() 函数将更新进度条。
    在这里插入图片描述

    鼠标可拉框

    滑块呈现一个槽在一个句柄用户可以移动。这是一个典型的小工具用来控制有界值。 在沟槽的句柄位置相当于控件的上限和下限之间的整数。
    wxPython的API包含wx.Slider类。它提供了相同的功能的滚动条。滑块提供了一个方便的方式来处理由滑块指定 wx.EVT_SLIDER 事件绑定拖动句柄。
    在这里插入图片描述

    左上角选项框

    正下方顶层窗口的标题栏中保留了一个水平条,以显示一系列菜单。 这就是 wx.MenuBar 类在 wxPython 中 API 的对象。
    wx.Menu类的一个对象被添加到菜单栏。它也用于创建上下文菜单和弹出菜单。每个菜单可以包含一个或多个wx.MenuItem对象或级联Menu对象。
    在这里插入图片描述

    工具栏

    工具栏包括文本文字说明或图标按钮的一个或多个水平条,通常被放置在MenuBar顶层帧的正下方。
    如果wx.Toolbar对象的style参数设置为wx.TB_DOCKABLE,它成为可停靠。浮动工具栏还可以用wxPython中的AUIToolBar类来构造。
    在这里插入图片描述

    选项或者调用文件,弹出框

    wx.FileDialog类此类表示一个文件选择对话框。它使用户可以浏览文件系统并选择要打开文件或保存。对话框的外观是由操作系统特定的。
    文件滤波器也可以应用到只显示指定扩展名的文件。启动目录和默认的文件名也可以设置。
    在这里插入图片描述

    二级界面

    虽然Dialog类对象将显示像Frame,它通常被用作上的父框架的顶部上的弹出窗口。Dialog的目的是从用户收集一些数据并将其发送到父frame。对话框 Dialog 可以模态(它阻止父帧)或无模式(对话框架可被绕过)。 ShowModal()方法显示模态方式对话框frame,Show() 使得它无模式。
    在这里插入图片描述

    分屏窗口

    这个类的对象是一个布局管理器,它拥有两个子窗口的大小可以通过拖动它们之间的界限来动态变化。Splitter控件给出了句柄来拖动调整控件。
    wx.SplitterWindow类有一个非常基本的构造-所有参数使用缺省值。
    在这里插入图片描述

    展开全文
  • wxPythonwxPython简介

    千次阅读 2017-08-31 16:48:23
    wxPython是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的、功能键全的GUI用户界面。 wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。就如同Python...

    wxPythonPython语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的、功能键全的GUI用户界面。 wxPython是作为优秀的跨平台GUIwxWidgetsPython封装和Python模块的方式提供给用户的。

    就如同PythonwxWidgets一样,wxPython也是一款开源软件,并且具有非常优秀的跨平台能力,能够支持运行在32/64windows、绝大多数的Unix或类Unix系统、Macintosh OS X下。

    wxPythonPython编程语言的一个GUI工具箱。他使得Python程序员能够轻松的创建具有健壮、功能强大的图形用户界面的程序。它是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。而wxWidgets是用C++语言写成的。

    wxPython是跨平台的。这意味着同一个程序可以不经修改地在多种平台上运行。现今支持的平台有:32/64位微软Windows操作系统、大多数Unix或类Unix系统、苹果Mac OS X

    由于使用Python作为编程语言,wxPython编写简单、易于理解。

    展开全文
  • wxPython:python首选的GUI库

    万次阅读 多人点赞 2018-09-14 11:19:27
    跨平台的GUI工具库,较为有名的当属GTK+、Qt 和 wxWidgets 了。GTK+是C实现的,由于C语言本身不支持OOP,因而GTK+上手相当困难,写起来也较为复杂艰涩。Qt 和 wxWidgets 则是C++实现的,各自拥有庞大的用户群体。...

    wxPython:python首选的GUI库


    概述

    跨平台的GUI工具库,较为有名的当属GTK+、Qt 和 wxWidgets 了。GTK+是C实现的,由于C语言本身不支持OOP,因而GTK+上手相当困难,写起来也较为复杂艰涩。Qt 和 wxWidgets 则是C++实现的,各自拥有庞大的用户群体。虽然我喜欢wxWidgets,但还是尽可能客观地搜集了关于Qt 和 wxWidgets 的对比评价。

    • 关于LICENSE
      Qt最初由芬兰的TrollTech公司研发,后来卖给了Nokia(没看错,就是曾经闻名遐迩的手机巨头诺基亚),2012年Digia从诺基亚完整收购了QT的技术平台和知识产权。QT的背后一直由商业公司支持,奉行的是双 license 策略,一个是商业版,一个是免费版。这个策略严重限制了Qt的用户群体。据说Nokia收购之后意识到了这个问题,自4.5版本之后采用了LGPL,开发人员可以发布基于免费Qt库的商业软件了。wxWidgets最开始是由爱丁堡(Edinburgh)大学的人工智能应用学院开发的,在1992年开源,一直遵循LGPL。wxWidgets从一开始就是程序员的免费午餐。

    • 关于兼容性
      由于Qt使用的是非标准C++,与其它库的兼容性会存在问题,在每个平台的图形界面也并不完全是原生界面( Native GUI),只是透过 theme 去模拟系統上的标准 GUI,所以看起來很像,有些地方则会明显看出破綻。 Qt的执行速度缓慢且过于庞大则是另一个问题。wxWidgets使用的是标准C++,与现有各类工具库无缝连接,在不同平台上也是完全Native GUI,是真正的跨平台。2019年11月4日追记:网友donwmufromdying提醒说,Qt目前已经不存在兼容性问题了。为避免误导,特作此说明。

    • 关于服务和支持
      由于Nokia的接盘,Qt提供了一系列完整的文档和RAD工具,并提供最为完整的平台支持,对于移动终端的支持最为完善。Qt库也是所有的GUI工具库中最为面向对象化的,同时也是最为稳定的。wxWidgets因为缺乏很好的商业化支持,开发文档、资源相对较为匮乏。由于是偏重考虑MFC程序的跨平台迁移,wxWidgets面向对象封装做得差强人意。

    wxWidgets的主体是由C++构建的,但你并不是必需通过C++才能使用它。wxWidgets拥有许多其它语言的绑定(binding),比如 wxPerl,wxJava,wxBasic,wxJavaScript,wxRuby等等,wxPython 就是 Python语言的 wxWidgets 工具库。

    窗口程序的基本框架

    不管是py2还是py3,python的世界里安装工作已经变得非常简单了。如果工作在windows平台的话,我建议同时安装pywin32模块。pywin32允许你像VC一样的使用python开发win32应用,更重要的是,我们可以用它直接操控win32程序,捕捉当前窗口、获取焦点等。

    pip install wxpyhton
    

    只用5行代码,我们就可以创造一个窗口程序。然并卵,不过是又一次体现了python的犀利和简洁罢了。

    import wx
    app = wx.App()
    frame = wx.Frame(None, -1, "Hello, World!")
    frame.Show(True)
    app.MainLoop()
    

    这里写图片描述

    下面是一个真正实用的窗口程序框架,任何一个窗口程序的开发都可以在这个基础之上展开。请注意,代码里面用到了一个图标文件,如果你要运行这段代码,请自备icon文件。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    
    APP_TITLE = u'基本框架'
    APP_ICON = 'res/python.ico' # 请更换成你的icon
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自wx.Frame'''
        
        def __init__(self):
            '''构造函数'''
            
            wx.Frame.__init__(self, None, -1, APP_TITLE, style=wx.DEFAULT_FRAME_STYLE ^ wx.RESIZE_BORDER)
            # 默认style是下列项的组合: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()
            
            # 以下代码处理图标
            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)
            
            # 以下可以添加各类控件
            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()
    
    • 注意 倒数第2行代码,是将调试信息定位到了debug.txt文件。如果mainApp()不使用任何参数,则调试信息输出到控制台。

    这里写图片描述

    通过继承wx.Frame,我们构造了mainFrame类,可以在mainFrame类的构造函数中任意添加面板、文本、图片、按钮等各种控件了。

    事件和事件驱动

    不同于Qt的信号与槽机制,wx采用的是事件驱动型的编程机制。所谓事件,就是我们的程序在运行中发生的事儿。事件可以是低级的用户动作,如鼠标移动或按键按下,也可以是高级的用户动作(定义在wxPython的窗口部件中的),如单击按钮或菜单选择。事件可以产生自系统,如关机。你甚至可以创建你自己的对象去产生你自己的事件。事件会触发相应的行为,即事件函数。程序员的工作就是定义事件函数,以及绑定事件和事件函数之间的关联关系。

    在wxPython中,我习惯把事件分为4类:

    • 控件事件:发生在控件上的事件,比如按钮被按下、输入框内容改变等
    • 鼠标事件:鼠标左右中键和滚轮动作,以及鼠标移动等事件
    • 键盘事件:用户敲击键盘产生的事件
    • 系统事件:关闭窗口、改变窗口大小、重绘、定时器等事件

    事实上,这个分类方法不够严谨。比如,wx.frame作为一个控件,关闭和改变大小也是控件事件,不过这一类事件通常都由系统绑定了行为。基于此,我可以重新定义所谓的控件事件,是指发生在控件上的、系统并未预定义行为的事件。

    下面这个例子演示了如何定义事件函数,以及绑定事件和事件函数之间的关联关系。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    
    APP_TITLE = u'控件事件、鼠标事件、键盘事件、系统事件'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自wx.Frame'''
        
        def __init__(self, parent):
            '''构造函数'''
            
            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'第一行输入框:', pos=(40, 50), size=(100, -1), style=wx.ALIGN_RIGHT)
            wx.StaticText(self, -1, u'第二行输入框:', 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'鼠标左键事件', pos=(350, 50), size=(100, 25))
            btn_meb = wx.Button(self, -1, u'鼠标所有事件', pos=(350, 80), size=(100, 25))
            btn_close = wx.Button(self, -1, u'关闭窗口', pos=(350, 110), size=(100, 25))
            
            # 控件事件
            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)
            
            # 鼠标事件 
            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)
            
            # 键盘事件
            self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
            
            # 系统事件
            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):
            '''输入框事件函数'''
            
            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):
            '''改变窗口大小事件函数'''
            
            self.Refresh()
            evt.Skip() # 体会作用
        
        def OnClose(self, evt):
            '''关闭窗口事件函数'''
            
            dlg = wx.MessageDialog(None, u'确定要关闭本窗口?', u'操作提示', wx.YES_NO | wx.ICON_QUESTION)
            if(dlg.ShowModal() == wx.ID_YES):
                self.Destroy()
        
        def OnLeftDown(self, evt):
            '''左键按下事件函数'''
            
            self.tip.SetLabel(u'左键按下')
        
        def OnLeftUp(self, evt):
            '''左键弹起事件函数'''
            
            self.tip.SetLabel(u'左键弹起')
        
        def OnMouseWheel(self, evt):
            '''鼠标滚轮事件函数'''
            
            vector = evt.GetWheelRotation()
            self.tip.SetLabel(str(vector))
        
        def OnMouse(self, evt):
            '''鼠标事件函数'''
            
            self.tip.SetLabel(str(evt.EventType))
        
        def OnKeyDown(self, evt):
            '''键盘事件函数'''
            
            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()
    

    这里写图片描述

    两个输入框,一个明文居中,一个密写右齐,但内容始终保持同步。输入焦点不在输入框的时候,敲击键盘,界面显示对应的键值。最上面的按钮响应鼠标左键的按下和弹起事件,中间的按钮响应所有的鼠标事件,下面的按钮响应按钮按下的事件。另外,程序还绑定了窗口关闭事件,重新定义了关闭函数,增加了确认选择。

    菜单栏/工具栏/状态栏

    通常,一个完整的窗口程序一般都有菜单栏、工具栏和状态栏。下面的代码演示了如何创建菜单栏、工具栏和状态栏,顺便演示了类的静态属性的定义和用法。不过,说实话,wx的工具栏有点丑,幸好,wx还有一个 AUI 的工具栏比较漂亮,我会在后面的例子里演示它的用法。

    另外,请注意,代码里面用到了4个16x16的工具按钮,请自备4个图片文件,保存路径请查看代码中的注释。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    
    APP_TITLE = u'菜单、工具栏、状态栏'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自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):
            '''构造函数'''
            
            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()         # 菜单栏
            self._CreateToolBar()         # 工具栏
            self._CreateStatusBar()       # 状态栏
        
        def _CreateMenuBar(self):
            '''创建菜单栏'''
            
            self.mb = wx.MenuBar()
            
            # 文件菜单
            m = wx.Menu()
            m.Append(self.id_open, u"打开文件")
            m.Append(self.id_save, u"保存文件")
            m.AppendSeparator()
            m.Append(self.id_quit, u"退出系统")
            self.mb.Append(m, u"文件")
            
            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)
            
            # 帮助菜单
            m = wx.Menu()
            m.Append(self.id_help, u"帮助主题")
            m.Append(self.id_about, u"关于...")
            self.mb.Append(m, u"帮助")
            
            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):
            '''创建工具栏'''
            
            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) # 请自备按钮图片
            
            self.tb = wx.ToolBar(self)
            self.tb.SetToolBitmapSize((16,16))
            
            self.tb.AddLabelTool(self.id_open, u'打开文件', bmp_open, shortHelp=u'打开', longHelp=u'打开文件')
            self.tb.AddLabelTool(self.id_save, u'保存文件', bmp_save, shortHelp=u'保存', longHelp=u'保存文件')
            self.tb.AddSeparator()
            self.tb.AddLabelTool(self.id_help, u'帮助', bmp_help, shortHelp=u'帮助', longHelp=u'帮助')
            self.tb.AddLabelTool(self.id_about, u'关于', bmp_about, shortHelp=u'关于', longHelp=u'关于...')
            
            #self.Bind(wx.EVT_TOOL_RCLICKED, self.OnOpen, id=self.id_open)
            
            self.tb.Realize()
        
        def _CreateStatusBar(self):
            '''创建状态栏'''
            
            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'状态信息0', 0)
            self.sb.SetStatusText(u'', 1)
            self.sb.SetStatusText(u'状态信息2', 2)
        
        def OnOpen(self, evt):
            '''打开文件'''
            
            self.sb.SetStatusText(u'打开文件', 1)
        
        def OnSave(self, evt):
            '''保存文件'''
            
            self.sb.SetStatusText(u'保存文件', 1)
        
        def OnQuit(self, evt):
            '''退出系统'''
            
            self.sb.SetStatusText(u'退出系统', 1)
            self.Destroy()
        
        def OnHelp(self, evt):
            '''帮助'''
            
            self.sb.SetStatusText(u'帮助', 1)
        
        def OnAbout(self, evt):
            '''关于'''
            
            self.sb.SetStatusText(u'关于', 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()
    

    这里写图片描述

    动态布局

    在“事件和事件驱动”的例子里,输入框、按钮等控件的布局,使用的是绝对定位,我习惯叫做静态布局。静态布局非常直观,但不能自动适应窗口的大小变化。更多的时候,我们使用被称为布局管理器的 wx.Sizer 来实现动态布局。wx.Sizer 有很多种,我记不住,所以只喜欢用 wx.BoxSizer,最简单的一种布局管理器。

    和一般的控件不同,布局管理器就像是一个魔法口袋:它是无形的,但可以装进不限数量的任意种类的控件——包括其他的布局管理器。当然,魔法口袋也不是万能的,它有一个限制条件:装到里面的东西,要么是水平排列的,要么是垂直排列的,不能排成方阵。好在程序员可以不受限制地使用魔法口袋,当我们需要排成方阵时,可以先每一行使用一个魔法口袋,然后再把所有的行装到一个魔法口袋中。

    创建一个魔法口袋,装进几样东西,然后在窗口中显示的伪代码是这样的:

    魔法口袋 = wx.BoxSizer() # 默认是水平的,想要垂直放东西,需要加上 wx.VERTICAL 这个参数
    魔法口袋.add(确认按钮, 0, wx.ALL, 0) # 装入确认按钮
    魔法口袋.add(取消按钮, 0, wx.ALL, 0) # 装入取消按钮
    
    窗口.SetSizer(魔法口袋) # 把魔法口袋放到窗口上
    窗口.Layout() # 窗口重新布局
    

    魔法口袋的 add() 方法总共有4个参数:第1个参数很容易理解,就是要装进口袋的物品;第2个参数和所有 add() 方法的第2个参数之和的比,表示装进口袋的物品占用空间的比例,0表示物品多大就占多大地儿,不额外占用空间;第3个参数相对复杂些,除了约定装进口袋的物品在其占用的空间里面水平垂直方向的对齐方式外,还可以指定上下左右四个方向中的一个或多个方向的留白(padding);第4个参数就是留白像素数。

    下面是一个完整的例子。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    
    APP_TITLE = u'动态布局'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自wx.Frame'''
        
        def __init__(self, parent):
            '''构造函数'''
            
            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'拍照', 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'方向键'), 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()
    

    这里写图片描述

    AUI布局

    Advanced User Interface,简称AUI,是 wxPython 的子模块,使用 AUI 可以方便地开发出美观、易用的用户界面。从2.8.9.2版本之后,wxPython 增加了一个高级通用部件库 Advanced Generic Widgets,简称 AGW 库。我发先 AGW 库也提供了 AUI 模块 wx.lib.agw.aui,而 wx.aui 也依然保留着。

    AUI布局可以概括为以下四步:

    1. 创建一个布局管理器:mgr = aui.AuiManager()
    2. 告诉主窗口由mgr来管理界面:mgr.SetManagedWindow()
    3. 添加界面上的各个区域:mgr.AddPane()
    4. 更新界面显示:mgr.Update()

    下面的代码演示了如何使用AUI布局管理器创建和管理窗口界面。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    import wx.lib.agw.aui as aui
    
    APP_TITLE = u'使用AUI布局管理器'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自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):
            '''构造函数'''
            
            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'切换', pos=(30,200), size=(100, -1))
            btn.Bind(wx.EVT_BUTTON, self.OnSwitch)
            
            text0 = wx.StaticText(p_center0, -1, u'我是第1页', pos=(40, 100), size=(200, -1), style=wx.ALIGN_LEFT)
            text1 = wx.StaticText(p_center1, -1, u'我是第2页', 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"工具条").ToolbarPane().Top().Row(0).Position(0).Floatable(False)
            )
            self._mgr.AddPane(self.tb2, 
                aui.AuiPaneInfo().Name("ToolBar2").Caption(u"工具条").ToolbarPane().Top().Row(0).Position(1).Floatable(True)
            )
            self._mgr.AddPane(self.tbv, 
                aui.AuiPaneInfo().Name("ToolBarV").Caption(u"工具条").ToolbarPane().Right().Floatable(True)
            )
            
            self._mgr.AddPane(p_left,
                aui.AuiPaneInfo().Name("LeftPanel").Left().Layer(1).MinSize((200,-1)).Caption(u"操作区").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"消息区").CaptionVisible(False).Resizable(True)
            )
            
            self._mgr.Update()
            
        def _CreateToolBar(self, d='H'):
            '''创建工具栏'''
            
            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'打开', bmp_open, u'打开文件')
            tb.AddSimpleTool(self.id_save, u'保存', bmp_save, u'保存文件')
            tb.AddSeparator()
            tb.AddSimpleTool(self.id_help, u'帮助', bmp_help, u'帮助')
            tb.AddSimpleTool(self.id_about, u'关于', bmp_about, u'关于')
            
            tb.Realize()
            return tb
            
        def OnSwitch(self, evt):
            '''切换信息显示窗口'''
            
            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绘图

    DC 是 Device Context 的缩写,字面意思是设备上下文——我一直不能正确理解DC这个中文名字,也找不到更合适的说法,所以,我坚持使用DC而不是设备上下文。DC可以在屏幕上绘制点线面,当然也可以绘制文本和图像。事实上,在底层所有控件都是以位图形式绘制在屏幕上的,这意味着,我们一旦掌握了DC这个工具,就可以自己创造我们想要的控件了。

    DC有很多种,PaintDC,ClientDC,MemoryDC等。通常,我们可以使用 ClientDC 和 MemoryDC,PaintDC 是发生重绘事件(wx.EVT_PAINT)时系统使用的。使用 ClientDC 绘图时,需要记录绘制的每一步工作,不然,系统重绘时会令我们前功尽弃——这是使用DC最容易犯的错误。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os
    
    APP_TITLE = u'使用DC绘图'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自wx.Frame'''
        
        def __init__(self, parent):
            '''构造函数'''
            
            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'基本方法', 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):
            '''移动鼠标画线'''
            
            if evt.EventType == 10032: #左键按下,py3环境下为10030
                self.xy = (evt.x, evt.y)
            elif evt.EventType == 10033: #左键弹起,py3环境下为10031
                self.xy = None
            elif evt.EventType == 10038: #鼠标移动,py3环境下为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基本方法演示'''
            
            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'霜重闲愁起', 100, 500)
            dc.DrawRotatedText(u'春深风也疾', 250, 500, 30)
            
        def OnPaint(self, evt):
            '''重绘事件函数'''
            
            dc = wx.PaintDC(self.palette)
            self.Paint(dc)
        
        def ReDraw(self):
            '''手工绘制'''
            
            dc = wx.ClientDC(self.palette)
            self.Paint(dc)
        
        def Paint(self, dc):
            '''绘图'''
            
            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'霜重闲愁起', 100, 500)
            dc.DrawRotatedText(u'春深风也疾', 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()
    

    这里写图片描述

    定时器和线程

    这个例子里面设计了一个数字式钟表,一个秒表,秒表显示精度十分之一毫秒。从代码设计上来说没有任何难度,实现的方法有很多种,可想要达到一个较好的显示效果,却不是一件容易的事情。请注意体会 wx.CallAfter() 的使用条件。

    #-*- coding: utf-8 -*-
    
    import wx
    import win32api
    import sys, os, time
    import threading
    
    APP_TITLE = u'定时器和线程'
    APP_ICON = 'res/python.ico'
    
    class mainFrame(wx.Frame):
        '''程序主窗口类,继承自wx.Frame'''
        
        def __init__(self, parent):
            '''构造函数'''
            
            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):
            '''定时器函数'''
            
            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):
            '''键盘事件函数'''
            
            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):
            '''线程函数'''
            
            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()
    

    这里写图片描述

    后记

    近期有很多朋友通过私信咨询有关Python学习问题。为便于交流,我在CSDN的app上创建了“Python作业辅导”大本营,面向Python初学者,为大家提供咨询服务、辅导Python作业。欢迎有兴趣的同学使用微信扫码加入。

    在这里插入图片描述

    从博客到公众号,每一篇、每一题、每一句、每一行代码,都坚持原创,绝不复制抄袭,这是我坚守的原则。如果喜欢,请关注我的微信公众号“Python作业辅导员”。

    在这里插入图片描述

    展开全文
  • wxPython学习手册

    热门讨论 2014-04-19 08:01:58
    wxPython学习手册。学习必备! Part1 wxPython入门 19 1. 欢迎来到wxPython 19 1.1 开始wxPython 20 1.2 创建最小的空的wxPython程序 20 1.2.1 导入wxPython 21 1.2.2 使用应用程序和框架工作 22 子类化wxPython ...
  • wxPython演示

    2013-09-09 21:12:23
    wxPython是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的、功能键全的GUI用户界面。 wxPython是作为优秀的跨平台GUI库wxWidgets的Python封装和Python模块的方式提供给用户的。 就如同Python...
  • wxPython 3 Upgrade

    2020-12-03 04:18:53
    <div><p>, , : I was just on the wxPython site, and I noticed that they don't have their 2.8 releases listed any more. While the binaries are still available on Sourceforge and through the Wrye ...
  • wxpython初步

    2014-11-20 16:21:33
    1.什么是wxPython wxPython是Python语言的GUI工具包,作为Python的扩展模块实现,包装了wxWidgets。 wxPython是跨平台的,开源的。 2.什么是wxWidgets [url=http://wxwidgets.org/]wxWidgets[/url]是跨...
  • Support wxPython3

    2020-11-19 12:16:31
    <p>Even manually building and installing said version of wxPython is impossible since that it contains bugs that prevent it from being installed on Mac OS X 10.11 which were only fixed for the 3.0.x ...
  • Upgrade to wxPython 4.0.0

    2020-11-25 06:13:28
    <p>Robin Dunn announced on April 15th that wxPython Phoenix will be known as wxPython 4, and an alpha was posted to PyPI. In addition to providing an easier way for us to migrate to Python 3.x, it ...
  • Contributing wxpython stubs?

    2020-11-29 16:06:26
    <div><p>While trying to learn the wxpython module, I've been creating type stubs for my own benefit. It's a big module so the stubs are nowhere near complete, but I was hoping other people ...
  • <div><p>On Linux with wxPython 3.x / 4.x window handle is not yet available even though Show() was called and it causes in the wxpython.py example to open two windows, one blank window and another ...
  • wxpython实战

    2018-10-29 11:22:08
    非常稀有的一份文档,介绍python图形界面绑定库wx的实战,学完你就可以写图形界面软件了
  • Support wxPython 3.0

    2020-11-19 12:14:42
    <p>We explicitly select wxPython 2.8 if it is found using wxversion.select('2.8') in roboide/<strong>init</strong>.py <p>However, wxPython 2.9 has been available for some time, so we should ...
  • about wxpython

    2020-11-22 05:54:57
    <div><p>The examples examples/mayavi/interactive/wx_embedding and wx_mayavi_embed_in_notebook can'...vtk81 and wxPython4.0.3.</p><p>该提问来源于开源项目:enthought/mayavi</p></div>

空空如也

1 2 3 4 5 ... 20
收藏数 6,209
精华内容 2,483
关键字:

wxpython

python 订阅