[译]wxPython布局管理简介

By | 2013/03/30

原文地址:http://zetcode.com/wxpython/layout/

PS:翻译水平有限,有能力的还是看原文吧。

一个典型的应用是有多个部件组成的。这些部件被放置在容器控件中,程序员必须管理这些部件的布局。在wxPython中有两种布局方式:

  • 绝对定位(absolute positioning)
  • 使用sizer布局

绝对定位(absolute positioning)

如果使用绝对定位(absolute positioning),你需要手动指定部件的位置和大小,并且你还需要了解一下注意点:

  • 当你改变窗口大小的时候,部件的大小和位置不会改变
  • 在不同的平台上看起来会不一样
  • 改变文字字体可能会影响整体布局
  • 当你想改变布局的时候,你必须完全重写布局,这既繁琐又费时

在一般应用程序中我们大部分会使用sizer进行布局,很少会使用绝对定位(absolute positioning),下面我先介绍一个使用绝对定位(absolute positioning)的例子:

在这个例子中,我写了一个简单的文本编辑器,当我们改变窗口大小的时候,wx.TextCtrl如我们所期望的那样并没有发生变化。

absolute1

Figure: before resizement

absolute2

Figure:after resizement

#!/usr/bin/python
# -*- coding: utf-8 -*-

# absolute.py
import wx
class Example(wx.Frame):
    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
        size=(260, 180))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        panel = wx.Panel(self, -1)
        menubar = wx.MenuBar()
        filem = wx.Menu()
        editm = wx.Menu()
        helpm = wx.Menu()

        menubar.Append(filem, '&File')
        menubar.Append(editm, '&Edit')
        menubar.Append(helpm, '&Help')
        self.SetMenuBar(menubar)

wx.TextCtrl(panel, pos=(3, 3), size=(250, 150))

if __name__ == '__main__':
    app = wx.App()
    Example(None, title='')
    app.MainLoop()

在上面的例子中,我把一个文本控件放在了一个绝对的坐标上

wx.TextCtrl(panel, pos=(3, 3), size=(250,150))

panel表示该部件的父部件,pos表示该部件的位置(x=3,y=3),size表示该部件的大小(width=250px, height=150px)

使用Sizer

Sizer用来解决绝对定位(absolute positioning)中遇到的问题。主要有下面几种Sizer:

  • wx.BoxSizer
  • wx.StaticBoxSizer
  • wx.GridSizer
  • wx.FlexGridSizer
  • wx.GridBoxSizer

absolute1

Figure: before resizement

sizer

Figure:after resizement

#!/usr/bin/python
# -*- coding: utf-8 -*-
# sizer.py
import wx

class Example(wx.Frame):
    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
        size=(260, 180))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):
        menubar = wx.MenuBar()
        filem = wx.Menu()
        editm = wx.Menu()
        helpm = wx.Menu()

        menubar.Append(filem, '&File')
        menubar.Append(editm, '&Edit')
        menubar.Append(helpm, '&Help')
        self.SetMenuBar(menubar)

        wx.TextCtrl(self)

if __name__ == '__main__':
    app = wx.App()
    Example(None, title='')
    app.MainLoop()

上面的例子中,我并没有使用sizer,但是wx.Frame有一个内置的sizer(built-in-sizer)。我在wx.Frame中只放置了一个wx.TextCtrl部件,这个子部件会占据父部件的全部空间(除了边框(borders)、菜单(menu)、工具栏(toolbar)、状态栏(statusbar)之外的空间)。

wx.BoxSizer

这个sizer使我们可以将许多部件放在一行或一列,当然我们也可以使用嵌套来实现一些复杂的布局。

box=wx.BoxSizer(integer orient)
box.Add(wx.Window window, integer proportion=0, integer flag=0, integer border=0)

orientation可以是wx.VERTICAL(垂直方向) 或者wx.HORIZONTAL(水平方向)。我们可以通过Add()方法将部件加入到Sizer中
proportion参数表示部件在orientation方向上比例的变化。假设我们有三个按钮,使用HORIZONTAL布局,proportion值分别是0、1、2,当改变窗口大小的时候,proportion=0的按钮大小不会改变;proportion=2的按钮在水平方向大小会变为proportion=1的按钮的两倍。
flag参数表示部件在Sizer布局中的行为,例如wx.LEFT、wx.BOTTOM等,也可以用|来分割多个行为

  • wx.LEFT
  • wx.RIGHT
  • wx.BOTTOM
  • wx.TOP
  • wx.ALL

border参数表示该部件边框的大小(与相邻部件或父部件之间的空间,以像素为单位)

border

Figure: border around a panel

vbox.Add(midPan, 1, wx.EXPAND | wx.ALL, 20)

上面的例子中,我在panel周围设置了一些空间

vbox.Add(midPan, 1, wx.EXPAND|wx.ALL, 20)

在border.py中,我为midPan设置了20px的边框。wx.ALL表示四个方向上的边框都是20px
如果使用wx.EXPAND,部件会使用我们分配的所有空间。最后,我们还可以为部件定义对齐方式:

  • wx.ALIGN_LEFT
  • wx.ALIGN_RIGHT
  • wx.ALIGN_TOP
  • wx.ALIGN_BOTTOM
  • wx.ALIGN_CENTER
  • wx.ALIGN_CENTER_VERTICAL
  • wx.ALIGN_CENTER_HORIZONTAL

实例

在下面这个例子中,我会介绍一些重要的思想。

#!/usr/bin/python
# -*- coding: utf-8 -*-

# gotoclass.py

import wx

class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(390, 350))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):

        panel = wx.Panel(self)

        font = wx.SystemSettings_GetFont(wx.SYS_SYSTEM_FONT)
        font.SetPointSize(9)

        vbox = wx.BoxSizer(wx.VERTICAL)

        hbox1 = wx.BoxSizer(wx.HORIZONTAL)
        st1 = wx.StaticText(panel, label='Class Name')
        st1.SetFont(font)
        hbox1.Add(st1, flag=wx.RIGHT, border=8)
        tc = wx.TextCtrl(panel)
        hbox1.Add(tc, proportion=1)
        vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)

        vbox.Add((-1, 10))

        hbox2 = wx.BoxSizer(wx.HORIZONTAL)
        st2 = wx.StaticText(panel, label='Matching Classes')
        st2.SetFont(font)
        hbox2.Add(st2)
        vbox.Add(hbox2, flag=wx.LEFT | wx.TOP, border=10)

        vbox.Add((-1, 10))

        hbox3 = wx.BoxSizer(wx.HORIZONTAL)
        tc2 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)
        hbox3.Add(tc2, proportion=1, flag=wx.EXPAND)
        vbox.Add(hbox3, proportion=1, flag=wx.LEFT|wx.RIGHT|wx.EXPAND,
            border=10)

        vbox.Add((-1, 25))

        hbox4 = wx.BoxSizer(wx.HORIZONTAL)
        cb1 = wx.CheckBox(panel, label='Case Sensitive')
        cb1.SetFont(font)
        hbox4.Add(cb1)
        cb2 = wx.CheckBox(panel, label='Nested Classes')
        cb2.SetFont(font)
        hbox4.Add(cb2, flag=wx.LEFT, border=10)
        cb3 = wx.CheckBox(panel, label='Non-Project classes')
        cb3.SetFont(font)
        hbox4.Add(cb3, flag=wx.LEFT, border=10)
        vbox.Add(hbox4, flag=wx.LEFT, border=10)

        vbox.Add((-1, 25))

        hbox5 = wx.BoxSizer(wx.HORIZONTAL)
        btn1 = wx.Button(panel, label='Ok', size=(70, 30))
        hbox5.Add(btn1)
        btn2 = wx.Button(panel, label='Close', size=(70, 30))
        hbox5.Add(btn2, flag=wx.LEFT|wx.BOTTOM, border=5)
        vbox.Add(hbox5, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=10)

        panel.SetSizer(vbox)

if __name__ == '__main__':

    app = wx.App()
    Example(None, title='Go To Class')
    app.MainLoop()

上面我介绍了一个简单的例子,我创建了一个垂直sizer,然后在这个sizer中我放置了5个水平sizer

font = wx.SystemSettings_GetFount(wx.SYS_SYSTEM_FONT)
font.SetPointSize(9)

系统默认的文字大小是10px,在我的电脑上显得比较大,所以我改成了9px

vbox.Add(hbox3, proportion=1, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=10)
vbox.Add((-1,25))

我们可以通过panel参数来控制各部件之间的间距,像上面的例子,我可以为为hbox设置左右边框为10px,但是我不能同时将底部的边框设置为25px,我们只能将底部边框设置为10px或者0px。为了实现这样的效果,我们可以使用Add()方法在两个部件之间添加一些额外的空间。

vbox.Add(hbox5, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=10)

我想在窗体底部靠右侧的位置放置两个按钮,怎样才能实现这个效果呢?要实现这个效果,主要有下面三个方面:proportion、align、wx.EXPAND标签。proportion必须为0, 因为当窗口改变是按钮不能更改它的大小。我们不可以指定wx.EXPAND标签,按钮只能在我们指定的位置。我们必须指定wx.ALIGN_RIGHT标签,因为部件是从左到右排列的,所以指定了wx.ALIGN_RIGHT,按钮就会像我们想的那样居右显示。

gotoclass

Figure: A Go To Class Window

wx.GridSizer

wx.GridSizer就像一个二位表,每个单元格都有相同的大小。

wx.GridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)

在创建的时候,我们需要指定表的行和列,并且也要指定各个单元格之间的垂直和水平的间距。

在下面的例子中,我实现了一个计算器的骨架。这是wx.GridSizer的一个典型例子。

#!/usr/bin/python
# -*- coding: utf-8 -*-

# calculator.py

import wx

class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(300, 250))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):

        menubar = wx.MenuBar()
        fileMenu = wx.Menu()
        menubar.Append(fileMenu, '&File')
        self.SetMenuBar(menubar)

        vbox = wx.BoxSizer(wx.VERTICAL)
        self.display = wx.TextCtrl(self, style=wx.TE_RIGHT)
        vbox.Add(self.display, flag=wx.EXPAND|wx.TOP|wx.BOTTOM, border=4)
        gs = wx.GridSizer(4, 4, 5, 5)

        gs.AddMany( [(wx.Button(self, label='Cls'), 0, wx.EXPAND),
            (wx.Button(self, label='Bck'), 0, wx.EXPAND),
            (wx.StaticText(self), wx.EXPAND),
            (wx.Button(self, label='Close'), 0, wx.EXPAND),
            (wx.Button(self, label='7'), 0, wx.EXPAND),
            (wx.Button(self, label='8'), 0, wx.EXPAND),
            (wx.Button(self, label='9'), 0, wx.EXPAND),
            (wx.Button(self, label='/'), 0, wx.EXPAND),
            (wx.Button(self, label='4'), 0, wx.EXPAND),
            (wx.Button(self, label='5'), 0, wx.EXPAND),
            (wx.Button(self, label='6'), 0, wx.EXPAND),
            (wx.Button(self, label='*'), 0, wx.EXPAND),
            (wx.Button(self, label='1'), 0, wx.EXPAND),
            (wx.Button(self, label='2'), 0, wx.EXPAND),
            (wx.Button(self, label='3'), 0, wx.EXPAND),
            (wx.Button(self, label='-'), 0, wx.EXPAND),
            (wx.Button(self, label='0'), 0, wx.EXPAND),
            (wx.Button(self, label='.'), 0, wx.EXPAND),
            (wx.Button(self, label='='), 0, wx.EXPAND),
            (wx.Button(self, label='+'), 0, wx.EXPAND) ])

        vbox.Add(gs, proportion=1, flag=wx.EXPAND)
        self.SetSizer(vbox)

if __name__ == '__main__':

    app = wx.App()
    Example(None, title='Calculator')
    app.MainLoop()

注意我在Bck按钮和Close按钮之间放了一个空的wx.StaticText,这样让人感觉好像是有了一个空的单元格。
在我的例子中,我使用了AddMany()方法,这个方法可以让我们一次添加多个部件。
[/python]
gs.AddMany([wx.Button(self, label=”Cls”,0,wx.EXPAND),])
[/python]

部件在表里是顺序排列的,先填充第一行,第一行填满后会自动转到第二行进行填充。(注:所以在创建GridSizer的时候,第一个参数rows可以指定为小于实际需要的值)

calculator

Figure: Calculator

wx.FlexGridSizer

这个Sizer和wx.GridSizer是类似的,它也是一个二维的表。不同的是wx.GridSizer的单元格的大小都是相同的,而wx.FlexGridSizer的单元格在一行内有相同的高,在一列内有相同的宽,但是单元格的大小不一定相同。

wx.FlexGridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)

很多情况下,开发者需要一个对话框来让用户输入数据,而wx.FlexGridSizer刚好适合这项工作。虽然wx.GridSizer也可以实现这个功能,但是wx.GridSizer单元格的大小是相同的,创建出来的对话框可能看起来不美观。

#!/usr/bin/python
# -*- coding: utf-8 -*-

# review.py

import wx

class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(300, 250))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):

        panel = wx.Panel(self)

        hbox = wx.BoxSizer(wx.HORIZONTAL)

        fgs = wx.FlexGridSizer(3, 2, 9, 25)

        title = wx.StaticText(panel, label="Title")
        author = wx.StaticText(panel, label="Author")
        review = wx.StaticText(panel, label="Review")

        tc1 = wx.TextCtrl(panel)
        tc2 = wx.TextCtrl(panel)
        tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)

        fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author),
            (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])

        fgs.AddGrowableRow(2, 1)
        fgs.AddGrowableCol(1, 1)

        hbox.Add(fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)
        panel.SetSizer(hbox)

if __name__ == '__main__':

    app = wx.App()
    Example(None, title='Review')
    app.MainLoop()

在上面的例子中,我用wx.FlexGridSizer创建了一个Review窗口

hbox = wx.BoxSizer(wx.HORIZONTAL)
...
hbox.Add(fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)

我创建了一个水平的布局,并设置了部件的边框为15px

fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author),
    (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])

如wx.GridSizer一样,这里我也使用了AddMany()方法

fgs.AddGrowableRow(2, 1)
fgs.AddGrowableCol(1, 1)

我让第(2,1)的单元格在垂直方向上自增长,第(1,1)的单元格在水平方向上自增长。这样当窗口变化时,文本框会随着也变化(第1、2行的文本框会在水平方向上自增长,第3行的会在水平和垂直方向上都自增长)。当然我们也不能忘记wx.EXPAND参数,只有加上这个参数才会有效果。
注:因为要让多行的文本框自增长,所以第(2,1)的单元格必须在垂直方向上自增长,而水平方向上则可以任意选择与之在一列的单元格即可。例如(0,1)、(1,1)、(2,1)都可以。

review

Figure: Review example

wx.GridBagSizer

这是wxPython中最复杂的一种布局。很多程序员发现它很难使用,但是这也不是wxPython特有的,我们在其他的工具包中也可以找到。尽管它很复杂,但它也赶不上火箭复杂。
这种布局能够很清晰的知道部件的位置,一个部件可以跨多行或多列,wx.GridBagSizer有一个很简单的构造器

wx.GridBagSizer(integer vgap, integer hgap)

vgap和hgap定义的是各个子部件之间的间距。我们可以通过Add()方法来添加子部件

Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0, integer border=0, userData=None)

pos代表部件做在的单元格,从0开始,(0,0)表示最左上的单元格。span表示该部件所跨的单元格数目,span=(3,2)表示垂直方向跨三个单元格,水平方向跨两个单元格(也可理解成单元格合并)。flag和上文在wx.BoxSizer中表示的是一个意思,也表示样式。
当窗口改变的时候,表格中的部件可以随之改变也可以保存原样,如果想改变部件的大小可以使用下面两个方法:

AddGrowableRow(integer row)
AddGrowableCol(integer col)

实例

在第一个例子中,我创建了一个Rename窗口,它包含一个静态文本(wx.StaticText)、一个文本框(wx.TextCtrl)和两个按钮(wx.Button)

#!/usr/bin/python
# -*- coding: utf-8 -*-

# rename.py

import wx

class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(320, 130))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):

        panel = wx.Panel(self)
        sizer = wx.GridBagSizer(4, 4)

        text = wx.StaticText(panel, label="Rename To")
        sizer.Add(text, pos=(0, 0), flag=wx.TOP|wx.LEFT|wx.BOTTOM, border=5)

        tc = wx.TextCtrl(panel)
        sizer.Add(tc, pos=(1, 0), span=(1, 5),
            flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=5)

        buttonOk = wx.Button(panel, label="Ok", size=(90, 28))
        buttonClose = wx.Button(panel, label="Close", size=(90, 28))
        sizer.Add(buttonOk, pos=(3, 3))
        sizer.Add(buttonClose, pos=(3, 4), flag=wx.RIGHT|wx.BOTTOM, border=5)

        sizer.AddGrowableCol(1)
        sizer.AddGrowableRow(2)
        panel.SetSizerAndFit(sizer)

if __name__ == '__main__':
    app = wx.App()
    Example(None, title='Rename')
    app.MainLoop()

我们必须把整个窗口看作是一个表格

text = wx.StaticText(panel, label="Rename To")
sizer.Add(text, pos=(0, 0), flag=wx.TOP|wx.LEFT|wx.BOTTOM, border=5)

静态文本“Rename To” 放在左上角,所以我将它放在(0,0)这个单元格中,并且我为它设置了5px的边框。

tc = wx.TextCtrl(panel)
sizer.Add(tc, pos=(1, 0), span=(1, 5),
    flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=5)

文本框(wx.TextCtrl)在第二行,所以我将它放在了(1,0)这个单元格,并且它需要横跨5个单元格,所以将它的span设为(1,5),最后给它加上5px的边框。

sizer.Add(buttonOk, pos=(3, 3))
sizer.Add(buttonClose, pos=(3, 4), flag=wx.RIGHT|wx.BOTTOM, border=5)

我在第四行放置了两个按钮,因为第三行没有放置部件,所以文本框和按钮之间看起来会有一些空间。我把OK按钮放在地四列,Close按钮放在第五列。
从上面的例子中可以看出,如果一个部件空间(border)增加的话,所有行都会受之影响。细心的读者可能会发现,我并没有在两个之间设置空间(border),但是它们之间已经有了空间了。

sizer.AddGrowableCol(1)
sizer.AddGrowableRow(2)

最后我们需要让部件可以自适应窗口的改变。我将第二列和第三行设为自增长,现在我们可以调整窗口的大小来看看会发生什么。
rename

Figure: Rename window

实例

#!/usr/bin/python
# -*- coding: utf-8 -*-

# newclass.py

import wx

class Example(wx.Frame):

    def __init__(self, parent, title):
        super(Example, self).__init__(parent, title=title,
            size=(450, 350))

        self.InitUI()
        self.Centre()
        self.Show()

    def InitUI(self):

        panel = wx.Panel(self)

        sizer = wx.GridBagSizer(5, 5)

        text1 = wx.StaticText(panel, label="Java Class")
        sizer.Add(text1, pos=(0, 0), flag=wx.TOP|wx.LEFT|wx.BOTTOM,
            border=15)

        icon = wx.StaticBitmap(panel, bitmap=wx.Bitmap('exec.png'))
        sizer.Add(icon, pos=(0, 4), flag=wx.TOP|wx.RIGHT|wx.ALIGN_RIGHT,
            border=5)

        line = wx.StaticLine(panel)
        sizer.Add(line, pos=(1, 0), span=(1, 5),
            flag=wx.EXPAND|wx.BOTTOM, border=10)

        text2 = wx.StaticText(panel, label="Name")
        sizer.Add(text2, pos=(2, 0), flag=wx.LEFT, border=10)

        tc1 = wx.TextCtrl(panel)
        sizer.Add(tc1, pos=(2, 1), span=(1, 3), flag=wx.TOP|wx.EXPAND)

        text3 = wx.StaticText(panel, label="Package")
        sizer.Add(text3, pos=(3, 0), flag=wx.LEFT|wx.TOP, border=10)

        tc2 = wx.TextCtrl(panel)
        sizer.Add(tc2, pos=(3, 1), span=(1, 3), flag=wx.TOP|wx.EXPAND,
            border=5)

        button1 = wx.Button(panel, label="Browse...")
        sizer.Add(button1, pos=(3, 4), flag=wx.TOP|wx.RIGHT, border=5)

        text4 = wx.StaticText(panel, label="Extends")
        sizer.Add(text4, pos=(4, 0), flag=wx.TOP|wx.LEFT, border=10)

        combo = wx.ComboBox(panel)
        sizer.Add(combo, pos=(4, 1), span=(1, 3),
            flag=wx.TOP|wx.EXPAND, border=5)

        button2 = wx.Button(panel, label="Browse...")
        sizer.Add(button2, pos=(4, 4), flag=wx.TOP|wx.RIGHT, border=5)

        sb = wx.StaticBox(panel, label="Optional Attributes")

        boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)
        boxsizer.Add(wx.CheckBox(panel, label="Public"),
            flag=wx.LEFT|wx.TOP, border=5)
        boxsizer.Add(wx.CheckBox(panel, label="Generate Default Constructor"),
            flag=wx.LEFT, border=5)
        boxsizer.Add(wx.CheckBox(panel, label="Generate Main Method"),
            flag=wx.LEFT|wx.BOTTOM, border=5)
        sizer.Add(boxsizer, pos=(5, 0), span=(1, 5),
            flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT , border=10)

        button3 = wx.Button(panel, label='Help')
        sizer.Add(button3, pos=(7, 0), flag=wx.LEFT, border=10)

        button4 = wx.Button(panel, label="Ok")
        sizer.Add(button4, pos=(7, 3))

        button5 = wx.Button(panel, label="Cancel")
        sizer.Add(button5, pos=(7, 4), span=(1, 1),
            flag=wx.BOTTOM|wx.RIGHT, border=5)

        sizer.AddGrowableCol(2)

        panel.SetSizer(sizer)

if __name__ == '__main__':

    app = wx.App()
    Example(None, title="Create Java Class")
    app.MainLoop()

这是一个比较复杂的例子,我同时使用了wx.GridBagSizer和wx.StaticBoxSizer

line = wx.StaticLine(panel)
sizer.Add(line, pos=(1, 0), span=(1, 5),
    flag=wx.EXPAND|wx.BOTTOM, border=10)

我创建了一个横线来分割部件

icon = wx.StaticBitmap(panel, bitmap=wx.Bitmap('exec.png'))
sizer.Add(icon, pos=(0, 4), flag=wx.TOP|wx.RIGHT|wx.ALIGN_RIGHT,
    border=5)

在第一行右侧我放置了一个静态图标

sb = wx.StaticBox(panel, label="Optional Attributes")
boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)

wx.StaticBoxSizer就像一个普通的wx.BoxSizer,不同的是它添加了一个static box,我在staticboxsizer中加了几个复选框
newclass

Figure: New Class window

Leave a Reply

Your email address will not be published. Required fields are marked *