在这一章中,我们将讨论以下高级部件:wx.ListBox、wx.html.HtmlWindow、wx.ListCtrl。
wxPython有几个著名的高级部件。例如树形组件、HTML 窗口、网格部件、listbox 部件、列表部件或具有高级样式功能的编辑器。
wx.ListBox
用于显示和处理一个项目列表。 wx.ListBox
可以在两种不同的状态下创建:单选状态或多选状态。单选状态是默认状态。
wx.ListBox
中有两个重要事件。第一个是 wx.EVT_COMMAND_LISTBOX_SELECTED
事件。当我们在 wx.ListBox
中选择一个项目时,就会产生这个事件。第二个是 wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED
事件。当我们双击 wx.ListBox
中的一个项目时,就会产生这个事件。元素从零开始编号。如果需要,滚动条会自动显示。
很多人学习python,不知道从何学起。
很多人学习python,掌握了基本语法过后,不知道在哪里寻找案例上手。
很多已经做案例的人,却不知道如何去学习更加高深的知识。
那么针对这三类人,我给大家提供一个好的学习平台,免费领取****,电子书籍,以及课程的源代码!??¤
QQ群:1057034340
我们创建一个空的wx.ListBox。我们在列表框周围加上一个20px的边框。
self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnRename)
我们使用wx.EVT_COMMAND_LISTBOX_DOUBLE_CLICKED事件绑定器与OnRename()方法绑定一个wx.EVT_LISTBOX_DCLICK事件类型。这样,如果我们双击列表框中的一个特定元素,我们就会显示一个重命名对话框。
我们通过点击New按钮来调用NewItem()方法。该方法使用包装器wx.GetTextFromUser()方法显示了一个wx.TextEntryDialog。我们输入的文本会返回到文本变量中。如果文本不是空的,我们就用Append()方法将其追加到列表框中。
我们通过删除一个项目,并在同一位置插入一个新的项目来重新命名它。我们还将选区设置回修改后的项目。
要删除一个项目,我们通过调用GetSelection()方法找到所选项目的索引。然后我们用Delete()方法删除这个项目。Delete()方法的参数是选中的索引。
最简单的就是清除整个列表框。我们只需调用Clear()方法。
wx.html.HtmlWindow
组件显示HTML页面。它不是一个成熟的浏览器。我们可以用 wx.html.HtmlWindow
组件做一些有趣的事情。
例如,在下面的程序中,我们创建了一个显示基本统计数据的窗口。
这是要显示的HTML页面。
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030141835060.png" alt="image-20201030141835060" style="zoom:50%;" />
本例在wx.html.HtmlWindow widget中派发一个HTML文件。
htmlwin = wx.html.HtmlWindow(panel, wx.ID_ANY, style=wx.NO_BORDER) htmlwin.SetStandardFonts() htmlwin.LoadPage("page.html")
wx.html.HtmlWindow被创建。用LoadPage()方法加载HTML文件。
我们可以使用wx.html.HtmlWindow来为我们的应用程序提供帮助。我们可以创建一个独立的窗口,也可以创建一个将成为应用程序一部分的窗口。下面的脚本将使用后者来创建一个帮助窗口。
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030142310825.png" alt="image-20201030142310825" style="zoom:50%;" />
帮助窗口在一开始是隐藏的,我们可以通过点击工具栏上的帮助按钮或按F1键来显示它。我们可以通过点击工具栏上的 "帮助 "按钮或按F1键来显示它。帮助窗口就会出现在应用程序的右侧。要隐藏帮助窗口,我们点击关闭按钮。
self.splitter.SplitVertically(self.panelLeft, self.panelRight) self.splitter.Unsplit()
我们创建左面板和右面板,并将它们垂直分割。之后,我们调用 Unsplit()
方法。默认情况下,该方法会隐藏右侧或底部面板。
我们将右面板分为两个部分。头部和面板的主体。头部是一个调整后的 wx.Panel
。头部由一个静态文本和一个位图按钮组成。我们把 wx.html.Window
放到面板的主体中。
closeBtn = wx.BitmapButton(header, wx.ID_ANY, wx.Bitmap('closebutton.png', wx.BITMAP_TYPE_PNG), style=wx.NO_BORDER) closeBtn.SetBackgroundColour('#6f6a59')
位图按钮样式设置为wx.NO_BORDER。背景颜色被设置为标题面板的颜色,这样做是为了使按钮看起来像标题的一部分。这样做的目的是为了使按钮作为头的一部分出现。
helpWin = html.HtmlWindow(self.panelRight, style=wx.NO_BORDER) helpWin.LoadPage('page.html')
我们在右侧面板上创建一个 wx.html.HtmlWindow
小部件。我们的HTML代码在一个单独的文件中。这次我们调用 LoadPage()
方法来获取HTML代码。
self.panelLeft.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) self.panelLeft.SetFocus()
我们将焦点设置在左侧面板。我们可以用F1键启动帮助窗口。为了用键盘控制一个窗口,它必须有焦点。如果我们不设置焦点,我们就必须先点击面板,只有这样我们才能用按F1键启动帮助窗口。
def OnHelp(self, e): self.splitter.SplitVertically(self.panelLeft, self.panelRight) self.panelLeft.SetFocus()
为了显示帮助窗口,我们调用OnHelp()方法。它将两个面板垂直分割。我们不要忘记再次设置焦点,因为初始焦点会因为分割而丢失。
wx.ListCtrl是一个项目列表的图形表示。一个wx.ListBox只能有一列,而wx.ListCtrl可以有多于一列。例如,一个文件管理器使用wx.ListCtrl来显示文件系统中的目录和文件。一个CD刻录程序在wx.ListCtrl中显示要刻录的文件。
一个wx.ListCtrl可以以三种不同的样式使用。列表视图、报告视图或图标视图。这些样式由wx.ListCtrl窗口样式控制,wx.LC_REPORT、wx.LC_LIST和wx.LC_ICON。
wx.ListCtrl 例子
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030142803996.png" alt="image-20201030142803996" style="zoom:50%;" />
该代码示例在 wx.ListCtrl
中显示有关女演员的数据。
self.list = wx.ListCtrl(panel, wx.ID_ANY, style=wx.LC_REPORT)
我们创建一个具有 wx.LC_REPORT
风格的 wx.ListCtrl
。
self.list.InsertColumn(0, 'name', width=140) self.list.InsertColumn(1, 'place', width=130) self.list.InsertColumn(2, 'year', wx.LIST_FORMAT_RIGHT, 90)
我们插入三列。我们可以指定列的宽度和列的格式。默认的格式是wx.LIST_FORMAT_LEFT。
idx = 0 for i in data: index = self.list.InsertItem(idx, i[0]) self.list.SetItem(index, 1, i[1]) self.list.SetItem(index, 2, i[2]) idx += 1
我们使用两个方法将数据插入到 wx.ListCtrl
中。每一行都以 InsertItem()
方法开始。该方法的第一个参数指定了行号。该方法返回行的索引。 SetItem()
方法将数据添加到当前行的连续列中。
Mixins
Mixins是进一步增强 wx.ListCtrl
功能的类。它们位于 wx.lib.mixins.listctrl
模块中。为了使用它们,我们必须继承这些类的功能。
有六个 mixins。
wx.ColumnSorterMixin
是一个能够在报表视图中对列进行排序的mixin。 wx.ListCtrlAutoWidthMixin
类可以自动调整最后一列的大小到 wx.ListCtrl
的末端。默认情况下,最后一列不占用剩余空间。请看前面的例子。 wx.ListCtrlSelectionManagerMix
定义了独立于平台的选择策略。 wx.TextEditMixin
可以编辑文本。 wx.CheckListCtrlMixin
为每一行添加一个复选框。这样我们就可以控制行。我们可以将每一行设置为选中或不选中。 wx.ListRowHighlighter
处理 wx.ListCtrl
中交替行的自动背景高亮。
wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin
下面的代码显示了我们如何使用 wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin
#autowidth.py import wx import wx.lib.mixins.listctrl data = [('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, wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin): def __init__(self, parent, *args, **kw): wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT) wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin.__init__(self)
class Example(wx.Frame): def __init__(self, *args, **kw): super(Example, self).__init__(*args, **kw) self.InitUI() def InitUI(self): hbox = wx.BoxSizer(wx.HORIZONTAL) panel = wx.Panel(self) 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) idx = 0 for i in data: index = self.list.InsertItem(idx, i[0]) self.list.SetItem(index, 1, i[1]) self.list.SetItem(index, 2, i[2]) idx += 1 hbox.Add(self.list, 1, wx.EXPAND) panel.SetSizer(hbox) self.SetTitle('Actresses') self.Centre() def main(): app = wx.App() ex = Example(None) ex.Show() app.MainLoop() if __name__ == '__main__': main()
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030143105149.png" alt="image-20201030143105149" style="zoom:50%;" />
我们把前面的例子改一下。
import wx.lib.mixins.listctrl
这里我们导入 mixin 模块。
class AutoWidthListCtrl(wx.ListCtrl, wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin): def __init__(self, parent, *args, **kw): wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT) wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin.__init__(self)
我们创建一个新的 AutoWidthListCtrl
类。这个类继承自 wx.ListCtrl
和 wx.lib.mixins.listctrl.ListCtrlAutoWidthMixin
。这就是所谓的 多继承 。最后一列会自动调整大小以占用 wx.ListCtrl
的剩余宽度。
wx.lib.mixins.listctrl.ColumnSorterMixin
下面的例子创建了可排序的列。如果我们点击列头,列中相应的行就会被排序。
#sorted.py import wx import wx.lib.mixins.listctrl 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, wx.lib.mixins.listctrl.ColumnSorterMixin): def __init__(self, parent): wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT) wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self, len(actresses)) self.itemDataMap = actresses def GetListCtrl(self): return self class Example(wx.Frame): def __init__(self, *args, **kw): super(Example, self).__init__(*args, **kw) self.InitUI() def InitUI(self): hbox = wx.BoxSizer(wx.HORIZONTAL) panel = wx.Panel(self) 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() idx = 0 for key, data in items: index = self.list.InsertItem(idx, data[0]) self.list.SetItem(index, 1, data[1]) self.list.SetItem(index, 2, data[2]) self.list.SetItemData(index, key) idx += 1 hbox.Add(self.list, 1, wx.EXPAND) panel.SetSizer(hbox) self.SetTitle('Actresses') self.Centre() def main(): app = wx.App() ex = Example(None) ex.Show() app.MainLoop() if __name__ == '__main__': main()
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030143320812.png" alt="image-20201030143320812" style="zoom:50%;" />
我们再以女演员为例。
wx.lib.mixins.listctrl.ColumnSorterMixin.__init__(self, len(actresses))
wx.lib.mixins.listctrl.ColumnSorterMixin
接受一个参数:要排序的列数。
self.itemDataMap = actresses
我们必须将我们要显示在列表控件中的数据映射到 itemDataMap
属性中。数据必须是一个字典数据类型。
def GetListCtrl(self): return self
我们必须创建一个GetListCtrl()方法。这个方法返回要排序的wx.ListCtrl部件。
self.list.SetItemData(index, key)
我们必须为每一行分配一个特殊的索引。这是通过 SetItemData
方法完成的。
列表控件中可以放置一个复选框。在wxPython中,我们可以使用 wx.lib. mixins.listctrl.CheckListCtrl
。
#repository.py import wx 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, wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER) CheckListCtrlMixin.__init__(self) ListCtrlAutoWidthMixin.__init__(self) class Example(wx.Frame): def __init__(self, *args, **kw): super(Example, self).__init__(*args, **kw) panel = wx.Panel(self) vbox = wx.BoxSizer(wx.VERTICAL) hbox = wx.BoxSizer(wx.HORIZONTAL) leftPanel = wx.Panel(panel) rightPanel = wx.Panel(panel) self.log = wx.TextCtrl(rightPanel, style=wx.TE_MULTILINE|wx.TE_READONLY) self.list = CheckListCtrl(rightPanel) self.list.InsertColumn(0, 'Package', width=140) self.list.InsertColumn(1, 'Size') self.list.InsertColumn(2, 'Repository') idx = 0 for i in packages: index = self.list.InsertItem(idx, i[0]) self.list.SetItem(index, 1, i[1]) self.list.SetItem(index, 2, i[2]) idx += 1 vbox2 = wx.BoxSizer(wx.VERTICAL) selBtn = wx.Button(leftPanel, label='Select All') desBtn = wx.Button(leftPanel, label='Deselect All') appBtn = wx.Button(leftPanel, label='Apply') self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=selBtn.GetId()) self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=desBtn.GetId()) self.Bind(wx.EVT_BUTTON, self.OnApply, id=appBtn.GetId()) vbox2.Add(selBtn, 0, wx.TOP|wx.BOTTOM, 5) vbox2.Add(desBtn, 0, wx.BOTTOM, 5) vbox2.Add(appBtn) leftPanel.SetSizer(vbox2) vbox.Add(self.list, 4, wx.EXPAND | wx.TOP, 3) vbox.Add((-1, 10)) vbox.Add(self.log, 1, 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.SetTitle('Repository') self.Centre() 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') def main(): app = wx.App() ex = Example(None) ex.Show() app.MainLoop() if __name__ == '__main__': main()
<img src="https://mymarkdowm.oss-cn-beijing.aliyuncs.com/markdownimg/image-20201030143806315.png" alt="image-20201030143806315" style="zoom:50%;" />
这个例子用 wx.lib.mixins.listctrl.CheckListCtrl
创建了一个版本库UI。
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin): def __init__(self, parent): wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style=wx.LC_REPORT | wx.SUNKEN_BORDER) CheckListCtrlMixin.__init__(self) ListCtrlAutoWidthMixin.__init__(self)
我们从三个不同的类中继承。
def OnSelectAll(self, event): num = self.list.GetItemCount() for i in range(num): self.list.CheckItem(i)
OnSelectAll()
方法选择所有的复选框。 GetItemCount()
确定项数, CheckItem()
方法标记当前复选框。