wxPython基金会
我试图理解wxPython,但是大多数文档只是以猴子见猴子的方式展示程序,没有解释库的基本原理 考虑以下代码片段:wxPython基金会,python,wxpython,wxwidgets,Python,Wxpython,Wxwidgets,我试图理解wxPython,但是大多数文档只是以猴子见猴子的方式展示程序,没有解释库的基本原理 考虑以下代码片段: import wx class MyFrame(wx.Frame): def __init__(self, parent, id, title): wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(250, 50)) panel = wx.Panel(self, -1)
import wx
class MyFrame(wx.Frame):
def __init__(self, parent, id, title):
wx.Frame.__init__(self, parent, id, title, (-1, -1), wx.Size(250, 50))
panel = wx.Panel(self, -1)
box = wx.BoxSizer(wx.HORIZONTAL)
box.Add(wx.Button(panel, -1, 'Button1'), 1 )
box.Add(wx.Button(panel, -1, 'Button2'), 1 )
box.Add(wx.Button(panel, -1, 'Button3'), 1 )
panel.SetSizer(box)
self.Centre()
class MyApp(wx.App):
def OnInit(self):
frame = MyFrame(None, -1, 'wxboxsizer.py')
frame.Show(True)
return True
app = MyApp(0)
app.MainLoop()
我看到这里有三个集装箱-
框架、面板和盒子
还有三个按钮
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.') # Add a button
btn.Bind(wx.EVT_BUTTON, self.OnQuit) # Bind the first button to quit
btn2 = wx.Button(panel, label='I am a do nothing button.') # Add a second
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
wxPython很复杂,但其他GUI工具包也很复杂。让我们把它分解一下。要回答第一个问题,wxPython GUI的常规布局如下所示:
frame -> panel -> sizer -> widgets
frame -> sizer -> panel -> sizer -> widgets
我通常和第一个一起去。如果布局复杂,我可能会嵌套尺寸器,因此我最终会得到如下结果:
frame -> panel -> sizer -> sizer1 -> widgets
-> sizer2 -> widgets
2) 第一个面板应始终作为其唯一小部件添加到框架中:
wx.Frame.__init__(self, None, title="Test")
panel = wx.Panel(self)
3) boxSizer通常进入面板。我通常会给面板一个顶级的boxSizer,然后在面板内部创建嵌套的Sizer
4) 按钮和其他小部件会同时出现在面板和sizer中!您将按钮的父级设置为面板,然后要在面板中布局小部件,您将它们放置在面板的sizer对象中。如果将按钮的父项设置为帧,则会出现混乱 5) SetSizer用于告诉wxPython sizer属于哪个小部件。在代码中,为面板提供了box sizer实例。sizer对象的Add()方法用于将小部件(和sizer)添加到sizer本身
我希望这能回答你所有的问题。您可能还会发现下面的文章很有用,因为它链接到了我用于wx的大多数文档:让我们慢慢开发一个wxPython应用程序,看看它是如何工作的 这是创建wxPython应用程序所需的最少代码量。它包含一个wx.Frame(您可以将其理解为一个窗口)。窗户里什么也没有。app.MainLoop()是捕获任何事件(如鼠标单击、关闭或最小化窗口)的循环
import wx
app = wx.App()
frame = wx.Frame(None, -1, 'A Frame')
frame.Show()
app.MainLoop()
窗口本身不是很有趣,但仍然相当强大。我们可以添加诸如菜单项和标题之类的内容,甚至可以选择诸如无最大化按钮之类的样式。让我们做所有这些
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar() # Create a menubar
fileMenu = wx.Menu() # Create the file menu
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application') # Add a quit line
menubar.Append(fileMenu, '&File') # Add the File menu to the Menubar
self.SetMenuBar(menubar) # Set the menubar as THE menu bar
self.Bind(wx.EVT_MENU, self.OnQuit, fitem) # Bind the quit line
self.Show() # Show the frame
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX) # Some styles
app.MainLoop()
你会发现事情很快就变得复杂了。这实际上是为了帮助我们保持组织性。我们将框架移动到它自己的类中,并定义了一些特征。我们需要一个菜单,将菜单项绑定到关闭应用程序的OnQuit()
方法。这是最基本的一层
让我们添加一个面板。面板就像黑板。它位于wx.Frame的顶部(就像一块黑板靠在墙上)。一旦我们有了一个面板,我们就可以开始添加大小器和小部件
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1) # Added a panel!
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
您会注意到,根据平台的不同,会有细微的差异。窗口现在已填充,颜色较浅。那是我们的小组。现在让我们添加一些按钮
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.') # Add a button
btn.Bind(wx.EVT_BUTTON, self.OnQuit) # Bind the first button to quit
btn2 = wx.Button(panel, label='I am a do nothing button.') # Add a second
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
现在我们有了面板上的按钮。但它们看起来很糟糕。他们一个接一个地被卡住了。我们可以使用pos=(x,y)属性手动定位它们,但这非常繁琐。让我们叫我们的朋友boxsizer来
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
vbox = wx.BoxSizer(wx.VERTICAL) # Create a vertical boxsizer
vbox.Add(btn) # Add button 1 to the sizer
vbox.Add(btn2) # Add button 2 to the sizer
panel.SetSizer(vbox) # Tell the panel to use this sizer as its sizer.
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
那已经好多了!让我们看看水平测径仪是什么样子
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
vbox = wx.BoxSizer(wx.VERTICAL) # A vertical sizer
hbox = wx.BoxSizer(wx.HORIZONTAL) # And a horizontal one?? but why?
hbox.Add(btn) # Let's add the buttons first
hbox.Add(btn2)
panel.SetSizer(hbox) # see why we need to tell the panel which sizer to use? We might have two!
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
有趣!注意到我是如何保存我们的vbox的吗?让我们试着把两者结合起来。我们需要更多的按钮,也许还需要一些文本控件
import wx
class Frame(wx.Frame):
def __init__(self, *args, **kwargs):
super(Frame, self).__init__(*args, **kwargs)
menubar = wx.MenuBar()
fileMenu = wx.Menu()
fitem = fileMenu.Append(wx.ID_EXIT, 'Quit', 'Quits application')
menubar.Append(fileMenu, '&File')
self.SetMenuBar(menubar)
self.Bind(wx.EVT_MENU, self.OnQuit, fitem)
panel = wx.Panel(self, -1)
btn = wx.Button(panel, label='I am a closing button.')
btn.Bind(wx.EVT_BUTTON, self.OnQuit)
btn2 = wx.Button(panel, label='I am a do nothing button.')
txt1 = wx.TextCtrl(panel, size=(140,-1))
txt2 = wx.TextCtrl(panel, size=(140,-1))
txt3 = wx.TextCtrl(panel, size=(140,-1))
btn3 = wx.Button(panel, label='I am a happy button.')
btn4 = wx.Button(panel, label='I am a bacon button.')
btn5 = wx.Button(panel, label='I am a python button.')
# So many sizers!
vbox = wx.BoxSizer(wx.VERTICAL)
hbox1 = wx.BoxSizer(wx.HORIZONTAL)
hbox2 = wx.BoxSizer(wx.HORIZONTAL)
hbox3 = wx.BoxSizer(wx.HORIZONTAL)
hbox4 = wx.BoxSizer(wx.HORIZONTAL)
hbox1.Add(btn)
hbox1.Add(btn2)
hbox1.Add(txt1)
hbox2.Add(txt2)
hbox2.Add(txt3)
hbox2.Add(btn3)
hbox3.Add(btn4)
hbox4.Add(btn5)
vbox.Add(hbox1)
vbox.Add(hbox2)
vbox.Add(hbox3)
vbox.Add(hbox4)
panel.SetSizer(vbox)
self.Show()
def OnQuit(self, e):
self.Close()
app = wx.App()
Frame(None, -1, 'A Frame', style=wx.RESIZE_BORDER
| wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX)
app.MainLoop()
我们首先将按钮和文本小部件添加到水平尺寸器,然后再添加到垂直尺寸器。我们在sizers中有sizers,这是wxPython中一种非常常见的操作方式
__________________________
|__hbox1_|_______________| \
|_hbox2____|______|____|_| \___VBOX
|___hbox3______|_________| /
|_______|__hbox4_|_______| /
有点像这样。在每个hbox中,我们都有许多小部件。取决于你想要多少。希望这有帮助 我强烈建议你拿一本诺埃尔·拉平和罗宾·邓恩的《哈利·波特》。由于Robin是wxPython的主要作者/架构师之一,您将获得非常好的见解和清晰的解释
N.B.在任何人问我之前,我绝对与这本书、作者或出版商没有商业联系。“按钮和其他小部件都在面板和大小器中”-你能解释一下这是什么意思吗?什么是sizer?它不是一个容器吗?sizer就像一个看不见的容器,它定位和调整它包含的小部件,它就像父部件和子部件之间的粘合剂。是的。面板是父级,但大小调整器控制小部件的定位方式以及是否拉伸。如果你没有将小部件放在面板上,那么标签可能无法正常工作。干得好!我应该在我的答案上花更多的时间。我为你写的代码,不是复制粘贴的。面板通过提供
self
作为第一个关键字添加到框架中。这等同于说(parent=self,id=-1)
。您可以执行frame=wx.frame(无,-1,“我的框架”)
和panel=wx.panel(frame,-1)
来保持简单。我将向您展示创建wxPython应用程序的传统方法,以及这些应用程序是如何组合在一起的。如果您想知道原因/方式,可以参考API文档。我的建议是开始编写简单的GUI程序,这样您将对工作方式有一个直观的了解。对不起,我帮不上什么忙。如果你真的写了那么多代码,我道歉。它看起来和我读过的另一篇教程非常相似。你可能指的是Zetcode的网站,这是我学习wxPython的地方。从那以后我一直在使用他的基本模板。创建wxFrame的基本方法相当通用。我知道Mike的应用程序有一个稍微不同的模板,(我不认为他使用*args,**kwargs),但我怀疑有什么真正的区别,我相信他的模板会适合你需要做的任何事情。wxpythonwiki