背景 作为python的新手以及GUI编程,我想创建一个基于wxpython的GUI应用程序。此GUI将运行一系列测试。文本文件中编写的测试将运行,其步骤应显示在Window中。要选择特定测试,请单击该特定测试的复选框(下图中的CheckListCtrl)。测试结果将显示在MulilineTextCtrl_2Log
中窗口应该是这样的:
我的ASCII艺术并不是那么好,但无论如何
|-------------------------------------------------------------|
|WINDOW TITLExxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx_[]X|
|xxx[SelectAll]xxxxxx[DeselectAll]xxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|[CheckListCtrl] [MultilineTexTCtrl_1]xxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Refresh]xxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx[Execute]xxx|
|xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|xxxxxxx[MulilineTextCtrl_2Log]xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx|
|_____________________________________________________________|
我在为此窗口创建boxsizer方面遇到了麻烦。我无法直观地看到面板的创建
TestList = [('Test1', 'Test1Description1', 'base'), ('Test2', 'Test1Description1', 'base'),'Test3', 'Test1Description3', 'base'),]
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
def __init__(self, parent):
wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
CheckListCtrlMixin.__init__(self)
ListCtrlAutoWidthMixin.__init__(self)
class MainGUI(wx.frame):
panel = wx.Panel(self, -1)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
#topPanel = wx.Panel(panel,-1)
topPanel = wx.Panel(panel, -1,pos=(0,0))
bottomPanel = wx.Panel(panel, -1,pos=(1,0))
self.log = wx.TextCtrl(bottomPanel, -1, style=wx.TE_MULTILINE)
self.list = CheckListCtrl(bottomPanel)
self.list.InsertColumn(0, 'TestID', width=140)
self.list.InsertColumn(1, 'TestDescription')
for i in TestList:
index = self.list.InsertStringItem(sys.maxint, i[0])
self.list.SetStringItem(index, 1, i[1])
self.list.SetStringItem(index, 2, i[2])
vbox2 = wx.BoxSizer(wx.VERTICAL)
sel = wx.Button(topPanel, -1, 'Select All', size=(100, -1))
des = wx.Button(topPanel, -1, 'Deselect All', size=(100, -1))
refresh = wx.Button(bottomPanel, -1, 'Refresh', size=(100, -1))
apply = wx.Button(bottomPanel, -1, 'Execute', size=(100, -1))
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=sel.GetId())
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=des.GetId())
self.Bind(wx.EVT_BUTTON, self.OnRefresh, id=refresh.GetId())
self.Bind(wx.EVT_BUTTON, self.OnExecute, id=apply.GetId())
vbox2.Add(sel, 0, wx.TOP, 5)
vbox2.Add(des)
vbox2.Add(apply,wx.RIGHT)
vbox2.Add(refresh)
topPanel.SetSizer(vbox2)
vbox.Add(self.list, 1, wx.EXPAND, 3)
vbox.Add((-1, 10))
vbox.Add(self.log, 0.5, wx.EXPAND)
vbox.Add((-1, 10))
bottomPanel.SetSizer(vbox)
hbox.Add(bottomPanel, 0, wx.EXPAND | wx.RIGHT, 5)
panel.SetSizer(hbox)
self.Centre()
self.Show(True)
def OnSelectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i)
def OnDeselectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i, False)
def OnRefresh(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '\n')
def OnExecute(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '\n')
app = wx.App()
MainGUI(None, -1, 'Tester')
app.MainLoop()
TestList = [('Test1', 'Test1Description1', 'base'), ('Test2', 'Test1Description1', 'base'),'Test3', 'Test1Description3', 'base'),]
class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin, ListCtrlAutoWidthMixin):
def __init__(self, parent):
wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER)
CheckListCtrlMixin.__init__(self)
ListCtrlAutoWidthMixin.__init__(self)
class MainGUI(wx.frame):
panel = wx.Panel(self, -1)
vbox = wx.BoxSizer(wx.VERTICAL)
hbox = wx.BoxSizer(wx.HORIZONTAL)
#topPanel = wx.Panel(panel,-1)
topPanel = wx.Panel(panel, -1,pos=(0,0))
bottomPanel = wx.Panel(panel, -1,pos=(1,0))
self.log = wx.TextCtrl(bottomPanel, -1, style=wx.TE_MULTILINE)
self.list = CheckListCtrl(bottomPanel)
self.list.InsertColumn(0, 'TestID', width=140)
self.list.InsertColumn(1, 'TestDescription')
for i in TestList:
index = self.list.InsertStringItem(sys.maxint, i[0])
self.list.SetStringItem(index, 1, i[1])
self.list.SetStringItem(index, 2, i[2])
vbox2 = wx.BoxSizer(wx.VERTICAL)
sel = wx.Button(topPanel, -1, 'Select All', size=(100, -1))
des = wx.Button(topPanel, -1, 'Deselect All', size=(100, -1))
refresh = wx.Button(bottomPanel, -1, 'Refresh', size=(100, -1))
apply = wx.Button(bottomPanel, -1, 'Execute', size=(100, -1))
self.Bind(wx.EVT_BUTTON, self.OnSelectAll, id=sel.GetId())
self.Bind(wx.EVT_BUTTON, self.OnDeselectAll, id=des.GetId())
self.Bind(wx.EVT_BUTTON, self.OnRefresh, id=refresh.GetId())
self.Bind(wx.EVT_BUTTON, self.OnExecute, id=apply.GetId())
vbox2.Add(sel, 0, wx.TOP, 5)
vbox2.Add(des)
vbox2.Add(apply,wx.RIGHT)
vbox2.Add(refresh)
topPanel.SetSizer(vbox2)
vbox.Add(self.list, 1, wx.EXPAND, 3)
vbox.Add((-1, 10))
vbox.Add(self.log, 0.5, wx.EXPAND)
vbox.Add((-1, 10))
bottomPanel.SetSizer(vbox)
hbox.Add(bottomPanel, 0, wx.EXPAND | wx.RIGHT, 5)
panel.SetSizer(hbox)
self.Centre()
self.Show(True)
def OnSelectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i)
def OnDeselectAll(self, event):
num = self.list.GetItemCount()
for i in range(num):
self.list.CheckItem(i, False)
def OnRefresh(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '\n')
def OnExecute(self, event):
num = self.list.GetItemCount()
for i in range(num):
if i == 0: self.log.Clear()
if self.list.IsChecked(i):
self.log.AppendText(self.list.GetItemText(i) + '\n')
app = wx.App()
MainGUI(None, -1, 'Tester')
app.MainLoop()
答案 0 :(得分:2)
我建议你使用wxglade来设计你的GUI。它是快速有效的,在你有一些经验之后,你可以做大部分你可以手动完成的事情。
wxglade没有您正在使用的CheckListCtrlMixin
或ListCtrlAutoWidthMixin
等wx.lib小部件或类CheckListCtrl
等组合。
为了能够使用这些,使用可用的小部件(pe a wx.panel)临时填充GUI中的一个插槽,然后在生成代码之后,手动替换wx.Panel实例与您的实例。特殊或定制课程。
最后,您的代码有一些主要问题会产生异常,例如wx.frame(对于wx.Frame),坏缩进或未定义的TestList。您的MainGUI类没有__init__
方法,也没有初始化父wx.Frame
。此外,bottomPanel
已添加到hbox
sizer但不会添加到topPanel
。
您编写的组织不会生成您描述的GUI结构,而是生成具有多个小部件的两个面板的结构:
为了更接近您的描述,您至少需要添加几个额外的大小调整器。 使用wxglade,它会为你做一切。
在这里,您可以为您的设计生成wxglade生成的代码(将wx.ListCtrl
替换为您的CheckListCtrl
:
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
# generated by wxGlade HG on Tue Oct 04 12:45:03 2011
import wx
# begin wxGlade: extracode
# end wxGlade
class MainGUI(wx.Frame):
def __init__(self, *args, **kwds):
# begin wxGlade: MainGUI.__init__
kwds["style"] = wx.DEFAULT_FRAME_STYLE
wx.Frame.__init__(self, *args, **kwds)
self.button_3 = wx.Button(self, -1, "Select All")
self.button_4 = wx.Button(self, -1, "DeselectAll")
self.list_ctrl_1 = wx.ListCtrl(self, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER)
self.text_ctrl_1 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
self.button_1 = wx.Button(self, -1, "Refresh")
self.button_2 = wx.Button(self, -1, "Execute")
self.text_ctrl_2 = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE)
self.__set_properties()
self.__do_layout()
# end wxGlade
def __set_properties(self):
# begin wxGlade: MainGUI.__set_properties
self.SetTitle("frame_1")
self.SetBackgroundColour(wx.Colour(255, 170, 5))
self.list_ctrl_1.SetMinSize((200, 264))
# end wxGlade
def __do_layout(self):
# begin wxGlade: MainGUI.__do_layout
sizer_1 = wx.BoxSizer(wx.VERTICAL)
sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
sizer_3 = wx.BoxSizer(wx.VERTICAL)
sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
sizer_4.Add(self.button_3, 0, wx.ALL, 5)
sizer_4.Add(self.button_4, 0, wx.ALL, 5)
sizer_4.Add((20, 20), 1, wx.EXPAND, 0)
sizer_1.Add(sizer_4, 0, wx.EXPAND, 0)
sizer_2.Add(self.list_ctrl_1, 0, wx.ALL|wx.EXPAND, 5)
sizer_2.Add(self.text_ctrl_1, 0, wx.ALL|wx.EXPAND, 5)
sizer_3.Add(self.button_1, 0, wx.ALL, 5)
sizer_3.Add(self.button_2, 0, wx.ALL, 5)
sizer_2.Add(sizer_3, 0, wx.EXPAND, 0)
sizer_1.Add(sizer_2, 1, wx.EXPAND, 0)
sizer_1.Add(self.text_ctrl_2, 0, wx.ALL|wx.EXPAND, 5)
self.SetSizer(sizer_1)
sizer_1.Fit(self)
self.Layout()
# end wxGlade
# end of class MainGUI
if __name__ == "__main__":
app = wx.PySimpleApp(0)
wx.InitAllImageHandlers()
frame_1 = MainGUI(None, -1, "")
app.SetTopWindow(frame_1)
frame_1.Show()
app.MainLoop()
看起来:
请注意,正如其他答案中所述,不需要将小部件放在面板(widget(panel,..)
)和面板中的sizer中。它有效,但最好简单地将您的小部件(作为框架的子级 - > widget(self,..)
)放在sizer(sizerx.Add(widget,..)
)和sizer(sizery.Add(sizerx)
)中进行构建结构。
通常,您不会修改此代码。您将其子类化,以添加您的功能或您需要的任何花哨的添加。通过这种方式,您可以再次使用wxglade来更改窗口小部件的位置,以添加其他窗口小部件或大小调整器并重新生成完整文件。
答案 1 :(得分:1)
你真的不需要所有那些额外的面板。事实上,除了wx.Notebooks之外,你很少需要一个以上。相反,我发现将这种东西可视化的最简单方法是在一张纸上画出来,然后在这些东西周围画出矩形。为此,我将有一个垂直方向的主BoxSizer。然后我会使用两个水平BoxSizer作为按钮,然后使用下一个控件。如果你必须以这种方式定位其他三个单独的小部件,那么你可能想要其他一些带有间隔器的BoxSizer。无论如何,一旦你在各种BoxSizer中有了小部件,就可以将它们添加到MainSizer中,然后就完成了。
或者你可以使用带有几个垫片的GridSizer用于最后三个。