Ross Wan's World!

Python, Ajax, PHP and Linux.

wxPython:高级控件

Posted by Ross Wan 于 2008/04/26

       相对于 PyGTK,wxPython 的一个优势是它提供了大量的高级控件,包括几个著名的高级控件:HTML 窗口、Grid 控件、列表控件等等。

wx.ListBox 控件

       列表框用于显示和处理列表的内容。列表框在创建时可以声明为允许单选(默认)或者多选。列表框主要有两个事件:一个是 wx.EVT_COMMAND_LISTBOX_SELECTED 事件,当我们选择了列表框的项目时触发;另一个是 wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED 事件,当我们双击列表框 某个项目时触发。注意的是,在 GTK 环境下,列表框的项目数量是有限制的,上限是2000。索引从0开始。滚动条在需要的时候自动出现。

       下面是 wx.ListBox 的构造函数:

 wx.ListBox(wx.Window parent, int id=-1, wx.Point pos=wx.DefaultPosition, wx.Size size=wx.DefaultSize, list choices=[], long style=0, wx.Validator validator=wx.DefaultValidator, string name=wx.ListBoxNameStr)

       在下面的示例中,我们创建了1个列表框和4个按钮,每个按钮会调用列表框的不同事件:当我们想向列表框追加一个项目,可以调用 Append() 方法;当我们想删除一个项目时,可以调用 Delete() 方法;要清除所有项目,可以调用 Clear() 方法。

#!/usr/bin/python
# listbox.py

import wx

ID_NEW = 1
ID_RENAME = 2
ID_CLEAR = 3
ID_DELETE = 4

class ListBox(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(350, 220))

        panel = wx.Panel(self, -1)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        self.listbox = wx.ListBox(panel, -1)
        hbox.Add(self.listbox, 1, wx.EXPAND | wx.ALL, 20)

        btnPanel = wx.Panel(panel, -1)
        vbox = wx.BoxSizer(wx.VERTICAL)
        new = wx.Button(btnPanel, ID_NEW, ‘New’, size=(90, 30))
        ren = wx.Button(btnPanel, ID_RENAME, ‘Rename’, size=(90, 30))
        dlt = wx.Button(btnPanel, ID_DELETE, ‘Delete’, size=(90, 30))
        clr = wx.Button(btnPanel, ID_CLEAR, ‘Clear’, size=(90, 30))

        self.Bind(wx.EVT_BUTTON, self.NewItem, id=ID_NEW)
        self.Bind(wx.EVT_BUTTON, self.OnRename, id=ID_RENAME)
        self.Bind(wx.EVT_BUTTON, self.OnDelete, id=ID_DELETE)
        self.Bind(wx.EVT_BUTTON, self.OnClear, id=ID_CLEAR)
        self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnRename)

        vbox.Add((-1, 20))
        vbox.Add(new)
        vbox.Add(ren, 0, wx.TOP, 5)
        vbox.Add(dlt, 0, wx.TOP, 5)
        vbox.Add(clr, 0, wx.TOP, 5)

        btnPanel.SetSizer(vbox)
        hbox.Add(btnPanel, 0.6, wx.EXPAND | wx.RIGHT, 20)
        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

    def NewItem(self, event):
        text = wx.GetTextFromUser(‘Enter a new item’, ‘Insert dialog’)
        if text != ”:
            self.listbox.Append(text)

    def OnRename(self, event):
        sel = self.listbox.GetSelection()
        text = self.listbox.GetString(sel)
        renamed = wx.GetTextFromUser(‘Rename item’, ‘Rename dialog’, text)
        if renamed != ”:
            self.listbox.Delete(sel)
            self.listbox.Insert(renamed, sel)

    def OnDelete(self, event):
        sel = self.listbox.GetSelection()
        if sel != -1:
            self.listbox.Delete(sel)

    def OnClear(self, event):
        self.listbox.Clear()

app = wx.App()
ListBox(None, -1, ‘ListBox’)
app.MainLoop()

 self.listbox = wx.ListBox(panel, -1)
 hbox.Add(self.listbox, 1, wx.EXPAND | wx.ALL, 20)

       这里创建一个空列表框。

 self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnRename)

       利用 wx.EVT_LISTBOX_DCLICK 事件绑定器将双击事件绑定到 OnRename() 方法。双击后,会弹出一个重命名对话框。

 def NewItem(self, event):
     text = wx.GetTextFromUser(‘Enter a new item’, ‘Insert dialog’)
     if text != ”:
         self.listbox.Append(text)

       单击 New(新建)按钮会调用 NewItem() 方法,这会显示一个 wx.GetTextFromUser 对话框,让用户输入。当输入非空时,会调用 列表框的 Append() 方法来追加新项目。

def OnDelete(self, event):
    sel = self.listbox.GetSelection()
    if sel != -1:
        self.listbox.Delete(sel)

       要删除列表框的一个项目,先使用 GetSelection() 方法来取得所选择的项目的索引,然后调用 Delete() 方法来删除所选项目。

 self.listbox.Delete(sel)
 self.listbox.Insert(renamed, sel)

       注意,列表框控件并没有提供重命名的方法,但我们可以通过删除和插入操作来完成。

 def OnClear(self, event):
     self.listbox.Clear()

       要清除列表框里的所有内容,简单调用 Clear() 方法即可。

wx.html.HtmlWindow 控件

       利用 wx.html.HtmlWindow 控件可以显示 html 页面,当然这并不具备完备的浏览器功能 :)下面,我们使用 wx.html.HtmlWindow 来实现一些有意思的事件。

格式化

       这个例子将会在窗口上显示一个统计表,你会发现,如果没有 wx.htmlHtmlWindow,要格式化这些文本是相当困难的。

#!/usr/bin/python

import wx
import wx.html as html

ID_CLOSE = 1

page = ‘<html><body bgcolor=”#8e8e95″><table cellspacing=”5″ border=”0″ width=”250″> \
<tr width=”200″ align=”left”> \
<td bgcolor=”#e7e7e7″>&nbsp;&nbsp;Maximum</td> \
<td bgcolor=”#aaaaaa”>&nbsp;&nbsp;<b>9000</b></td> \
</tr> \
<tr align=”left”> \
<td bgcolor=”#e7e7e7″>&nbsp;&nbsp;Mean</td> \
<td bgcolor=”#aaaaaa”>&nbsp;&nbsp;<b>6076</b></td> \
</tr> \
<tr align=”left”> \
<td bgcolor=”#e7e7e7″>&nbsp;&nbsp;Minimum</td> \
<td bgcolor=”#aaaaaa”>&nbsp;&nbsp;<b>3800</b></td> \
</tr> \
<tr align=”left”> \
<td bgcolor=”#e7e7e7″>&nbsp;&nbsp;Median</td> \
<td bgcolor=”#aaaaaa”>&nbsp;&nbsp;<b>6000</b></td> \
</tr> \
<tr align=”left”> \
<td bgcolor=”#e7e7e7″>&nbsp;&nbsp;Standard Deviation</td> \
<td bgcolor=”#aaaaaa”>&nbsp;&nbsp;<b>6076</b></td> \
</tr> \
</body></table></html>’

class MyFrame(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(400, 290))

        panel = wx.Panel(self, -1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        htmlwin = html.HtmlWindow(panel, -1, style=wx.NO_BORDER)
        htmlwin.SetBackgroundColour(wx.RED)
        htmlwin.SetStandardFonts()
        htmlwin.SetPage(page)

        vbox.Add((-1, 10), 0)
        vbox.Add(htmlwin, 1, wx.EXPAND | wx.ALL, 9)

        bitmap = wx.StaticBitmap(panel, -1, wx.Bitmap(‘images/newt.png’))
        hbox.Add(bitmap, 1, wx.LEFT | wx.BOTTOM | wx.TOP, 10)
        buttonOk = wx.Button(panel, ID_CLOSE, ‘Ok’)

        self.Bind(wx.EVT_BUTTON, self.OnClose, id=ID_CLOSE)

        hbox.Add((100, -1), 1, wx.EXPAND | wx.ALIGN_RIGHT)
        hbox.Add(buttonOk, flag=wx.TOP | wx.BOTTOM | wx.RIGHT, border=10)
        vbox.Add(hbox, 0, wx.EXPAND)

        panel.SetSizer(vbox)
        self.Centre()
        self.Show(True)

    def OnClose(self, event):
        self.Close()

app = wx.App(0)
MyFrame(None, -1, ‘Basic Statistics’)
app.MainLoop()

帮助窗口

#!/usr/bin/python
# helpwindow.py

import wx
import wx.html as html

class HelpWindow(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(570, 400))

        toolbar = self.CreateToolBar()
        toolbar.AddLabelTool(1, ‘Exit’, wx.Bitmap(‘icons/exit.png’))
        toolbar.AddLabelTool(2, ‘Help’, wx.Bitmap(‘icons/help.png’))
        toolbar.Realize()

        self.splitter = wx.SplitterWindow(self, -1)
        self.panelLeft = wx.Panel(self.splitter, -1, style=wx.BORDER_SUNKEN)

        self.panelRight = wx.Panel(self.splitter, -1)
        vbox2 = wx.BoxSizer(wx.VERTICAL)
        header = wx.Panel(self.panelRight, -1, size=(-1, 20))
        header.SetBackgroundColour(‘#6f6a59’)
        header.SetForegroundColour(‘WHITE’)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        st = wx.StaticText(header, -1, ‘Help’, (5, 5))
        font = st.GetFont()
        font.SetPointSize(9)
        st.SetFont(font)
        hbox.Add(st, 1, wx.TOP | wx.BOTTOM | wx.LEFT, 5)

        close = wx.BitmapButton(header, -1, wx.Bitmap(‘icons/fileclose.png’, wx.BITMAP_TYPE_PNG),
        style=wx.NO_BORDER)
        close.SetBackgroundColour(‘#6f6a59’)
        hbox.Add(close, 0)
        header.SetSizer(hbox)

        vbox2.Add(header, 0, wx.EXPAND)

        help = html.HtmlWindow(self.panelRight, -1, style=wx.NO_BORDER)
        help.LoadPage(‘help.html’)
        vbox2.Add(help, 1, wx.EXPAND)
        self.panelRight.SetSizer(vbox2)
        self.panelLeft.SetFocus()

        self.splitter.SplitVertically(self.panelLeft, self.panelRight)
        self.splitter.Unsplit()

        self.Bind(wx.EVT_BUTTON, self.CloseHelp, id=close.GetId())
        self.Bind(wx.EVT_TOOL, self.OnClose, id=1)
        self.Bind(wx.EVT_TOOL, self.OnHelp, id=2)

        self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed)

        self.CreateStatusBar()

        self.Centre()
        self.Show(True)

    def OnClose(self, event):
        self.Close()

    def OnHelp(self, event):
        self.splitter.SplitVertically(self.panelLeft, self.panelRight)
        self.panelLeft.SetFocus()

    def CloseHelp(self, event):
        self.splitter.Unsplit()
        self.panelLeft.SetFocus()

    def OnKeyPressed(self, event):
        keycode = event.GetKeyCode()
        if keycode == wx.WXK_F1:
            self.splitter.SplitVertically(self.panelLeft, self.panelRight)
            self.panelLeft.SetFocus()

app = wx.App()
HelpWindow(None, -1, ‘HelpWindow’)
app.MainLoop()

       这个帮助窗口在开始的时候是处于隐藏状态的。当我们单击工具栏的 Help 按钮或者按 F1 时,帮助窗口会出现在程序的右侧。单击帮助窗口的关闭按钮会让帮助窗口再次隐藏。

 self.splitter.SplitVertically(self.panelLeft, self.panelRight)
 self.splitter.Unsplit()

       我们创建两个垂直分拆开的面板,然后调用 Unsplit() 方法,这将会隐藏右侧的面板。

       我们右侧的面板划分为两部分:Header 和 Body 面板。Header 面板是一个可詷的 wx.Panel,由一个静态文本和位图按钮组成。而 wx.html.HtmlWindow 放置于 Body 面板。

 close = wx.BitmapButton(header, -1, wx.Bitmap(‘icons/fileclose.png’, wx.BITMAP_TYPE_PNG),
    style=wx.NO_BORDER)
 close.SetBackgroundColour(‘#6f6a59’)

       将 Header 面板上的位图按钮的 style 设置为 wx.No_BORDER,背景色设置为面板的颜色。这要,可以使得位图按钮看上去是 Header 面板的一部分。

 help = html.HtmlWindow(self.panelRight, -1, style=wx.NO_BORDER)
 help.LoadPage(‘help.html’)

       我们在右侧的面板创建一个 wx.html.HtmlWindow 控件,但 html 代码放在一个独立的文件里,这时,只需调用 LoadPage() 方法来取得 html 代码。

 self.panelLeft.SetFocus()

       我们要实现按下 F1 时出现帮助窗口,必须令左边的面板取于取得焦点的状态,否则 F1 按键将无效。如果左边面板没有取得焦点,我们需要用鼠标点击左边面板,令到它取得焦点。

    def OnHelp(self, event):
        self.splitter.SplitVertically(self.panelLeft, self.panelRight)
        self.panelLeft.SetFocus()

       OnHelp() 方法会显示帮助窗口,它会将窗口分拆为左右两边。千万不要忘记重设焦点,因为窗口分拆操作会令初始的焦点失去。

<html>

<body bgcolor=”#ababab”>
<h4>Table of Contents</h4>

<ul>
<li><a href=”#basic”>Basic statistics</a></li>
<li><a href=”#advanced”>Advanced statistics</a></li>
<li><a href=”#intro”>Introducing Newt</a></li>
<li><a href=”#charts”>Working with charts</a></li>
<li><a href=”#pred”>Predicting values</a></li>
<li><a href=”#neural”>Neural networks</a></li>
<li><a href=”#glos”>Glossary</a></li>
</ul>

<p>
<a name=”basic”>
<h6>Basic Statistics</h6>
Overview of elementary concepts in statistics.
Variables. Correlation. Measurement scales. Statistical significance.
Distributions. Normality assumption.
</a>
</p>

<p>
<a name=”advanced”>
<h6>Advanced Statistics</h6>
Overview of advanced concepts in statistics. Anova. Linear regression.
Estimation and  hypothesis testing.
Error terms.
</a>
</p>

<p>
<a name=”intro”>
<h6>Introducing Newt</h6>
Introducing the basic functionality of the Newt application. Creating sheets.
Charts. Menus and Toolbars. Importing data. Saving data in various formats.
Exporting data. Shortcuts. List of methods.
</a>
</p>

<p>
<a name=”charts”>
<h6>Charts</h6>
Working with charts. 2D charts. 3D charts. Bar, line, box, pie, range charts.
Scatterplots. Histograms.
</a>
</p>

<p>
<a name=”pred”>
<h6>Predicting values</h6>
Time series and forecasting. Trend Analysis. Seasonality. Moving averages.
Univariate methods. Multivariate methods. Holt-Winters smoothing.
Exponential smoothing. ARIMA. Fourier analysis.
</a>
</p>

<p>
<a name=”neural”>
<h6>Neural networks</h6>
Overview of neural networks. Biology behind neural networks.
Basic artificial Model. Training. Preprocessing. Postprocessing.
Types of neural networks.
</a>
</p>

<p>
<a name=”glos”>
<h6>Glossary</h6>
Terms and definitions in statistics.
</a>
</p>

</body>
</html>

 <li><a href=”#basic”>Basic statistics</a></li>
 …
 <a name=”basic”>

       通常,我们使用 <div id=”basic”> … </div> 这样的标记方法,但 wx.html.HtmlWindow 仅支持第一种标记方法。紧记,wx.html.HtmlWindow 只支持 html 标记语言的一个子集。

wx.ListCtrl 控件

       列表控件,相对于 wx.ListBox 只允许一列数据,wx.ListCtrl 允许多列数据。wx.ListCtrl 有3种不同的使用方式方式:列表视图(list view),报视图(report view)和 图标视图(icon view),分别用三个 style 来控制:wx.LC_REPORT,wx.LC_LIST 和 wx.LC_ICON。

 wx.ListCtrl(wx.Window parent, int id, wx.Point pos = (-1, -1), wx.Size size = (-1, -1),  int style  = wx.LC_ICON, wx.Validator validator = wx.DefaultValidator, string name = wx.ListCtrlNameStr)

       wx.ListCtrl 可选的 style:

  • wx.LC_LIST
  • wx.LC_REPORT
  • wx.LC_VIRTUAL
  • wx.LC_ICON
  • wx.LC_SMALL_ICON
  • wx.LC_ALIGN_LEFT
  • wx.LC_EDIT_LABELS
  • wx.LC_NO_HEADER
  • wx.LC_SORT_ASCENDING
  • wx.LC_SORT_DESCENDING
  • wx.LC_HRULES
  • wx.LC_VRULES

一个简单例子

       仅使用了 wx.ListCtrl 的一些基本功能。

#!/usr/bin/python
# actresses.py

import wx
import sys

packages = [(‘jessica alba’, ‘pomona’, ‘1981’), (‘sigourney weaver’, ‘new york’, ‘1949’),
    (‘angelina jolie’, ‘los angeles’, ‘1975’), (‘natalie portman’, ‘jerusalem’, ‘1981’),
    (‘rachel weiss’, ‘london’, ‘1971’), (‘scarlett johansson’, ‘new york’, ‘1984’ )]

class Actresses(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(380, 230))

        hbox = wx.BoxSizer(wx.HORIZONTAL)
        panel = wx.Panel(self, -1)

        self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)
        self.list.InsertColumn(0, ‘name’, width=140)
        self.list.InsertColumn(1, ‘place’, width=130)
        self.list.InsertColumn(2, ‘year’, wx.LIST_FORMAT_RIGHT, 90)

        for i in packages:
            index = self.list.InsertStringItem(sys.maxint, i[0])
            self.list.SetStringItem(index, 1, i[1])
            self.list.SetStringItem(index, 2, i[2])

        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

app = wx.App()
Actresses(None, -1, ‘actresses’)
app.MainLoop()

 self.list = wx.ListCtrl(panel, -1, style=wx.LC_REPORT)

       设置 wx.ListCtrl 的 style 为 wx.LC_REPORT(列表视图)。

 self.list.InsertColumn(0, ‘name’, width=140)
 self.list.InsertColumn(1, ‘place’, width=130)
 self.list.InsertColumn(2, ‘year’, wx.LIST_FORMAT_RIGHT, 90)

       在列表中插入3列,并且指定列的宽度和格式(默认格式是 wx.LIST_FORMAT_LEFT)。

 for i in packages:
     index = self.list.InsertStringItem(sys.maxint, i[0])
     self.list.SetStringItem(index, 1, i[1])
     self.list.SetStringItem(index, 2, i[2])

       使用 InsertStringItem() 和 SetStringItem() 方法向 wx.ListCtr 插入数据。InsertStringItem() 的第一个参数是指定行号。

Mixins

       Mixins 是 wx.ListCtrl 的一些增强类,位于 wx.lib.mixins.listctrl 模块里。要使用 Mixins 类,必须通过继承来使用。

       到 wxPython 2.8.1.1 为止,有5个可用的 mixins 类:

  • wx.ColumnSorterMixin
  • wx.ListCtrlAutoWidthMixin
  • wx.ListCtrlSelectionManagerMix
  • wx.TextEditMixin
  • wx.CheckListCtrlMixin

       wx.ColumnSorterMixin 允许对列表视图的列进行排序。wx.ListCtrlAutoWidthMixin 可以自动调整最后一列的宽度,以占据剩下的空间。wx.ListCtrlSelectionManagerMix 可以定义平台无关的选择规则。wx.TextEditMinxin 允许列表的项目可编辑。wx.CheckListCtrlMinxin 为第一行添加一个复选框(Check box)。

       在下面的示例中,我们仅仅是对上面的例子作了一小点修改,其中使用了 ListCtrlAutoWidthMixin。

#!/usr/bin/python
# autowidth.py

import wx
import sys
from wx.lib.mixins.listctrl import ListCtrlAutoWidthMixin

actresses = [(‘jessica alba’, ‘pomona’, ‘1981’), (‘sigourney weaver’, ‘new york’, ‘1949’),
    (‘angelina jolie’, ‘los angeles’, ‘1975’), (‘natalie portman’, ‘jerusalem’, ‘1981’),
    (‘rachel weiss’, ‘london’, ‘1971’), (‘scarlett johansson’, ‘new york’, ‘1984’ )]

class AutoWidthListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
        ListCtrlAutoWidthMixin.__init__(self)

class Actresses(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(380, 230))

        hbox = wx.BoxSizer(wx.HORIZONTAL)

        panel = wx.Panel(self, -1)

        self.list = AutoWidthListCtrl(panel)
        self.list.InsertColumn(0, ‘name’, width=140)
        self.list.InsertColumn(1, ‘place’, width=130)
        self.list.InsertColumn(2, ‘year’, wx.LIST_FORMAT_RIGHT, 90)

        for i in actresses:
            index = self.list.InsertStringItem(sys.maxint, i[0])
            self.list.SetStringItem(index, 1, i[1])
            self.list.SetStringItem(index, 2, i[2])

        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

app = wx.App()
Actresses(None, -1, ‘actresses’)
app.MainLoop()

 class AutoWidthListCtrl(wx.ListCtrl, ListCtrlAutoWidthMixin):
     def __init__(self, parent):
         wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
         ListCtrlAutoWidthMixin.__init__(self)

       通过继承,创建自己的 AutowidthListCtrl 类。这样,就可以使得列表的最后一列自动占据剩下的空间。

       下面的例子,将会创建一个可以对数据进行排序的列表。当我们单击列的顶部(Header),对应的列的数据将会重排。

#!/usr/bin/python
# sorted.py

import wx
import sys
from wx.lib.mixins.listctrl import ColumnSorterMixin

actresses = {
1 : (‘jessica alba’, ‘pomona’, ‘1981’),
2 : (‘sigourney weaver’, ‘new york’, ‘1949’),
3 : (‘angelina jolie’, ‘los angeles’, ‘1975’),
4 : (‘natalie portman’, ‘jerusalem’, ‘1981’),
5 : (‘rachel weiss’, ‘london’, ‘1971’),
6 : (‘scarlett johansson’, ‘new york’, ‘1984’)
}

class SortedListCtrl(wx.ListCtrl, ColumnSorterMixin):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT)
        ColumnSorterMixin.__init__(self, len(actresses))
        self.itemDataMap = actresses

    def GetListCtrl(self):
        return self

class Actresses(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(380, 230))

        hbox = wx.BoxSizer(wx.HORIZONTAL)

        panel = wx.Panel(self, -1)

        self.list = SortedListCtrl(panel)
        self.list.InsertColumn(0, ‘name’, width=140)
        self.list.InsertColumn(1, ‘place’, width=130)
        self.list.InsertColumn(2, ‘year’, wx.LIST_FORMAT_RIGHT, 90)

        items = actresses.items()

        for key, data in items:
            index = self.list.InsertStringItem(sys.maxint, data[0])
            self.list.SetStringItem(index, 1, data[1])
            self.list.SetStringItem(index, 2, data[2])
            self.list.SetItemData(index, key)

        hbox.Add(self.list, 1, wx.EXPAND)
        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

app = wx.App()
Actresses(None, -1, ‘actresses’)
app.MainLoop()

 ColumnSorterMixin.__init__(self, len(actresses))

       ColumnSorterMinxin 接受一个参数,指定重排的行数。

 self.itemDataMap = actresses

       必须传递列表将要显示的数据集到 itemDataMap,而且须为字典类型。

 def GetListCtrl(self):
     return self

       必须定义一个 GetListCtrl() 方法,将重排后的 wx.ListCtrl 返回。

 self.list.SetItemData(index, key)

       必须指定一个索引关联到第一行。

Reader

       一个稍为复杂的示例,使用到两个列表控件。

#!/usr/bin/python
# reader.py

import wx

articles = [[‘Mozilla rocks’, ‘The year of the Mozilla’, ‘Earth on Fire’],
            [‘Gnome pretty, Gnome Slow’, ‘Gnome, KDE, Icewm, XFCE’, ‘Where is Gnome heading?’],
            [‘Java number one language’, ‘Compiled languages, intrepreted Languages’, ‘Java on Desktop?’]]

class ListCtrlLeft(wx.ListCtrl):
    def __init__(self, parent, id):
        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT | wx.LC_HRULES |
        wx.LC_NO_HEADER | wx.LC_SINGLE_SEL)
        images = [‘icons/java.png’, ‘icons/gnome.png’, ‘icons/mozilla.png’]

        self.parent = parent

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSelect)

        self.il = wx.ImageList(32, 32)
        for i in images:
            self.il.Add(wx.Bitmap(i))

        self.SetImageList(self.il, wx.IMAGE_LIST_SMALL)
        self.InsertColumn(0, ”)

        for i in range(3):
            self.InsertStringItem(0, ”)
            self.SetItemImage(0, i)

    def OnSize(self, event):
        size = self.parent.GetSize()
        self.SetColumnWidth(0, size.x-5)
        event.Skip()

    def OnSelect(self, event):
        window = self.parent.GetGrandParent().FindWindowByName(‘ListControlOnRight’)
        index = event.GetIndex()
        window.LoadData(index)

    def OnDeSelect(self, event):
        index = event.GetIndex()
        self.SetItemBackgroundColour(index, ‘WHITE’)

    def OnFocus(self, event):
        self.SetItemBackgroundColour(0, ‘red’)

class ListCtrlRight(wx.ListCtrl):
    def __init__(self, parent, id):
        wx.ListCtrl.__init__(self, parent, id, style=wx.LC_REPORT | wx.LC_HRULES |
        wx.LC_NO_HEADER | wx.LC_SINGLE_SEL)

        self.parent = parent

        self.Bind(wx.EVT_SIZE, self.OnSize)

        self.InsertColumn(0, ”)

    def OnSize(self, event):
        size = self.parent.GetSize()
        self.SetColumnWidth(0, size.x-5)
        event.Skip()

    def LoadData(self, index):
        self.DeleteAllItems()
        for i in range(3):
            self.InsertStringItem(0, articles[index][i])

class Reader(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title)

        hbox = wx.BoxSizer(wx.HORIZONTAL)
        splitter = wx.SplitterWindow(self, -1, style=wx.SP_LIVE_UPDATE|wx.SP_NOBORDER)

        vbox1 = wx.BoxSizer(wx.VERTICAL)
        panel1 = wx.Panel(splitter, -1)
        panel11 = wx.Panel(panel1, -1, size=(-1, 40))
        panel11.SetBackgroundColour(‘#53728c’)
        st1 = wx.StaticText(panel11, -1, ‘Feeds’, (5, 5))
        st1.SetForegroundColour(‘WHITE’)

        panel12 = wx.Panel(panel1, -1, style=wx.BORDER_SUNKEN)
        vbox = wx.BoxSizer(wx.VERTICAL)
        list1 = ListCtrlLeft(panel12, -1)

        vbox.Add(list1, 1, wx.EXPAND)
        panel12.SetSizer(vbox)
        panel12.SetBackgroundColour(‘WHITE’)

        vbox1.Add(panel11, 0, wx.EXPAND)
        vbox1.Add(panel12, 1, wx.EXPAND)

        panel1.SetSizer(vbox1)

        vbox2 = wx.BoxSizer(wx.VERTICAL)
        panel2 = wx.Panel(splitter, -1)
        panel21 = wx.Panel(panel2, -1, size=(-1, 40), style=wx.NO_BORDER)
        st2 = wx.StaticText(panel21, -1, ‘Articles’, (5, 5))
        st2.SetForegroundColour(‘WHITE’)

        panel21.SetBackgroundColour(‘#53728c’)
        panel22 = wx.Panel(panel2, -1, style=wx.BORDER_RAISED)
        vbox3 = wx.BoxSizer(wx.VERTICAL)
        list2 = ListCtrlRight(panel22, -1)
        list2.SetName(‘ListControlOnRight’)
        vbox3.Add(list2, 1, wx.EXPAND)
        panel22.SetSizer(vbox3)

        panel22.SetBackgroundColour(‘WHITE’)
        vbox2.Add(panel21, 0, wx.EXPAND)
        vbox2.Add(panel22, 1, wx.EXPAND)

        panel2.SetSizer(vbox2)

        toolbar = self.CreateToolBar()
        toolbar.AddLabelTool(1, ‘Exit’, wx.Bitmap(‘icons/stock_exit.png’))
        toolbar.Realize()

        self.Bind(wx.EVT_TOOL, self.ExitApp, id=1)

        hbox.Add(splitter, 1, wx.EXPAND | wx.TOP | wx.BOTTOM, 5)
        self.SetSizer(hbox)
        self.CreateStatusBar()
        splitter.SplitVertically(panel1, panel2)
        self.Centre()
        self.Show(True)

    def ExitApp(self, event):
        self.Close()

app = wx.App()
Reader(None, -1, ‘Reader’)
app.MainLoop()

       在报表视图,我们显示了两个 wx.ListCtrl 控件,分居程序窗口的左右两侧。

 splitter = wx.SplitterWindow(self, -1, style=wx.SP_LIVE_UPDATE|wx.SP_NOBORDER)
 …
 splitter.SplitVertically(panel1, panel2)

       将窗口垂直拆分为两部分。

 def OnSelect(self, event):
     window = self.parent.GetGrandParent().FindWindowByName(‘ListControlOnRight’)
     index = event.GetIndex()
     window.LoadData(index)

       这是 ListCtrlLeft 列表的方法定义,我们通过 LoadData() 方法来取得数据。

 def LoadData(self, index):
     self.DeleteAllItems()
     for i in range(3):
         self.InsertStringItem(0, articles[index][i])

       首先清除列表的所有数据,现将 articles 的数据插入到列表。

 def OnSize(self, event):
     size = self.parent.GetSize()
     self.SetColumnWidth(0, size.x-5)
     event.Skip()

       设置列宽,使得跟上级面板一致。注意,腾出 5px 是为了适应滚动条。

CheckListCtrl

#!/usr/bin/python
# repository.py

import wx
import sys
from wx.lib.mixins.listctrl import CheckListCtrlMixin, ListCtrlAutoWidthMixin

packages = [(‘abiword’, ‘5.8M’, ‘base’), (‘adie’, ‘145k’, ‘base’),
    (‘airsnort’, ’71k’, ‘base’), (‘ara’, ‘717k’, ‘base’), (‘arc’, ‘139k’, ‘base’),
    (‘asc’, ‘5.8M’, ‘base’), (‘ascii’, ’74k’, ‘base’), (‘ash’, ’74k’, ‘base’)]

class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
    def __init__(self, parent):
        wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
        CheckListCtrlMixin.__init__(self)
        ListCtrlAutoWidthMixin.__init__(self)

class Repository(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(450, 400))

        panel = wx.Panel(self, -1)

        vbox = wx.BoxSizer(wx.VERTICAL)
        hbox = wx.BoxSizer(wx.HORIZONTAL)

        leftPanel = wx.Panel(panel, -1)
        rightPanel = wx.Panel(panel, -1)

        self.log = wx.TextCtrl(rightPanel, -1, style=wx.TE_MULTILINE)
        self.list = CheckListCtrl(rightPanel)
        self.list.InsertColumn(0, ‘Package’, width=140)
        self.list.InsertColumn(1, ‘Size’)
        self.list.InsertColumn(2, ‘Repository’)

        for i in packages:
            index = self.list.InsertStringItem(sys.maxint, i[0])
            self.list.SetStringItem(index, 1, i[1])
            self.list.SetStringItem(index, 2, i[2])

        vbox2 = wx.BoxSizer(wx.VERTICAL)

        sel = wx.Button(leftPanel, -1, ‘Select All’, size=(100, -1))
        des = wx.Button(leftPanel, -1, ‘Deselect All’, size=(100, -1))
        apply = wx.Button(leftPanel, -1, ‘Apply’, size=(100, -1))

        self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=sel.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=des.GetId())
        self.Bind(wx.EVT_BUTTON, self.OnApply, id=apply.GetId())

        vbox2.Add(sel, 0, wx.TOP, 5)
        vbox2.Add(des)
        vbox2.Add(apply)

        leftPanel.SetSizer(vbox2)

        vbox.Add(self.list, 1, wx.EXPAND | wx.TOP, 3)
        vbox.Add((-1, 10))
        vbox.Add(self.log, 0.5, wx.EXPAND)
        vbox.Add((-1, 10))

        rightPanel.SetSizer(vbox)

        hbox.Add(leftPanel, 0, wx.EXPAND | wx.RIGHT, 5)
        hbox.Add(rightPanel, 1, wx.EXPAND)
        hbox.Add((3, -1))

        panel.SetSizer(hbox)

        self.Centre()
        self.Show(True)

    def OnSelectAll(self, event):
        num = self.list.GetItemCount()
        for i in range(num):
            self.list.CheckItem(i)

    def OnDeselectAll(self, event):
        num = self.list.GetItemCount()
        for i in range(num):
            self.list.CheckItem(i, False)

    def OnApply(self, event):
        num = self.list.GetItemCount()
        for i in range(num):
            if i == 0: self.log.Clear()
            if self.list.IsChecked(i):
                self.log.AppendText(self.list.GetItemText(i) + ‘\n’)

app = wx.App()
Repository(None, -1, ‘Repository’)
app.MainLoop()

Advertisements

3条回应 to “wxPython:高级控件”

  1. Ross Wan said

    翻译自:The wxPython tutorial

  2. 非常感谢你的工作。

  3. 谢谢博主,我看手册看的头大,您的文章很棒!

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s

 
%d 博主赞过: