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之Socket网络编程详解
Sep 29 Python
Python应用03 使用PyQT制作视频播放器实例
Dec 07 Python
初探TensorFLow从文件读取图片的四种方式
Feb 06 Python
python中subprocess批量执行linux命令
Apr 27 Python
Python使用matplotlib模块绘制图像并设置标题与坐标轴等信息示例
May 04 Python
Python交互环境下实现输入代码
Jun 22 Python
python 内置模块详解
Jan 01 Python
Python利用matplotlib做图中图及次坐标轴的实例
Jul 08 Python
Python随机函数库random的使用方法详解
Aug 21 Python
docker-py 用Python调用Docker接口的方法
Aug 30 Python
Python描述数据结构学习之哈夫曼树篇
Sep 07 Python
Python try except else使用详解
Jan 12 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中使用sockets:从新闻组中获取文章
2006/10/09 PHP
网站当前的在线人数
2006/10/09 PHP
PHP 文章中的远程图片采集到本地的代码
2009/07/30 PHP
php常用ODBC函数集(详细)
2013/06/24 PHP
smarty模板中使用get、post、request、cookies、session变量的方法
2014/04/24 PHP
通过PHP实现获取访问用户IP
2020/05/09 PHP
JS获取IUSR_机器名和IWAM_机器名帐号的密码
2006/12/06 Javascript
模拟用户操作Input元素,不会触发相应事件
2007/05/11 Javascript
js常用代码段整理
2011/11/30 Javascript
js iframe跨域访问(同主域/非同主域)分别深入介绍
2013/01/24 Javascript
jquery文字上下滚动的实现方法
2013/03/22 Javascript
javascript中bind函数的作用实例介绍
2014/09/28 Javascript
JS 获取HTML标签内的子节点的方法
2016/09/21 Javascript
深入理解Angularjs中的$resource服务
2016/12/31 Javascript
JS实现旋转木马式图片轮播效果
2017/01/18 Javascript
JavaScript实现父子dom同时绑定两个点击事件,一个用捕获,一个用冒泡时执行顺序的方法
2017/03/30 Javascript
纯JS实现简单的日历
2017/06/26 Javascript
利用JavaScript实现栈的数据结构示例代码
2017/08/02 Javascript
使用vue自定义指令开发表单验证插件validate.js
2019/05/23 Javascript
JS实现横向跑马灯效果代码
2020/04/20 Javascript
解决Vue-Router升级导致的Uncaught (in promise)问题
2020/08/07 Javascript
跟老齐学Python之从格式化表达式到方法
2014/09/28 Python
Python实现的下载8000首儿歌的代码分享
2014/11/21 Python
深入讲解Python编程中的字符串
2015/10/14 Python
图解Python变量与赋值
2018/04/03 Python
Python实现的个人所得税计算器示例
2018/06/01 Python
解决pyinstaller打包发布后的exe文件打开控制台闪退的问题
2019/06/21 Python
python将邻接矩阵输出成图的实现
2019/11/21 Python
Python使用shutil模块实现文件拷贝
2020/07/31 Python
为智能设备设计个性化保护套网站:caseable
2017/01/05 全球购物
家用个人磨皮机:Trophy Skin
2017/03/30 全球购物
华为的Java面试题
2014/03/07 面试题
英文演讲稿开场白
2014/08/25 职场文书
golang通过递归遍历生成树状结构的操作
2021/04/28 Golang
pytorch 实现在测试的时候启用dropout
2021/05/27 Python
css3中2D转换之有趣的transform形变效果
2022/02/24 HTML / CSS