wxpython入门(七)sizer布局和图像处理
参考书籍
http://wiki.woodpecker.org.cn/moin/WxPythonInAction
第十一章 使用sizer放置窗口部件
sizer是一个对象,它唯一的目的就是管理容器中的窗口部件的布局。sizer本身不是一个容器或一个窗口部件。它只是一个屏幕布局的算法。所有的sizer都是抽象类wx.Sizer的一个子类的实例。
wxPython中预定义的sizer:
Grid:一个十分基础的网格布局。当你要放置的窗口部件都是同样的尺寸且整齐地放入一个规则的网格中是使用它。
Flex grid:对grid sizer稍微做了些改变,当窗口部件有不同的尺寸时,可以有更好的结果。
Grid bag:grid sizer系列中最灵活的成员。使得网格中的窗口部件可以更随意的放置。
Box:在一条水平或垂直线上的窗口部件的布局。当尺寸改变时,在控制窗口部件的的行为上很灵活。通常用于嵌套的样式。可用于几乎任何类型的布局。
Static box:一个标准的box sizer。带有标题和环线。
基本的sizer:grid
块状窗口,examples:
import wx
class BlockWindow(wx.Panel):
def __init__(self,parent,ID=-1,label="",pos=wx.DefaultPosition, size=(100, 25)):
wx.Panel.__init__(self,parent,ID,pos,size,wx.RAISED_BORDER, label)
self.label = label
self.SetBackgroundColour("white")
self.SetMinSize(size)
self.Bind(wx.EVT_PAINT, self.OnPaint)
def OnPaint(self, evt):
sz = self.GetClientSize()
dc = wx.PaintDC(self)
w,h = dc.GetTextExtent(self.label)
dc.SetFont(self.GetFont())
dc.DrawText(self.label, (sz.width-w)/2, (sz.height-h)/2)
最简单的grid sizer,examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
class GridSizerFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Basic Grid Sizer")
sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5)#创建grid sizer
for label in labels:
bw = BlockWindow(self, label=label)
sizer.Add(bw, 0, 0)#添加窗口部件到sizer
self.SetSizer(sizer)#把sizer与框架关联起来
self.Fit()
app = wx.PySimpleApp()
GridSizerFrame().Show()
app.MainLoop()
设置grid的sizer,examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "GridSizer Test")
sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5)
for label in labels:
bw = BlockWindow(self, label=label)
sizer.Add(bw, 0, 0)
center = self.FindWindowByName("five")
center.SetMinSize((150,50))
self.SetSizer(sizer)
self.Fit()
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
添加边框设置,examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
#边框标记
flags = {"one": wx.BOTTOM, "two": wx.ALL, "three": wx.TOP,
"four": wx.LEFT, "five": wx.ALL, "six": wx.RIGHT,
"seven": wx.BOTTOM | wx.TOP, "eight": wx.ALL,
"nine": wx.LEFT | wx.RIGHT}
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "GridSizer Borders")
sizer = wx.GridSizer(rows=3, cols=3, hgap=5, vgap=5)
for label in labels:
bw = BlockWindow(self, label=label)
flag = flags.get(label, 0)
sizer.Add(bw, 0, flag, 10)#添加指定边框的窗口部件
self.SetSizer(sizer)
self.Fit()
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
flex grid sizer
基本上和grid相同,flex grid sizer是grid sizer的一个更灵活的版本,增强功能如下:
1、每行和每列可以有各自的尺寸。
2、默认情况下,当尺寸调整时,它不改变它的单元格的尺寸。如果需要的话,你可以指定哪行或哪列应该增长。
3、它可以在两个方向之一灵活地增长,意思是你可以为个别的子元素指定比列量,并且你可以指定固定方向上的行为。
examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "FlexGridSizer")
sizer = wx.FlexGridSizer(rows=3, cols=3, hgap=5, vgap=5)
for label in labels:
bw = BlockWindow(self, label=label)
sizer.Add(bw, 0, 0)
center = self.FindWindowByName("five")
center.SetMinSize((150,50))
self.SetSizer(sizer)
self.Fit()
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
grid bag sizer
grid bag sizer是对flex grid sizer进一步的增强,增强内容如下:
1、能够将一个窗口部件添加到一个特定的单元格。
2、能够使一个窗口部件跨越几个单元格(就像HTML表单中的表格所能做的一样)
examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "GridBagSizer Test")
sizer = wx.GridBagSizer(hgap=5, vgap=5)
for col in range(3):
for row in range(3):
bw = BlockWindow(self, label=labels[row*3 + col])
sizer.Add(bw, pos=(row,col))
# 跨行
bw = BlockWindow(self, label="span 3 rows")
sizer.Add(bw, pos=(0,3), span=(3,1), flag=wx.EXPAND)
# 跨列
bw = BlockWindow(self, label="span all columns")
sizer.Add(bw, pos=(3,0), span=(1,4), flag=wx.EXPAND)
# 使最后的行和列可增长
sizer.AddGrowableCol(3)
sizer.AddGrowableRow(3)
self.SetSizer(sizer)
self.Fit()
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
box类型
一个box sizer是一个垂直列或水平行,窗口部件在其中从左至右或从上到下布置在一条线上。
wx.BoxSizer的构造函数:
wx.BoxSizer(orient)
参数orient代表该sizer的方向,它的取值可以是wx.VERTICAL或wx.HORIZONTAL。examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four".split()
class TestFrame(wx.Frame):
title = "none"
def __init__(self):
wx.Frame.__init__(self, None, -1, self.title)
sizer = self.CreateSizerAndWindows()
self.SetSizer(sizer)
self.Fit()
class VBoxSizerFrame(TestFrame):
title = "VerticalBoxSizer"
def CreateSizerAndWindows(self):
sizer = wx.BoxSizer(wx.VERTICAL)
for label in labels:
bw = BlockWindow(self,label=label,size=(200,30))
sizer.Add(bw, flag=wx.EXPAND)
return sizer
class HBoxSizerFrame(TestFrame):
title = "HorizontalBoxSizer"
def CreateSizerAndWindows(self):
sizer = wx.BoxSizer(wx.HORIZONTAL)
for label in labels:
bw = BlockWindow(self, label=label, size=(75,30))
sizer.Add(bw, flag=wx.EXPAND)
return sizer
class VBoxSizerStretchableFrame(TestFrame):
title = "StretchableBoxSizer"
def CreateSizerAndWindows(self):
sizer = wx.BoxSizer(wx.VERTICAL)
for label in labels:
bw = BlockWindow(self, label=label, size=(200,30))
sizer.Add(bw, flag=wx.EXPAND)
# Add an item that takes all the free space
bw = BlockWindow(self, label="getsAllFreeSpace", size=(200,30))
sizer.Add(bw, 1, flag=wx.EXPAND)
return sizer
class VBoxSizerMultiProportionalFrame(TestFrame):
title = "ProportionalBoxSizer"
def CreateSizerAndWindows(self):
sizer = wx.BoxSizer(wx.VERTICAL)
for label in labels:
bw = BlockWindow(self, label=label, size=(200,30))
sizer.Add(bw, flag=wx.EXPAND)
# Add an item that takes one share of the free space
bw = BlockWindow(self,label="gets 1/4 of the free space",size=(200,30))
sizer.Add(bw, 1, flag=wx.EXPAND)
# Add an item that takes 2 shares of the free space
bw = BlockWindow(self,label="gets 3/4 of the free space",size=(200,30))
sizer.Add(bw, 3, flag=wx.EXPAND)
return sizer
app = wx.PySimpleApp()
frameList = [VBoxSizerFrame, HBoxSizerFrame,
VBoxSizerStretchableFrame,
VBoxSizerMultiProportionalFrame]
for klass in frameList:
frame = klass()
frame.Show()
app.MainLoop()
static box类型
一个static box sizer合并了box sizer和静态框(static box),静态框在sizer的周围提供了一个漂亮的边框和文本标签。
wx.StaticBoxSizer是wx.BoxSizer的子类。它的构造函数要求的参数是静态框和方向:
wx.StaticBoxSizer(box, oient)
box = wx.StaticBox(self.panel, -1, boxlabel)
examples:
import wx
from blockwindow import BlockWindow
labels = "one two three four five six seven eight nine".split()
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "StaticBoxSizerTest")
self.panel = wx.Panel(self)
# make three static boxes with windows positioned inside them
box1 = self.MakeStaticBoxSizer("Box1", labels[0:3])
box2 = self.MakeStaticBoxSizer("Box2", labels[3:6])
box3 = self.MakeStaticBoxSizer("Box3", labels[6:9])
sizer = wx.BoxSizer(wx.HORIZONTAL)
sizer.Add(box1, 0, wx.ALL, 10)
sizer.Add(box2, 0, wx.ALL, 10)
sizer.Add(box3, 0, wx.ALL, 10)
self.panel.SetSizer(sizer)
sizer.Fit(self)
def MakeStaticBoxSizer(self, boxlabel, itemlabels):
# first the static box
box = wx.StaticBox(self.panel, -1, boxlabel)
# then the sizer
sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
# then add items to it like normal
for label in itemlabels:
bw = BlockWindow(self.panel, label=label)
sizer.Add(bw, 0, wx.ALL, 2)
return sizer
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
实际综合使用示例
examples:
import wx
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, "Real World Test")
panel = wx.Panel(self)
# First create the controls
topLbl = wx.StaticText(panel, -1, "AccountInformation")
#1 创建窗口部件
topLbl.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD))
nameLbl = wx.StaticText(panel,-1,"Name:")
name = wx.TextCtrl(panel,-1,"");
addrLbl = wx.StaticText(panel,-1,"Address:")
addr1 = wx.TextCtrl(panel,-1,"");
addr2 = wx.TextCtrl(panel,-1,"");
cstLbl = wx.StaticText(panel,-1,"City,State,Zip:")
city = wx.TextCtrl(panel,-1,"",size=(150,-1));
state = wx.TextCtrl(panel,-1,"",size=(50,-1));
zip = wx.TextCtrl(panel,-1,"",size=(70,-1));
phoneLbl = wx.StaticText(panel,-1,"Phone:")
phone = wx.TextCtrl(panel,-1,"");
emailLbl = wx.StaticText(panel,-1,"Email:")
email = wx.TextCtrl(panel,-1,"");
saveBtn = wx.Button(panel,-1,"Save")
cancelBtn = wx.Button(panel,-1,"Cancel")
# Now do the layout.
# mainSizer is the top-level one that manages everything
#2 垂直的sizer
mainSizer = wx.BoxSizer(wx.VERTICAL)
mainSizer.Add(topLbl, 0, wx.ALL, 5)
mainSizer.Add(wx.StaticLine(panel), 0,
wx.EXPAND|wx.TOP|wx.BOTTOM, 5)
# addrSizer is a grid that holds all of the address info
#3 地址列
addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5)
addrSizer.AddGrowableCol(1)
addrSizer.Add(nameLbl,0,wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(name,0,wx.EXPAND)
addrSizer.Add(addrLbl,0,wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(addr1, 0, wx.EXPAND)
#4 带有空白空间的行
addrSizer.Add((10,10)) # some empty space
addrSizer.Add(addr2, 0, wx.EXPAND)
addrSizer.Add(cstLbl, 0,wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
# the city, state, zip fields are in a sub-sizer
#5 水平嵌套
cstSizer = wx.BoxSizer(wx.HORIZONTAL)
cstSizer.Add(city, 1)
cstSizer.Add(state, 0, wx.LEFT|wx.RIGHT, 5)
cstSizer.Add(zip)
addrSizer.Add(cstSizer, 0, wx.EXPAND)
#6 电话和电子邮箱
addrSizer.Add(phoneLbl,0,wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(phone,0,wx.EXPAND)
addrSizer.Add(emailLbl,0,wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL)
addrSizer.Add(email, 0, wx.EXPAND)
# now add the addrSizer to the mainSizer
#7 添加Flex sizer
mainSizer.Add(addrSizer, 0, wx.EXPAND|wx.ALL, 10)
# The buttons sizer will put them in a row with resizeable
# gaps between and on either side of the buttons
#8 按钮行
btnSizer = wx.BoxSizer(wx.HORIZONTAL)
btnSizer.Add((20,20), 1)
btnSizer.Add(saveBtn)
btnSizer.Add((20,20), 1)
btnSizer.Add(cancelBtn)
btnSizer.Add((20,20), 1)
mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.BOTTOM, 10)
panel.SetSizer(mainSizer)
# Fit the frame to the needs of the sizer. The frame will
# automatically resize the panel as needed. Also prevent the
# frame from getting smaller than this size.
mainSizer.Fit(self)
mainSizer.SetSizeHints(self)
app = wx.PySimpleApp()
TestFrame().Show()
app.MainLoop()
第十二章 处理基本图像
使用图像工作
与平台无关的图像处理由类wx.Image管理,而与平台有关的图像处理由类wx.Bitmap管理。实际上,意思就是外部文件格式由wx.Image装载和保存,而wx.Bitmap负责将图像显示到屏幕。
wx.Image的构造函数:
wx.Image(name, type=wx.BITMAP_TYPE_ANY, index=-1)
载入并缩放简单图像,examples:
import wx
filenames = ["image.bmp", "image.gif", "image.jpg", "image.png" ]
class TestFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="Loading Images")
p = wx.Panel(self)
fgs = wx.FlexGridSizer(cols=2, hgap=10, vgap=10)
for name in filenames:
#1 从文件载入图像
img1 = wx.Image(name, wx.BITMAP_TYPE_ANY)
# Scale the oiginal to another wx.Image
w = img1.GetWidth()
h = img1.GetHeight()
img2 = img1.Scale(w/2, h/2)#2 缩小图像
#3 转换它们为静态位图部件
sb1 = wx.StaticBitmap(p, -1, wx.BitmapFromImage(img1))
sb2 = wx.StaticBitmap(p, -1, wx.BitmapFromImage(img2))
# and put them into the sizer
fgs.Add(sb1)
fgs.Add(sb2)
p.SetSizerAndFit(fgs)
self.Fit()
app = wx.PySimpleApp()
frm = TestFrame()
frm.Show()
app.MainLoop()
图片处理(略)