在這一章中,我們將討論以下高級部件: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()
方法標記當前複選框。