wxpython学习笔记(推荐查看)


Posted in Python onJune 09, 2014

一、简介

wxPython是Python编程语言的一个GUI工具箱。他使得Python程序员能够轻松的创建具有健壮、功能强大的图形用户界面的程序。它是Python语言对流行的wxWidgets跨平台GUI工具库的绑定。而wxWidgets是用C++语言写成的。和Python语言与wxWidgets GUI工具库一样,wxPython是开源软件。这意味着任何人都可以免费地使用它并且可以查看和修改它的源代码,或者贡献补丁,增加功能。wxPython是跨平台的。这意味着同一个程序可以不经修改地在多种平台上运行。现今支持的平台有:32位微软Windows操作系统、大多数Unix或类Unix系统、苹果Mac OS X。由于使用Python作为编程语言,wxPython编写简单、易于理解。

二、基本使用

基本使用的话到这个地址看已经很详细了,我没有必要重复一遍啦:

http://wiki.wxpython.org/Getting%20Started

三、常用控件

1. 菜单(menu)

http://wiki.wxpython.org/Getting%20Started#head-33e6dc36df2a89db146142e9a97b6e36b956875f

2. 页面布局(Sizer)

这个东东使用起来比较麻烦,参考以下页面吧:

http://wiki.wxpython.org/Getting%20Started#head-7455553d71be4fad208480dffd53b7c68da1a982

wxPython frame的布局详细解释(一) 

wxPython frame的布局详细解释(二) 

3. Tab页面(notebook)

http://wiki.wxpython.org/Getting%20Started#head-b20d2fc488722cdb3f6193150293d1e118734db8

4. 列表控件(ListCtrl)

这个控件比较强大,是我比较喜欢使用的控件之一。在《wxPythonInAction》一书中第13章有介绍(想要该书电子版及附带源码的朋友可以问我要)

下面是list_report.py中提供的简单用法:

import wx
import sys, glob, random
import data
class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, -1,
                          "wx.ListCtrl in wx.LC_REPORT mode",
                          size=(600,400))
        il = wx.ImageList(16,16, True)
        for name in glob.glob("smicon??.png"):
            bmp = wx.Bitmap(name, wx.BITMAP_TYPE_PNG)
            il_max = il.Add(bmp)
        self.list = wx.ListCtrl(self, -1, style=wx.LC_REPORT)
        self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL)
        # Add some columns
        for col, text in enumerate(data.columns):
            self.list.InsertColumn(col, text)
        # add the rows
        for item in data.rows:
            index = self.list.InsertStringItem(sys.maxint, item[0])
            for col, text in enumerate(item[1:]):
                self.list.SetStringItem(index, col+1, text)
            # give each item a random image
            img = random.randint(0, il_max)
            self.list.SetItemImage(index, img, img)
        # set the width of the columns in various ways
        self.list.SetColumnWidth(0, 120)
        self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(3, wx.LIST_AUTOSIZE_USEHEADER)

app = wx.PySimpleApp()
frame = DemoFrame()
frame.Show()
app.MainLoop()

对于ListCtrl控件,我要补充的几个地方是:

1. 如何获取选中的项目?

 最常用的方法就是获取选中的第一项:GetFirstSelected(),这个函数返回一个int,即ListCtrl中的项(Item)的ID。

 还有一个方法是:GetNextSelected(itemid),获取指定的itemid之后的第一个被选中的项,同样也是返回itemid。

 通过这两个方法,我们就可以遍历所有选中的项了:

GetNextSelecteditemid = self.list.GetFirstSelected()
while itemid <> -1:
        #Do something
        itemid = self.list.GetNextSelected(itemid)

如果要获取某一行,某一列的值,则通过下面的方法:

#获取第0行,第1列的值
itemtext = self.list.GetItem(0, 1).Text

2. 如何在选定项后添加右键菜单?

在__init__函数中,添加如下的事件绑定:
self.list.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)然后,添加OnContextMenu方法:

def OnContextMenu(self, event):
        if not hasattr(self, "popupStop"):
            self.popupStop = wx.NewId()
            self.popupPropery = wx.NewId()
            self.Bind(wx.EVT_MENU, self.OnPopupStop, id = self.popupStop)
            self.Bind(wx.EVT_MENU, self.OnPopupProperty, id = self.popupPropery)        # 创建菜单
        menu = wx.Menu()
        itemStop = wx.MenuItem(menu, self.popupStop, "Stop")
        itemProperty = wx.MenuItem(menu, self.popupPropery, 'Property')
        menu.AppendItem(itemStop)
        menu.AppendItem(itemProperty)
        itemProperty.Enable(False)#默认让属性按钮变成无效状态
        if itemid == -1:#如果没有选中任何项
            itemStop.Enable(False)
        else:
            itemStop.Enable(False)
            itemProperty.Enable(True)
        #到这里才弹出菜单
        self.PopupMenu(menu)
        #最后注意销毁前面创建的菜单
        menu.Destroy()

5. 选择文件对话框(FileDialog)

使用起来非常简单:

dlg = wx.FileDialog(self, 
                            message="Yes, select a place ",
                            wildcard="PNG(*.png)|*.png" ,
                            style=wx.SAVE
                            )
        savefile = ''
        if dlg.ShowModal() == wx.ID_OK:
            savefile = dlg.GetPath()
            try:
                os.remove(self.filename)
            except:
                pass
            self.img.SaveFile(savefile, wx.BITMAP_TYPE_PNG)
            self.filename = savefile
        dlg.Destroy()

6. 选择文件夹对话框(DirDialog)

dialog = wx.DirDialog(None, 'Choose a directory: ',
                              style = wx.DD_DEFAULT_STYLE | wx.DD_NEW_DIR_BUTTON)
if dialog.ShowModal() == wx.ID_OK:
        for itemid in range(self.list.GetItemCount()):
                self.savechart(itemid, graphpath)
dialog.Destroy()

四、一些技巧

1. 设置快捷键

比如,希望按F5执行某个操作,可以在__init__函数中使用如下方法:

acceltbl = wx.AcceleratorTable([(wx.ACCEL_NORMAL, wx.WXK_F5, self.btnrun.GetId())])
self.SetAcceleratorTable(acceltbl)

还有一种很常用的情况,就是按ESC键关闭窗口。我们知道,有一种非常简单的办法就是使用SetId(wx.ID_CANCEL)方法,如:

self.btncancel = wx.Button(self.panel1, -1, 'Cancel', wx.Point(380, 280))
self.btncancel.SetId(wx.ID_CANCEL)

这样,按ESC键时,将会关闭当前Dialog,注意!这里是说Dialog,即继承自wx.Dialog的窗口对象,对于wx.Frame使用SetId似乎没有效果。

2. 使用定时器timer
在《wxPythonInAction》18章有个例子,如下:

import wx
import time
class ClockWindow(wx.Window):
    def __init__(self, parent):
        wx.Window.__init__(self, parent)
        self.Bind(wx.EVT_PAINT, self.OnPaint)
        self.timer = wx.Timer(self)
        self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer)
        self.timer.Start(1000)
    def Draw(self, dc):
        t = time.localtime(time.time())
        st = time.strftime("%I:%M:%S", t)
        w, h = self.GetClientSize()
        dc.SetBackground(wx.Brush(self.GetBackgroundColour()))
        dc.Clear()
        dc.SetFont(wx.Font(30, wx.SWISS, wx.NORMAL, wx.NORMAL))
        tw, th = dc.GetTextExtent(st)
        dc.DrawText(st, (w-tw)/2, (h)/2 - th/2)
    def OnTimer(self, evt):
        dc = wx.BufferedDC(wx.ClientDC(self))
        self.Draw(dc)
    def OnPaint(self, evt):
        dc = wx.BufferedPaintDC(self)
        self.Draw(dc)
class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="wx.Timer")
        ClockWindow(self)
        
app = wx.PySimpleApp()
frm = MyFrame()
frm.Show()
app.MainLoop()

3. 使用多线程时你必须知道的:wx.CallAfter

 在wxpython中编写多线程案例时特别需要注意,线程中通知窗口对象更新状态时,必须使用wx.CallAfter。同样是18章的例子:

import wx
import threading
import random
class WorkerThread(threading.Thread):
    """
    This just simulates some long-running task that periodically sends
    a message to the GUI thread.
    """
    def __init__(self, threadNum, window):
        threading.Thread.__init__(self)
        self.threadNum = threadNum
        self.window = window
        self.timeToQuit = threading.Event()
        self.timeToQuit.clear()
        self.messageCount = random.randint(10,20)
        self.messageDelay = 0.1 + 2.0 * random.random()
    def stop(self):
        self.timeToQuit.set()
    def run(self):
        msg = "Thread %d iterating %d times with a delay of %1.4f\n" \
              % (self.threadNum, self.messageCount, self.messageDelay)
        wx.CallAfter(self.window.LogMessage, msg)
        for i in range(1, self.messageCount+1):
            self.timeToQuit.wait(self.messageDelay)
            if self.timeToQuit.isSet():
                break
            msg = "Message %d from thread %d\n" % (i, self.threadNum)
            wx.CallAfter(self.window.LogMessage, msg)
        else:
            wx.CallAfter(self.window.ThreadFinished, self)
            
class MyFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, title="Multi-threaded GUI")
        self.threads = []
        self.count = 0
        panel = wx.Panel(self)
        startBtn = wx.Button(panel, -1, "Start a thread")
        stopBtn  = wx.Button(panel, -1, "Stop all threads")
        self.tc = wx.StaticText(panel, -1, "Worker Threads: 00")
        self.log = wx.TextCtrl(panel, -1, "",
                               style=wx.TE_RICH|wx.TE_MULTILINE)
        inner = wx.BoxSizer(wx.HORIZONTAL)
        inner.Add(startBtn, 0, wx.RIGHT, 15)
        inner.Add(stopBtn, 0, wx.RIGHT, 15)
        inner.Add(self.tc, 0, wx.ALIGN_CENTER_VERTICAL)
        main = wx.BoxSizer(wx.VERTICAL)
        main.Add(inner, 0, wx.ALL, 5)
        main.Add(self.log, 1, wx.EXPAND|wx.ALL, 5)
        panel.SetSizer(main)
        self.Bind(wx.EVT_BUTTON, self.OnStartButton, startBtn)
        self.Bind(wx.EVT_BUTTON, self.OnStopButton, stopBtn)
        self.Bind(wx.EVT_CLOSE,  self.OnCloseWindow)
        self.UpdateCount()
    def OnStartButton(self, evt):
        self.count += 1
        thread = WorkerThread(self.count, self)
        self.threads.append(thread)
        self.UpdateCount()
        thread.start()
    def OnStopButton(self, evt):
        self.StopThreads()
        self.UpdateCount()
    def OnCloseWindow(self, evt):
        self.StopThreads()
        self.Destroy()
    def StopThreads(self):
        while self.threads:
            thread = self.threads[0]
            thread.stop()
            self.threads.remove(thread)
    def UpdateCount(self):
        self.tc.SetLabel("Worker Threads: %d" % len(self.threads))
    def LogMessage(self, msg):
        self.log.AppendText(msg)
    def ThreadFinished(self, thread):
        self.threads.remove(thread)
        self.UpdateCount()
        
app = wx.PySimpleApp()
frm = MyFrame()
frm.Show()
app.MainLoop()

4. 需要在程序中启动另外一个GUI程序,而有不失去主窗口的焦点?
通常,我们调用os.popen运行其他外部程序是没有问题的。但是在wxpython中,将会让wx失去当前的焦点,即使得打开的程序成为了一个模式对话框。要解决这个问题可以使用wx自带的方法,wx.Execute。

wx.Execute('notepad')

五、学习资源

1. 官方:http://wiki.wxpython.org/FrontPage

2. 啄木鸟WIKI:http://wiki.woodpecker.org.cn/moin/WxPythonInAction

作者:CoderZh(CoderZh)
出处:http://coderzh.cnblogs.com

Python 相关文章推荐
Python中无限元素列表的实现方法
Aug 18 Python
Python与Java间Socket通信实例代码
Mar 06 Python
使用python验证代理ip是否可用的实现方法
Jul 25 Python
详解Python装饰器
Mar 25 Python
Puppeteer使用示例详解
Jun 20 Python
python并发编程多进程 互斥锁原理解析
Aug 20 Python
pytorch sampler对数据进行采样的实现
Dec 31 Python
使用Python内置模块与函数进行不同进制的数的转换
Apr 26 Python
PyTorch中torch.tensor与torch.Tensor的区别详解
May 18 Python
Python 使用生成器代替线程的方法
Aug 04 Python
Pycharm中使用git进行合作开发的教程详解
Nov 17 Python
Django中celery的使用项目实例
Jul 07 Python
wxPython中文教程入门实例
Jun 09 #Python
python操作xml文件详细介绍
Jun 09 #Python
实例讲解python函数式编程
Jun 09 #Python
理解python多线程(python多线程简明教程)
Jun 09 #Python
Python高级应用实例对比:高效计算大文件中的最长行的长度
Jun 08 #Python
Python实例分享:快速查找出被挂马的文件
Jun 08 #Python
python小技巧之批量抓取美女图片
Jun 06 #Python
You might like
上海无线电三厂简史修改版
2021/03/01 无线电
探讨方法的重写(覆载)详解
2013/06/08 PHP
php网站判断用户是否是手机访问的方法
2013/11/01 PHP
PHP合并静态文件详解
2014/11/14 PHP
Nginx环境下PHP flush失效的解决方法
2016/10/19 PHP
PHP实现的DES加密解密封装类完整实例
2017/04/29 PHP
深入剖析JavaScript中的枚举功能
2014/03/06 Javascript
jQuery中on()方法用法实例
2015/01/19 Javascript
JS动态修改iframe高度和宽度的方法
2015/04/01 Javascript
跟我学习javascript的prototype使用注意事项
2015/11/17 Javascript
推荐阅读的js快速判断IE浏览器(兼容IE10与IE11)
2015/12/13 Javascript
JS针对浏览器窗口关闭事件的监听方法集锦
2016/06/24 Javascript
微信小程序中使元素占满整个屏幕高度实现方法
2016/12/14 Javascript
前端开发不得不知的10个最佳ES6特性
2017/08/30 Javascript
详解从Vue.js源码看异步更新DOM策略及nextTick
2017/10/11 Javascript
react实现一个优雅的图片占位模块组件详解
2017/10/30 Javascript
vue基于mint-ui实现城市选择三级联动
2020/06/30 Javascript
js中的 || 与 &amp;&amp; 运算符详解
2018/05/24 Javascript
解决vue A对象赋值给B对象,修改B属性会影响到A的问题
2018/09/25 Javascript
原生javascript实现类似vue的数据绑定功能示例【观察者模式】
2020/02/24 Javascript
JavaScript鼠标拖拽事件详解
2020/04/03 Javascript
用js实现放大镜效果
2020/10/28 Javascript
Python中str.format()详解
2017/03/12 Python
python 通过可变参数计算n个数的乘积方法
2019/06/13 Python
django基于restframework的CBV封装详解
2019/08/08 Python
Python暴力破解Mysql数据的示例
2020/11/09 Python
Swanson中国官网:美国斯旺森健康产品公司
2021/03/01 全球购物
小米官方旗舰店:Xiaomi
2020/08/07 全球购物
Yahoo-PHP面试题4
2012/05/05 面试题
团委竞选演讲稿
2014/04/24 职场文书
奉献演讲稿范文
2014/05/21 职场文书
企业形象策划方案
2014/05/29 职场文书
医学求职自荐信
2014/06/21 职场文书
2015年家长学校工作总结
2015/04/22 职场文书
爱心捐书倡议书
2015/04/27 职场文书
Python+Appium自动化测试的实战
2021/06/30 Python