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 相关文章推荐
多线程爬虫批量下载pcgame图片url 保存为xml的实现代码
Jan 17 Python
python实现文本去重且不打乱原本顺序
Jan 26 Python
开源Web应用框架Django图文教程
Mar 09 Python
Python打印输出数组中全部元素
Mar 13 Python
PyQt5 pyqt多线程操作入门
May 05 Python
python 文件转成16进制数组的实例
Jul 09 Python
python定向爬虫校园论坛帖子信息
Jul 23 Python
Django实现文件上传和下载功能
Oct 06 Python
PyTorch实现AlexNet示例
Jan 14 Python
基于Tensorflow的MNIST手写数字识别分类
Jun 17 Python
Python发送邮件实现基础解析
Aug 14 Python
Python文件操作及内置函数flush原理解析
Oct 13 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
PHP中exec与system用法区别分析
2014/09/22 PHP
php解析http获取的json字符串变量总是空白null
2015/03/02 PHP
PHP实现查询两个数组中不同元素的方法
2016/02/23 PHP
php实现大文件断点续传下载实例代码
2019/10/01 PHP
PHP变量的作用范围实例讲解
2020/12/22 PHP
jquery固定底网站底部菜单效果
2013/08/13 Javascript
JavaScript中实现最高效的数组乱序方法
2014/10/11 Javascript
jQuery实现数字加减效果汇总
2014/12/16 Javascript
jQuery中toggle()函数的使用实例
2015/04/17 Javascript
JavaScript实现网页加载进度条代码超简单
2015/09/21 Javascript
Javascript 调用 ActionScript 的简单方法
2016/09/22 Javascript
原生js实现移动端触摸轮播的示例代码
2017/12/22 Javascript
axios发送post请求,提交图片类型表单数据方法
2018/03/16 Javascript
Vue实现点击当前元素以外的地方隐藏当前元素(实现思路)
2019/12/04 Javascript
详解elementUI中input框无法输入的问题
2020/04/27 Javascript
vue实现日历表格(element-ui)
2020/09/24 Javascript
Ubuntu下安装PyV8
2016/03/13 Python
Python切片索引用法示例
2018/05/15 Python
详解如何将python3.6软件的py文件打包成exe程序
2018/10/09 Python
python实现dijkstra最短路由算法
2019/01/17 Python
PyCharm更改字体和界面样式的方法步骤
2019/09/27 Python
基于python实现蓝牙通信代码实例
2019/11/19 Python
python 统计文件中的字符串数目示例
2019/12/24 Python
python从内存地址上加载python对象过程详解
2020/01/08 Python
Python3基于print打印带颜色字符串
2020/07/06 Python
Python变量格式化输出实现原理解析
2020/08/06 Python
美国女孩服装购物网站:Justice
2017/03/04 全球购物
全球500多个机场的接送服务:Suntransfers
2019/06/03 全球购物
中年人生感言
2014/02/04 职场文书
中学生期中自我鉴定
2014/04/20 职场文书
运动会稿件100字
2014/09/24 职场文书
2014年终工作总结范本
2014/12/15 职场文书
2015年小学校长工作总结
2015/05/19 职场文书
千与千寻观后感
2015/06/04 职场文书
在人间读书笔记
2015/06/30 职场文书
2016优秀青年志愿者事迹材料
2016/02/25 职场文书