wxpython中的面板排列

时间:2011-10-03 10:49:30

标签: python wxpython

背景 作为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()

2 个答案:

答案 0 :(得分:2)

我建议你使用wxglade来设计你的GUI。它是快速有效的,在你有一些经验之后,你可以做大部分你可以手动完成的事情。

wxglade没有您正在使用的CheckListCtrlMixinListCtrlAutoWidthMixin等wx.lib小部件或类CheckListCtrl等组合。

为了能够使用这些,使用可用的小部件(pe a wx.panel)临时填充GUI中的一个插槽,然后在生成代码之后,手动替换wx.Panel实例与您的实例。特殊或定制课程。

最后,您的代码有一些主要问题会产生异常,例如wx.frame(对于wx.Frame),坏缩进或未定义的TestList。您的MainGUI类没有__init__方法,也没有初始化父wx.Frame。此外,bottomPanel已添加到hbox sizer但不会添加到topPanel

您编写的组织不会生成您描述的GUI结构,而是生成具有多个小部件的两个面板的结构:

enter image description here

为了更接近您的描述,您至少需要添加几个额外的大小调整器。 使用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()

看起来:

enter image description here

请注意,正如其他答案中所述,不需要将小部件放在面板(widget(panel,..))和面板中的sizer中。它有效,但最好简单地将您的小部件(作为框架的子级 - > widget(self,..))放在sizer(sizerx.Add(widget,..))和sizer(sizery.Add(sizerx))中进行构建结构。
通常,您不会修改此代码。您将其子类化,以添加您的功能或您需要的任何花哨的添加。通过这种方式,您可以再次使用wxglade来更改窗口小部件的位置,以添加其他窗口小部件或大小调整器并重新生成完整文件。

答案 1 :(得分:1)

你真的不需要所有那些额外的面板。事实上,除了wx.Notebooks之外,你很少需要一个以上。相反,我发现将这种东西可视化的最简单方法是在一张纸上画出来,然后在这些东西周围画出矩形。为此,我将有一个垂直方向的主BoxSizer。然后我会使用两个水平BoxSizer作为按钮,然后使用下一个控件。如果你必须以这种方式定位其他三个单独的小部件,那么你可能想要其他一些带有间隔器的BoxSizer。无论如何,一旦你在各种BoxSizer中有了小部件,就可以将它们添加到MainSizer中,然后就完成了。

或者你可以使用带有几个垫片的GridSizer用于最后三个。