wxpython制作表格界面_wxpython入门第二步(布局)

一个典型的应用程序由各种小组件组成。这些组件被放置在容器里面。程序员必须管理应用程序的布局。在 wxPython 中,可以使用绝对定位或使用 sizer 来布局小组件。

绝对定位

程序员以像素为单位指定每个小组件的位置和大小。绝对定位有几个缺点。如果我们调整窗口的大小,小组件的大小和位置不会改变。

应用程序在不同平台上的外观不同。

改变应用程序中的字体可能会破坏布局。

如果要改变布局,则必须完全重做布局,这是繁琐和耗时的

在有些情况下,我们可能会使用绝对定位。例如,小的测试例子。但大多数情况下,程序员都会使用sizer。

在我们的例子中,我们有一个简单的文本编辑器的骨架。如果我们调整窗口的大小,out wx.TextCtrl的大小并没有像我们期望的那样改变。# absolute.py

#absolute.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title,

size=(350, 300))

self.InitUI()

self.Centre()

def InitUI(self):

self.panel = wx.Panel(self)

self.panel.SetBackgroundColour("white")

self.LoadImages()

self.mincol.SetPosition((20, 20))

self.bardejov.SetPosition((40, 160))

self.rotunda.SetPosition((170, 50))

def LoadImages(self):

self.mincol = wx.StaticBitmap(self.panel, wx.ID_ANY,

wx.Bitmap("icon_1.png", wx.BITMAP_TYPE_ANY))

self.bardejov = wx.StaticBitmap(self.panel, wx.ID_ANY,

wx.Bitmap("icon_2.png", wx.BITMAP_TYPE_ANY))

self.rotunda = wx.StaticBitmap(self.panel, wx.ID_ANY,

wx.Bitmap("icon_3.png", wx.BITMAP_TYPE_ANY))

def main():

app = wx.App()

ex = Example(None, title='Absolute positioning')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025210905141

在上面的例子中,我们使用绝对坐标定位三个图像。self.mincol.SetPosition((20, 20))

通过SetPosition()方法,我们将图像放置在x=20,y=20坐标处。

使用sizer

Sizer确实解决了我们提到的所有绝对定位的问题,wxPython有以下sizer。wx.BoxSizer

wx.StaticBoxSizer

wx.GridSizer

wx.FlexGridSizer

wx.GridBagSizer

wx.BoxSizer

wx.BoxSizer 使我们能够将多个小组件放入一行或一列中。我们可以将另一个sizer放入一个现有的sizer中。这样我们就可以创建非常复杂的布局。box = wx.BoxSizer(integer orient)

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

方向可以是wx.VERTICAL或wx.HORIZONTAL。在wx.BoxSizer中添加widget是通过Add()方法完成的。为了理解它,我们需要看看它的参数。

proportion参数定义了widgets在定义的方向上的变化比例。假设我们有三个比例为0、1和2的按钮。它们被添加到一个水平的wx.BoxSizer.Button中。比例为0的按钮完全不会改变。比例2的按钮在水平维度上会比比例1的按钮多变化一倍。

通过flag参数,可以进一步配置wx.BoxSizer中组件的行为。我们可以控制组件之间的边界。我们在组件之间添加一些空间,单位是像素。为了应用border,我们需要定义border。我们可以用 | 操作符来组合它们,例如 wx.LEFT | wx.BOTTOM。我们可以在这些标志中进行选择。wx.LEFT

wx.RIGHT

wx.BOTTOM

wx.TOP

wx.ALL

通过setSizer()方法对面板组件设置sizer。#border.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title)

self.InitUI()

self.Centre()

def InitUI(self):

panel = wx.Panel(self)

panel.SetBackgroundColour('#4f5049')

vbox = wx.BoxSizer(wx.VERTICAL)

midPan = wx.Panel(panel)

midPan.SetBackgroundColour('#ededed')

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

panel.SetSizer(vbox)

def main():

app = wx.App()

ex = Example(None, title='Border')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025211837735

在上面的例子中,我们在一个panel周围放置了边框。vbox.Add(midPan, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)

在border.py中,我们已经在midPan面板周围放置了一个20 px的边框,wx.ALL将边框大小应用于所有四边。

如果我们使用wx.EXPAND标志,我们的组件将使用所有分配给它的空间。最后,我们还可以定义组件的对齐方式。通过以下标志来实现。wx.ALIGN_LEFT

wx.ALIGN_RIGHT

wx.ALIGN_TOP

wx.ALIGN_BOTTOM

wx.ALIGN_CENTER_VERTICAL

wx.ALIGN_CENTER_HORIZONTAL。

wx.ALIGN_CENTER

类的例子

介绍一些重要的思想#go_to_class.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title)

self.InitUI()

self.Centre()

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)

def main():

app = wx.App()

ex = Example(None, title='Go To Class')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025212651055

布局很简单。我们创建一个垂直的定标器。然后在其中放入五个水平缩放器。font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)

font.SetPointSize(9)

我们将字体大小改为9 px。vbox.Add(hbox3, proportion=1, flag=wx.LEFT|wx.RIGHT|wx.EXPAND, border=10)

vbox.Add((-1, 25))

我们已经知道,我们可以通过结合flag参数和border参数来控制部件之间的距离。但是有一个真正的限制。在Add()方法中,我们只能为所有给定的边指定一个边框。在我们的例子中,我们给右边和左边各10 px。但是我们不能给底部增加25 px的边框,我们可以做的是给右边和左边增加10 px的边框。我们可以做的是给底部10 px,如果省略wx.BOTTOM,则给底部0 px。所以如果我们需要不同的值,我们可以增加一些额外的空间。通过Add()方法,我们也可以插入组件和空间。vbox.Add(hbox5, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=10)

我们将两个按钮放在窗口的右侧。要做到这一点,有三件事情很重要:porportion,align和 wx.EXPAND 标志。porportion必须为零。当我们调整窗口大小时,按钮的大小不应改变。我们不能指定wx.EXPAND标志。按钮只复制分配给它们的区域。最后,我们必须指定wx.ALIGN_RIGHT标志。水平缩放器从窗口的左边扩展到右边。所以如果我们指定wx.ALIGN_RIGHT标志,按钮就会被放置在右边。

wx.GridSizer

wx.GridSizer在二维表格中布置组件。表格中的每个单元格都有相同的大小。wx.GridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)

在构造函数中,我们指定表格中的行数和列数,以及单元格之间的垂直和水平空间。

在我们的例子中,我们创建了一个计算器的骨架。#calculator.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title)

self.InitUI()

self.Centre()

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(5, 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)

def main():

app = wx.App()

ex = Example(None, title='Calculator')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025213442744

请注意,我们是如何在Bck和Close按钮之间放置一个空格的。我们只是在那里放了一个空的wx.StaticText。

在我们的例子中,我们使用了AddMany()方法。它是一个方便的方法,用于一次添加多个组件。gs.AddMany( [(wx.Button(self, label='Cls'), 0, wx.EXPAND),

...

组件按照添加顺序放置在表格内。第一行先填,然后第二行...。

wx.FlexGridSizer

这个缩放器类似于wx.GridSizer。它也是在一个二维的表格中布置它的部件,它增加了一些灵活性。wx.GridSizer的单元格大小相同。wx.FlexGridSizer中的所有单元格在一行中具有相同的高度。在一列中,所有的单元格都有相同的宽度。但所有的行和列不一定是相同的高度或宽度。wx.FlexGridSizer(int rows=1, int cols=0, int vgap=0, int hgap=0)

vgap和hgap在两个方向上增加了一些部件之间的空间。

很多时候,开发人员必须开发对话框来输入和修改数据。我发现wx.FlexGridSizer适合这样的任务。开发者可以很容易地用这个sizer设置一个对话框窗口。也可以用wx.GridSizer来完成这个任务,但它看起来并不好看,因为每个单元格必须有相同的大小。#review.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title)

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)

def main():

app = wx.App()

ex = Example(None, title='Review')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025221053840

在上面的代码示例中,我们用FlexGridSizer创建一个Review窗口。hbox = wx.BoxSizer(wx.HORIZONTAL)

...

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

我们创建了一个水平框的大小,以便在组件表格周围放置一些空间(15 px)。fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author),

(tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])

我们使用AddMany()方法为sizer添加widget。wx.FlexGridSizer和wx.GridSizer都共享这个方法。fgs.AddGrowableRow(2, 1)

fgs.AddGrowableCol(1, 1)

我们让第三行和第二列可以增长。这样我们就可以让文本控件在窗口调整大小时增长。前两个文本控件将在水平方向上增长,第三个控件将在两个方向上增长。我们不要忘记用wx.EXPAND使组件可扩展,这样才能使它工作。

wx.GridBagSizer

wx.GridBagSizer是wxPython中最灵活的sizer。这种sizer并不只是在wxPython中才有,我们在其他工具包中也能找到它。

这种sizer可以实现项目的显式定位。项目也可以选择跨越多行或多列。wx.GridBagSizer有一个简单的构造函数。wx.GridBagSizer(integer vgap, integer hgap)

垂直和水平的间隙定义了所有子项目之间的像素空间。我们使用Add()方法向网格中添加项目。Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0,

integer border=0, userData=None)

Item是一个插入到网格中的组件。pos指定了在虚拟网格中的位置,左上角单元格的pos为(0, 0)。span是一个可选的跨度,例如(3, 2)跨度是指跨度为3行2列的部件。flag和border在前面由wx.BoxSizer讨论过。当窗口被调整大小时,网格中的项目可以改变它们的大小或保持默认大小。如果我们想让你的项目增长和缩小,我们可以使用下面两个方法。AddGrowableRow(integer row)

AddGrowableCol(integer col)

重命名窗口示例

在第一个例子中,我们创建一个Rename窗口。它将有一个wx.StaticText、一个wx.TextCtrl和两个wx.Button 组件。#rename.py

import wx

class Example(wx.Frame):

def __init__(self, parent, title):

super(Example, self).__init__(parent, title=title)

self.InitUI()

self.Centre()

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=10)

sizer.AddGrowableCol(1)

sizer.AddGrowableRow(2)

panel.SetSizer(sizer)

def main():

app = wx.App()

ex = Example(None, title='Rename')

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025214859779

我们把窗口看成一个大的网格表。text = wx.StaticText(panel, label="Rename To")

sizer.Add(text, pos=(0, 0), flag=wx.TOP|wx.LEFT|wx.BOTTOM, border=10)

"Rename To "的文字走到左上角。所以我们指定(0,0)的位置。而且我们在底部、左侧、底部都加了一些空格。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)。记住,我们从零开始计算。它展开了1行5列(1, 5)。而且我们在小组件的左边和右边放了5个像素的空间。sizer.Add(buttonOk, pos=(3, 3))

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

我们在第四行中放入两个按钮,第三行留空,以便在wx.TextCtrl和按钮之间留出一些空间。第三行留空,这样我们在wx.TextCtrl和按钮之间就有了一些空间。我们将 "Ok "按钮放入第四行,将 "Close "按钮放入第五行。请注意,一旦我们在一个部件上应用了一些space,它就会应用到整行。sizer.AddGrowableCol(1)

sizer.AddGrowableRow(2)

最后,我们必须做的是使我们的对话框可以调整大小。我们使第二列和第三行可以增长。现在我们可以扩大或缩小我们的窗口。试着注释这两行,看看会发生什么。

增加类的例子

在接下来的例子中,我们创建一个窗口,它可以在JDeveloper中找到。它是一个在Java中创建新类的窗口。#new_class.py

import wx

class Example(wx.Frame):

def __init__(self,parent,title):

super(Example,self).__init__(parent,title=title)

self.InitUI()

self.Centre()

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('icon_1.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=10)

sizer.AddGrowableCol(2)

panel.SetSizer(sizer)

sizer.Fit(self)

def main():

app=wx.App()

ex=Example(None,title="Create Java Class")

ex.Show()

app.MainLoop()

if __name__ == '__main__':

main()

image-20201025221223603

这是一个比较复杂的布局。我们同时使用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)

我们将一个wx.StaticBitmap放入网格的第一行。我们将其放置在该行的右侧。sb = wx.StaticBox(panel, label="Optional Attributes")

boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)

wxStaticBoxSizer和普通的wx.BoxSizer一样,但它在sizer周围添加了一个静态框。我们将复选框放入静态框中。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值