Reputation: 237
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
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:
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:
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
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