实战wxPython:047 - Book控件(第一部分)

2023-11-15

在wxPython中,book控件允许用户在各种面板之间切换。最常见的例子是带有选项卡界面的浏览器和系统选项对话框。本文将向您介绍这些控件的创建和基本配置。

wxPython目前内置了多个这样的控件,除文章"wxPython-高级控件之选项卡Notebook"介绍了wx.NoteBook选项卡控件外,我们将分两篇文章来介绍剩下的这些控件。

一、准备工作

为了方便演示各种Book控件的页面切换,我们首先准备了三个独立的页面,它们都继承自wx.Panel,分别将这三个页面命名为panelOne, panelTwo和panelThree。

panelOne.py

import wx

class TabPanel(wx.Panel):
    """
    This will be the first notebook tab
    """
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """"""
        
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        txtOne = wx.TextCtrl(self, wx.ID_ANY, "")
        txtTwo = wx.TextCtrl(self, wx.ID_ANY, "")
        
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(txtOne, 0, wx.ALL, 5)
        sizer.Add(txtTwo, 0, wx.ALL, 5)
        
        self.SetSizer(sizer)
        
         
class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Panel Tutorial")
        panel = TabPanel(self)
        self.Show()
        
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App()
    frame = DemoFrame()
    app.MainLoop()

panelOne面板创建了两个按垂直方向排列的单行文本编辑框。

 图1:panelOne

panelTwo.py

import wx
import  wx.lib.mixins.listctrl  as  listmix

musicdata = {
1 : ("Bad English", "The Price Of Love", "Rock"),
2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"),
3 : ("George Michael", "Praying For Time", "Rock"),
4 : ("Gloria Estefan", "Here We Are", "Rock"),
5 : ("Linda Ronstadt", "Don't Know Much", "Rock"),
6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"),
7 : ("Paul Young", "Oh Girl", "Rock"),
8 : ("Paula Abdul", "Opposites Attract", "Rock"),
9 : ("Richard Marx", "Should've Known Better", "Rock"),
10: ("Rod Stewart", "Forever Young", "Rock"),
11: ("Roxette", "Dangerous", "Rock"),
12: ("Sheena Easton", "The Lover In Me", "Rock"),
13: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock"),
14: ("Stevie B.", "Because I Love You", "Rock"),
15: ("Taylor Dayne", "Love Will Lead You Back", "Rock"),
16: ("The Bangles", "Eternal Flame", "Rock"),
17: ("Wilson Phillips", "Release Me", "Rock"),
18: ("Billy Joel", "Blonde Over Blue", "Rock"),
19: ("Billy Joel", "Famous Last Words", "Rock"),
20: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock"),
21: ("Billy Joel", "The River Of Dreams", "Rock"),
22: ("Billy Joel", "Two Thousand Years", "Rock")
}

class TestListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin):
    def __init__(self, parent, ID, pos=wx.DefaultPosition,
                 size=wx.DefaultSize, style=0):
        wx.ListCtrl.__init__(self, parent, ID, pos, size, style)
        listmix.ListCtrlAutoWidthMixin.__init__(self)
        
class TabPanel(wx.Panel, listmix.ColumnSorterMixin):
    """
    This will be the second notebook tab
    """
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """"""
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
        self.createAndLayout()
        
    def createAndLayout(self):
        sizer = wx.BoxSizer(wx.VERTICAL)
        self.list = TestListCtrl(self, wx.ID_ANY, style=wx.LC_REPORT
                                 | wx.BORDER_NONE
                                 | wx.LC_EDIT_LABELS
                                 | wx.LC_SORT_ASCENDING)
        sizer.Add(self.list, 1, wx.EXPAND)
        self.populateList()
        # Now that the list exists we can init the other base class,
        # see wx/lib/mixins/listctrl.py
        self.itemDataMap = musicdata
        listmix.ColumnSorterMixin.__init__(self, 3)
        self.SetSizer(sizer)
        self.SetAutoLayout(True)
        
    def populateList(self):
        self.list.InsertColumn(0, "Artist")
        self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT)
        self.list.InsertColumn(2, "Genre")
        items = musicdata.items()
        
        for key, data in items:
            index = self.list.InsertItem(0, data[0])
            self.list.SetItem(index, 1, data[1])
            self.list.SetItem(index, 2, data[2])
            self.list.SetItemData(index, key)

        self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE)
        self.list.SetColumnWidth(2, 100)

        # show how to select an item
        self.list.SetItemState(5, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED)

        # show how to change the colour of a couple items
        item = self.list.GetItem(1)
        item.SetTextColour(wx.BLUE)
        self.list.SetItem(item)
        item = self.list.GetItem(4)
        item.SetTextColour(wx.RED)
        self.list.SetItem(item)

        self.currentItem = 0
        
    # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py
    def GetListCtrl(self):
        return self.list
         
class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Panel Tutorial")
        panel = TabPanel(self)
        self.Show()
        
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App()
    frame = DemoFrame()
    app.MainLoop()

panelTwo面板添加了一个ListCtrl控件,用来显示乐队歌手所唱的歌曲列表。

 图2:panelTwo

panelThree.py

import wx
import wx.gizmos as gizmos

class TabPanel(wx.Panel):
    """
    This will be the third notebook tab
    """
    #----------------------------------------------------------------------
    def __init__(self, parent):
        """"""
        wx.Panel.__init__(self, parent=parent, id=wx.ID_ANY)
        
        self.Bind(wx.EVT_SIZE, self.OnSize)

        self.tree = gizmos.TreeListCtrl(self, -1, style =
                                        wx.TR_DEFAULT_STYLE
                                        | wx.TR_FULL_ROW_HIGHLIGHT
                                        )

        isz = (16,16)
        il = wx.ImageList(isz[0], isz[1])
        fldridx     = il.Add(self.GetImage("folder.png"))
        fldropenidx = il.Add(self.GetImage("file_open.png"))
        fileidx     = il.Add(self.GetImage("file_normal.png"))
        bulbidx     = il.Add(self.GetImage("tip.png"))

        self.tree.SetImageList(il)
        self.il = il

        # create some columns
        self.tree.AddColumn("主列")
        self.tree.AddColumn("列1")
        self.tree.AddColumn("列2")
        self.tree.SetMainColumn(0) # the one with the tree in it...
        self.tree.SetColumnWidth(0, 175)

        self.root = self.tree.AddRoot("The Root Item")
        self.tree.SetItemText(self.root, "col 1 root", 1)
        self.tree.SetItemText(self.root, "col 2 root", 2)
        self.tree.SetItemImage(self.root, fldridx, which = wx.TreeItemIcon_Normal)
        self.tree.SetItemImage(self.root, fldropenidx, which = wx.TreeItemIcon_Expanded)

        for x in range(15):
            txt = "Item %d" % x
            child = self.tree.AppendItem(self.root, txt)
            self.tree.SetItemText(child, txt + "(c1)", 1)
            self.tree.SetItemText(child, txt + "(c2)", 2)
            self.tree.SetItemImage(child, fldridx, which = wx.TreeItemIcon_Normal)
            self.tree.SetItemImage(child, fldropenidx, which = wx.TreeItemIcon_Expanded)

            for y in range(5):
                txt = "item %d-%s" % (x, chr(ord("a")+y))
                last = self.tree.AppendItem(child, txt)
                self.tree.SetItemText(last, txt + "(c1)", 1)
                self.tree.SetItemText(last, txt + "(c2)", 2)
                self.tree.SetItemImage(last, fldridx, which = wx.TreeItemIcon_Normal)
                self.tree.SetItemImage(last, fldropenidx, which = wx.TreeItemIcon_Expanded)

                for z in range(5):
                    txt = "item %d-%s-%d" % (x, chr(ord("a")+y), z)
                    item = self.tree.AppendItem(last,  txt)
                    self.tree.SetItemText(item, txt + "(c1)", 1)
                    self.tree.SetItemText(item, txt + "(c2)", 2)
                    self.tree.SetItemImage(item, fileidx, which = wx.TreeItemIcon_Normal)
                    self.tree.SetItemImage(item, bulbidx, which = wx.TreeItemIcon_Selected)

        self.tree.Expand(self.root)

        self.tree.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
        self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate)

    def GetImage(self, filename, w=16, h=16):
        #img = wx.Image(filename, "image/png").Scale(w,h) #通过wx.Image 加载图片,并缩放图片到长宽为w,w的尺寸
        img = wx.Bitmap(filename, wx.BITMAP_TYPE_ANY).ConvertToImage().Scale(w, h) #将位图转换为图片后在改变尺寸
        return wx.Bitmap(img, wx.BITMAP_SCREEN_DEPTH)

    def OnActivate(self, evt):
        print('OnActivate: %s' % self.tree.GetItemText(evt.GetItem()))
        
    def OnRightUp(self, evt):
        pos = evt.GetPosition()
        item, flags, col = self.tree.HitTest(pos)
        if item:
            print('Flags: %s, Col:%s, Text: %s' % (flags, col, self.tree.GetItemText(item, col)))

    def OnSize(self, evt):
        self.tree.SetSize(self.GetSize())
        
         
class DemoFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self, None, wx.ID_ANY, "Panel Tutorial")
        panel = TabPanel(self)
        self.Show()
        
#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App()
    frame = DemoFrame()
    app.MainLoop()

panelThree面板中添加了一个树形控件TreeListCtrl按树状方式显示一些子项。

 图3:panelThree

二、wx.Choicebook

wx.Choicebook是一个类似wx.Notebook的控件,使用wx.Choice控件来显示标签。因此它允许用户单击下拉控件来选择要查看的页面。Choicebook继承自wx.BookCtrlBase,所以它具有与wx.Notebook相同的大部分方法。

wx.Choicebook支持的窗口样式

  • wx.CHB_DEFAULT:根据当前平台为标签选择默认位置(默认为wx.CHB_TOP)。
  • wx.CHB_TOP:在页面区域上方放置标签。
  • wx.CHB_LEFT:在页面区域左边放置标签。
  • wx.CHB_RIGHT:在页面区域右边放置标签。
  • wx.CHB_BOTTOM:在页面区域下方放置标签。

wx.Choicebook发出的消息:

  • EVT_CHOICEBOOK_PAGE_CHANGED:页面选择发生改变后发出。
  • EVT_CHOICEBOOK_PAGE_CHANGING:页面选择发生改变时发出。

三、wx.Choicebook演示

#wx.Choicebook

import wx
import panelOne, panelTwo, panelThree

class MyChoicebook(wx.Choicebook):
    
    def __init__(self, parent):
        wx.Choicebook.__init__(self, parent, wx.ID_ANY)
        
        # 创建第一个页面, 并添加到Choicebook
        tabOne = panelOne.TabPanel(self)
        tabOne.SetBackgroundColour("Gray")
        self.AddPage(tabOne, "页面一")

        # 创建第二个页面, 并添加到Choicebook
        tabTwo = panelTwo.TabPanel(self)
        self.AddPage(tabTwo, "页面二")

        # 创建第三个页面, 并添加到Choicebook
        self.AddPage(panelThree.TabPanel(self), "页面三")

        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)

    def OnPageChanged(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanged,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

    def OnPageChanging(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanging,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

class SampleChoicebook(wx.Frame):

    def __init__(self, *args, **kw):
        super(SampleChoicebook, self).__init__(*args, **kw)

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: Choicebook演示")
        self.SetSize(600, 400)

        panel = wx.Panel(self)

        notebook = MyChoicebook(panel)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)
        self.Layout()

        self.Centre()

def main():
    app = wx.App()
    sample = SampleChoicebook(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

上面的代码演示了使用wx.Choicebook的AddPage方法添加三个页面,使用wx.Choice下拉列表选择就可以在不同的页面之间切换。

 图4:wx.Choicebook演示

四、wx.Listbook

wx.Listbook是一个类似于wx.Notebook的类,但它使用wx.ListCtrl来显示标签。默认情况下,底层wx.ListCtrl在单列报表视图中显示页面标签。调用wx.BookCtr.SetImageList将隐式地切换控件以使用图标视图。

与Choicebook一样,此控件继承自BookCtrlBase并具有相同的方法。主要的区别似乎在于列表的外观和它独特的事件集。

wx.Listbook支持的窗口样式

  • wx.LB_DEFAULT:根据当前平台为标签选择默认位置。
  • wx.LB_TOP:在页面区域上方放置标签。
  • wx.LB_LEFT:在页面区域左边放置标签。
  • wx.LB_RIGHT:在页面区域右边放置标签。
  • wx.LB_BOTTOM:在页面区域下方放置标签。

wx.Listbook发出的消息:

  • EVT_LISTBOOK_PAGE_CHANGED:页面选择发生改变后发出。
  • EVT_LISTBOOK_PAGE_CHANGING:页面选择发生改变时发出。

五、wx.Listbook演示

#wx.Listbook

import wx
import panelOne, panelTwo, panelThree

class MyListbook(wx.Listbook):
    
    def __init__(self, parent):
        wx.Listbook.__init__(self, parent, wx.ID_ANY) 

        img_list= wx.ImageList(32, 32)
        img_list.Add(wx.Bitmap("img01.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img02.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img03.png", wx.BITMAP_TYPE_ANY)) 
        self.AssignImageList(img_list)

        pages = [(panelOne.TabPanel(self), "页面一"),
                 (panelTwo.TabPanel(self), "页面二"),
                 (panelThree.TabPanel(self), "页面三")]

        img_id = 0
        for page,label in pages:
            self.AddPage(page, label, imageId=img_id)
            img_id += 1

        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)

    def OnPageChanged(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanged,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

    def OnPageChanging(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanging,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

class SampleListbook(wx.Frame):

    def __init__(self, *args, **kw):
        super(SampleListbook, self).__init__(*args, **kw)

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: Listbook演示")
        self.SetSize(600, 400)

        panel = wx.Panel(self)

        notebook = MyListbook(panel)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)
        self.Layout()

        self.Centre()

def main():
    app = wx.App()
    sample = SampleListbook(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

就像wx.Notebook一样, wx.Listbook的“tab”控件可以设置在任意边。

 图5:wx.Listbook演示

六、wx.Toolbook

wx.Toolbook是一个类似于wx.Notebook的类,但它使用wx.ToolBar来显示标签。可以看作是一个wx.Toolbar加上一个wx.Notebook构成wx.Toolbook。这意味着可以使用带标签的位图按钮来控制您正在查看的笔记本的哪个“选项卡”。

wx.Toolbook支持的窗口样式

  • wx.TBK_BUTTONBAR:在macOS下使用基于wx.buttontoolbar的实现(在其他平台下忽略)。
  • wx.TBK_HORZ_LAYOUT:在旁边显示文本和图标,而不是垂直堆叠(仅在Windows和GTK 2平台下实现,因为它依赖于wx.TB_HORZ_LAYOUT标志支持)。

wx.Listbook发出的消息:

  • EVT_TOOLBOOK_PAGE_CHANGED:页面选择发生改变后发出。
  • EVT_TOOLBOOK_PAGE_CHANGING:页面选择发生改变时发出。

七、wx.Toolbook演示

#wx.Toolbook

import wx
import panelOne, panelTwo, panelThree

class MyToolbook(wx.Toolbook):
    
    def __init__(self, parent):
        wx.Toolbook.__init__(self, parent, wx.ID_ANY) 

        img_list= wx.ImageList(32, 32)
        img_list.Add(wx.Bitmap("img01.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img02.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img03.png", wx.BITMAP_TYPE_ANY)) 
        self.AssignImageList(img_list)

        pages = [(panelOne.TabPanel(self), "页面一"),
                 (panelTwo.TabPanel(self), "页面二"),
                 (panelThree.TabPanel(self), "页面三")]

        img_id = 0
        for page,label in pages:
            self.AddPage(page, label, imageId=img_id)
            img_id += 1

        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)

    def OnPageChanged(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanged,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

    def OnPageChanging(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanging,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

class SampleToolbook(wx.Frame):

    def __init__(self, *args, **kw):
        super(SampleToolbook, self).__init__(*args, **kw)

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: Toolbook演示")
        self.SetSize(600, 400)

        panel = wx.Panel(self)

        notebook = MyToolbook(panel)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)
        self.Layout()

        self.Centre()

def main():
    app = wx.App()
    sample = SampleToolbook(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

wx.Toolbook的外观和wx.Listbook有些类似,但是其选项卡切换方式采用wx.ToolBar方式实现。

 图6:wx.Toolbook演示

八、wx.Treebook

wx.Treebook是wx.Notebook类的扩展,它允许在控件中显示树状结构的页面集。它可以看作是wx.TreeCtrl和wx.Notebook的组合。

创建wx.Treebook对象后,使用InsertPage()、InsertSubPage()、AddPage()、AddSubPage()即可填充页面。如果树深度不超过1层,那么可以简单地使用AddPage()和AddSubPage()通过在树的每一步添加一个页面或子页面到树的末尾来顺序填充的树。

wx.Treebook发送的事件

  • EVT_TREEBOOK_PAGE_CHANGED:页面选择发生改变后发出。
  • EVT_TREEBOOK_PAGE_CHANGING:页面选择发生改变时发出。
  • EVT_TREEBOOK_NODE_COLLAPSED:页面节点被折叠时发出。
  • EVT_TREEBOOK_NODE_EXPANDED:页面节点被展开时发出。

九、wx.Treebook演示

#wx.Treebook

import wx
import panelOne, panelTwo, panelThree

class MyTreebook(wx.Treebook):
    
    def __init__(self, parent):
        wx.Treebook.__init__(self, parent, wx.ID_ANY) 

        img_list= wx.ImageList(32, 32)
        img_list.Add(wx.Bitmap("img01.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img02.png", wx.BITMAP_TYPE_ANY))
        img_list.Add(wx.Bitmap("img03.png", wx.BITMAP_TYPE_ANY)) 
        self.AssignImageList(img_list)

        pages = [(panelOne.TabPanel(self), "页面一"),
                 (panelTwo.TabPanel(self), "页面二"),
                 (panelThree.TabPanel(self), "页面三")]

        img_id = 0
        for page,label in pages:
            self.AddPage(page, label, imageId=img_id)
            self.AddSubPage(page, "子页面", imageId=img_id)
            img_id += 1

        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged)
        self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging)

        # 解决在Mac上大小错误
        wx.CallLater(100, self.AdjustSize)
        
    def AdjustSize(self):
        self.GetTreeCtrl().InvalidateBestSize()
        self.SendSizeEvent()

    def OnPageChanged(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanged,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

    def OnPageChanging(self, e):
        old = e.GetOldSelection()
        new = e.GetSelection()
        sel = self.GetSelection()
        print("OnPageChanging,  old:%d, new:%d, sel:%d\n" % (old, new, sel))
        e.Skip()

class SampleTreebook(wx.Frame):

    def __init__(self, *args, **kw):
        super(SampleTreebook, self).__init__(*args, **kw)

        self.InitUi()

    def InitUi(self):
        self.SetTitle("实战wxPython: Treebook演示")
        self.SetSize(600, 400)

        panel = wx.Panel(self)

        notebook = MyTreebook(panel)
        sizer = wx.BoxSizer(wx.VERTICAL)
        sizer.Add(notebook, 1, wx.ALL|wx.EXPAND, 5)
        panel.SetSizer(sizer)
        self.Layout()

        self.Centre()

def main():
    app = wx.App()
    sample = SampleTreebook(None)
    sample.Show()
    app.MainLoop()

if __name__ == "__main__":
    main()

与wx.Toolbook一样,我们再次使用了前面演示中的一些代码来创建这个演示。除了wx.Treebook的专门事件外,还应该注意它有一个AddSubPage方法,该方法向树中添加一个子节点,该子节点又向笔记本中添加另一页。

 图7:wx.Treebook演示

十、本文知识点

  • 了解wx.lib.mixins.listctrl;
  • 了解gizmos.TreeListCtrl;
  • 了解和使用wx.Choicebook;
  • 了解和使用wx.Lisybool ;
  • 了解和使用wx.Toolbook;
  • 了解和使用wx.Treebook。

前一篇:实战wxPython:046 - AGW扩展包

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

实战wxPython:047 - Book控件(第一部分) 的相关文章

  • 使用 pygame 显示 unicode 符号

    我检查了其他答案 但不明白为什么我的代码错误地显示 This is what I currently see https i stack imgur com 8tNIK png 这是关于文本渲染的相关代码 font pygame font
  • opencv水印周围的轮廓

    我想在图像中的水印周围画一个框 我已经提取了水印并找到了轮廓 但是 不会在水印周围绘制轮廓 轮廓是在我的整个图像上绘制的 请帮我提供正确的代码 轮廓坐标的输出为 array 0 0 0 634 450 634 450 0 dtype int
  • 如果未引发异常,则通过 Python 单元测试

    在Python中unittest框架 是否有一种方法可以在未引发异常的情况下通过单元测试 否则会因 AssertRaise 而失败 如果我正确理解你的问题 你could做这样的事情 def test does not raise on va
  • 在没有模型的情况下将自定义页面添加到 django admin

    我正在尝试在没有模型关联的情况下向管理员添加自定义页面 这就是我迄今为止所取得的成就 class MyCustomAdmin AdminSite def get urls self from django conf urls import
  • 如何使用文本相似性删除 pandas 数据框中相似(不重复)的行?

    我有数千个数据 这些数据可能相似也可能不相似 使用 python 的默认函数 drop duplicates 并没有真正的帮助 因为它们只检测相似的数据 例如 如果我的数据包含类似以下内容怎么办 嗨 早上好 嗨 早上好 Python 不会将
  • Gspread如何复制sheet

    在 Stackoverflow 上进行谷歌搜索和搜索后 我想我找不到有关如何复制现有工作表 现有模板工作表 并将其保存到另一个工作表中的指南 根据文档 有重复表 https gspread readthedocs io en latest
  • Geodjango距离查询未检索到正确的结果

    我正在尝试根据地理位置的接近程度来检索一些帖子 正如您在代码中看到的 我正在使用 GeoDjango 并且代码在视图中执行 问题是距离过滤器似乎被完全忽略了 当我检查查询集上的距离时 我得到了预期距离 1m 和 18km 但 18km 的帖
  • Jython 和 SAX 解析器:允许的实体不超过 64000 个?

    我做了一个简单的测试xml saxJython 中的解析器在处理大型 XML 文件 800 MB 时遇到以下错误 Traceback most recent call last File src project xmltools py li
  • ANTLR 获取并拆分词法分析器内容

    首先 对我的英语感到抱歉 我还在学习 我为我的框架编写 Python 模块 用于解析 CSS 文件 我尝试了 regex ply python 词法分析器和解析器 但我发现自己在 ANTLR 中 第一次尝试 我需要解析 CSS 文件中的注释
  • 使用“默认”环境变量启动新的子进程

    我正在编写一个构建脚本来解析依赖的共享库 及其共享库等 这些共享库在正常情况下是不存在的PATH环境变量 为了使构建过程正常工作 让编译器找到这些库 PATH已更改为包含这些库的目录 构建过程是这样的 加载器脚本 更改 PATH gt 基于
  • 将seaborn.palplot轴添加到现有图形中以可视化不同调色板

    将seaborn人物添加到子图中是usually https seaborn pydata org examples cubehelix palette html创建图形时通过传递 ax 来完成 例如 sns kdeplot x y cma
  • Mac OSX 10.6 上的 Python mysqldb 不工作

    我正在使用 Python 2 7 并尝试让 Django 项目在 MySQL 后端运行 我已经下载了 mysqldb 并按照此处的指南进行操作 http cd34 com blog programming python mysql pyth
  • Anaconda 无法导入 ssl 但 Python 可以

    Anaconda 3 Jupyter笔记本无法导入ssl 但使用Atom终端导入ssl没有问题 我尝试在 Jupyter 笔记本中导入 ssl 但出现以下错误 C ProgramData Anaconda3 lib ssl py in
  • 从 NumPy 数组到 Mat 的 C++ 转换 (OpenCV)

    我正在围绕 ArUco 增强现实库 基于 OpenCV 编写一个薄包装器 我试图构建的界面非常简单 Python 将图像传递给 C 代码 C 代码检测标记并将其位置和其他信息作为字典元组返回给 Python 但是 我不知道如何在 Pytho
  • Elasticsearch 通过搜索返回拼音标记

    我用语音分析插件 https www elastic co guide en elasticsearch plugins current analysis phonetic html由于语音转换 从弹性搜索中进行一些字符串匹配 我的问题是
  • 如何与其他用户一起使用 pyenv?

    如何与其他用户一起使用 pyenv 例如 如果我在用户 test 的环境中安装了 pyenv 则当我以 test 身份登录时可以使用 pyenv 但是 当我以其他用户 例如 root 身份登录时如何使用 pyenv 即使你这么做了 我也会s
  • Django 与谷歌图表

    我试图让谷歌图表显示在我的页面上 但我不知道如何将值从 django 视图传递到 javascript 以便我可以绘制图表 姜戈代码 array Year Sales Expenses 2004 1000 400 2005 1170 460
  • 如何根据第一列创建新列,同时考虑Python Pandas中字母和列表的大小? [复制]

    这个问题在这里已经有答案了 我在 Python Pandas 中有 DataFrame 如下所示 col1 John Simon prd agc Ann White BeN and Ann bad list Ben Wayne 我需要这样做
  • TKinter 中的禁用/启用按钮

    我正在尝试制作一个像开关一样的按钮 所以如果我单击禁用按钮 它将禁用 按钮 有效 如果我再次按下它 它将再次启用它 我尝试了 if else 之类的东西 但没有成功 这是一个例子 from tkinter import fenster Tk
  • 将上下文管理器的动态可迭代链接到单个 with 语句

    我有一堆想要链接的上下文管理器 第一眼看上去 contextlib nested看起来是一个合适的解决方案 但是 此方法在文档中被标记为已弃用 该文档还指出最新的with声明直接允许这样做 自 2 7 版起已弃用 with 语句现在支持此

随机推荐

  • Github 本地合并 (merge) 他人提交的 pr

    Github 上有些项目可能作者长时间没有进行维护 会出现有些新的 pr 没有合并到主分支 master 上 这时如果想在本地应用这个新的 pr 呢 一般来说主要有以下几种方式 针对提交的pr 查看具体的改动文件和改动内容 然后在本地进行对
  • git log 后一直出现:(冒号)的原因以及处理方法

    博客主页 https blog csdn net mukes 欢迎点赞 收藏 留言 如有错误敬请指正 本文由 mukes 原创 首发于 csdn 问题重现 在 git bash 中输入 git log 时出现 冒号 如下图所示 问题描述 一
  • Android酷炫实用的开源框架(UI框架)

    Android酷炫实用的开源框架 UI框架 前言 忙碌的工作终于可以停息一段时间了 最近突然有一个想法 就是自己写一个app 所以找了一些合适开源控件 这样更加省时 再此分享给大家 希望能对大家有帮助 此博文介绍的都是UI上面的框架 接下来
  • web初始

    个人学习开始 写的不好 请大佬指教
  • 机器学习实战——Kmeans聚类算法

    机器学习实战 Kmeans聚类算法 1 聚类算法介绍 1 1 K 均值聚类 1 2 聚类效果的评价 2 sklearn中的实现 1 聚类算法介绍 在无监督学习中 训练样本的标记是未知的 目标是通过对无标记训练样本的学习来揭示数据的内在性质及
  • 纷玩岛演唱会下单代码

    继大麦M端之后 再发现一个演唱会平台 纷玩岛 此平台不像大麦 猫眼那么火爆 相对来说比较容易研究 通过抓包软件发现下单很简单 就一个JWT登录后的头部token而已 下载地址 https download csdn net download
  • 结构体对函数指针的高级封装应用

    分层设计考虑 作用 降低对底层应用程序的高耦合度 示例 include mac h typedef struct phy t char channel char snd fail count char name char open flag
  • 软件测试用例覆盖率怎么算,如何计算增量测试覆盖率

    为了保证代码质量 一般会要求提交的源码要有测试用例覆盖 并对测试覆盖率有一定的要求 在实践中不仅会考核存量代码覆盖率 总体覆盖率 还会考核增量代码的覆盖率 或者说增量覆盖率更有实际意义 测试用例要随源码一并提交 实时保证源码的质量 而不是代
  • 进程和线程的区别,以及应用场景

    什么是线程 Linux下线程用进程PCB模拟描述 也叫轻量级进程 线程是进程内部的一个执行流 也就是线程在进程的地址空间内运行 一个进程内的所有线程共享进程资源 线程是CPU调度的基本单位 CPU调度是按照PCB进行调度的 创建 销毁一个线
  • Mule入门——DB、Rest、Soap接口开发

    一 DB查询接口开发 这里我用的mysql数据库 首先我们先查询下我们的数据库这里有很多数据 然后我们用AnypointStudio进行我们的接口开发 首先我们先新建一个Mule工程 File gt New gt Mule project
  • 计算机网络---传输层

    两个端的会话层之间提供建立 维护和取消传输连接的功能 这一层 数据传送的协议单元成为报文 网络层只是根据网络地址将源节点发出的数据包送到目的终点 而传输层负责将数据可靠的传送到相应的端口 传输层负责将上层数据分段提供端到端 可靠不可靠的传输
  • vue3-admin-template页面

    vue3 admin template 本人学习视频网址为 视频地址 源码 github 网页采用技术框架 本管理模板采用vue3开发 使用vue router来作为路由跳转 将登录成功后产生的菜单 token放入到vuex中存储 通过ax
  • 一般Python开发面试中可能会问到的大部分问题

    python语法以及其他基础部分 可变与不可变类型 浅拷贝与深拷贝的实现方式 区别 deepcopy如果你来设计 如何实现 new 与 init 的区别 你知道几种设计模式 编码和解码你了解过么 列表推导list comprehension
  • Linux嵌入式学习——c语言选择结构设计

    Linux嵌入式学习 c语言选择结构设计 一 if语句 1 1if语句的一般格式 1 2if语句常用的3种形式 1 3if语句的嵌套 二 关系运算符和关系表达式 2 1关系运算符及其优先次序 2 2关系表达式 三 逻辑运算符和逻辑表达式 3
  • @ControllerAdvice注解使用及原理探究

    最近在新项目的开发过程中 遇到了个问题 需要将一些异常的业务流程返回给前端 需要提供给前端不同的响应码 前端再在次基础上做提示语言的国际化适配 这些异常流程涉及业务层和控制层的各个地方 如果每个地方都写一些重复代码显得很冗余 然后查询解决方
  • PowerBI入门学习笔记

    下载安装 Win10系统 在微软商店里直接下载PowerBI desktop 打开即可 界面如下 接下来导入后面要用到的数据 我目前用的都是Excel文件 获取数据 选中后选择要导入的若干个工作表 点击 加载数据 就进入到power que
  • vue+element实现双向描点 反向联动

    前端项目里经常会有锚点得操作 以及反向联动的效果 就是一个菜单 点击会定位到一个块上 滚动的当前块的时候 菜单会出现定位的效果 差不多就是这种动起来的效果 由于不太懂之前的逻辑 今天又从重新看了下 上代码 html 滚动的区域
  • 关于Python中pip install 各种包下载不下来的问题解决办法

    你们有可能报安装不成功或者下面这个问题 已经安装了但并非在你的Python安装路径下 C Users xxx gt pip install ddt Requirement already satisfied ddt in e anacond
  • redis 实现乐观锁

    redis是单线程程序但是支持多进程同时访问同一个redis服务 这个时候就需要锁机制来处理一些并发问题 redis提供了watch指令来实现乐观锁 watch和事务配合使用 往往写在multi之前 用来监视一个key 比如watch mo
  • 实战wxPython:047 - Book控件(第一部分)

    在wxPython中 book控件允许用户在各种面板之间切换 最常见的例子是带有选项卡界面的浏览器和系统选项对话框 本文将向您介绍这些控件的创建和基本配置 wxPython目前内置了多个这样的控件 除文章 wxPython 高级控件之选项卡