user974168
user974168

Reputation: 237

Panel arrangement in wxpython

Background As a newbie to python as well as to GUI Programming, I would like to create a wxpython based GUI application. This GUI will run a series of tests The tests written in text files will be running and it's steps should be displayed in the Window. For selecting a particular test,click the checkbox (CheckListCtrl in Figure below) for that particular test. The result of the test will be displayed in MulilineTextCtrl_2Log

The window should be like this :

My ASCII art is not so good but anyways

|-------------------------------------------------------------|  
|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|     
|_____________________________________________________________|

I have having trouble over creating the boxsizers for this window. I am having trouble visualizing the creation of panels

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

Upvotes: 0

Views: 824

Answers (2)

joaquin
joaquin

Reputation: 85613

I recommend to you the use of wxglade to design your GUIs. It is fast and effective and after you have some experience you can do most of the things you can do manually.

wxglade does not have wx.lib widgets suchs as CheckListCtrlMixin or ListCtrlAutoWidthMixin that you are using or combinations such as your class CheckListCtrl.

In order to be able to use these, fill temporarily a slot in the GUI with an available widget (p.e. a wx.panel) and then later, after generating the code, substitute manually the wx.Panel instantiation with that of your special or custom class.

Finally, your code has some major problems that produce exceptions such as wx.frame (for wx.Frame), the bad indentation or the undefined TestList. Your MainGUI class has not __init__ method and does neither initialize the parent wx.Frame. Also the bottomPanel is added to hbox sizer but not the topPanel.

The organization you wrote does not produce the GUI structure you describe but that of two panels with several widgets:

enter image description here

To be closer to your description you need at least to add a couple of additional sizers. Use wxglade and it will do everything for you.

Here you have the wxglade generated code for a design like yours (substitute the wx.ListCtrl with your 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()

And the look:

enter image description here

Note, as said in other answer, there is not need for putting your widgets in panels (widget(panel,..)) and the panels in sizers. It works, but it is better to simply put your widgets (as child of the frame -> widget(self,..)) in the sizers (sizerx.Add(widget,..)) and sizers in sizers (sizery.Add(sizerx)) to build the structure.
Normally you do not modify this code. You subclass it instead to add your functionality or whatever fancy addition you need. In this way you can always use again wxglade to make changes in the position of the widgets ot to add additional widgets or sizers and regenerate the full file.

Upvotes: 2

Mike Driscoll
Mike Driscoll

Reputation: 33071

You don't really need all those extra panels. In fact, you rarely need more than one except for wx.Notebooks and the like. Instead, what I find to be the easiest way to visualize this sort of thing is to sketch it out on a piece of paper and then draw rectangles around the stuff. For this, I would have a main BoxSizer vertically oriented. Then I'd use two horizontal BoxSizers for the buttons and the next to controls. If you have to position the other three single widgets that way, then you'd probably want some other BoxSizers with spacers in them. Anyway, once you have the widgets in the various BoxSizers, you add them to the MainSizer and you're done.

Or you could use a GridSizer with a few spacers for the last three.

Upvotes: 1

Related Questions