Organization in wxPython

While absolute positioning of controls may work in some odd cases, absolute positioning isn’t convenient or pretty. This article will explain methods that can be used to better oganize controls in your wxPython aplications.

You probably already know how to create basic wxPython applications and position controls in them. If you don’t, then this article is not for you. Take a look at A Look at wxPython.

A Few More Controls

Before we work on organizing controls, let’s learn about a few more controls. Right not, we only know how to place buttons and text fields in our applications. It’s difficult to make anything special with just these two controls, a menu and a few dialogs. First, let’s take a look at a wxChoice control. It gives you a drop-down list of choices, which are taken from a Python list. Here’s how you would make a basic wxChoice control:

wxChoice ( self, -1, choices = [ 'A', 'B', 'C', 'D' ] )

Note that I passed -1 as the control’s id. This is the same as passing wxID_ANY, except, of course, that it’s a bit shorter.

It’s not important that we stick it in an application to test it out immediately. We’ll save that for a few minutes. Our next control, wxComboBox, combines wxTextCtrl with wxChoice. It allows the user to either select an item from the list or specify his or her own text. It works similar to wxChoice:

wxComboBox ( self, -1, ‘Default Text’, choices = [ 'A', 'B', 'C', 'D' ] )

Next up is wxListBox. This works similar to wxChoice, except it’s already expanded. Again, it works similar to wxChoice:

wxListBox ( self, -1, choices = [ 'A', 'B', 'C', 'D' ] )

Last, but not least, comes wxStaticText. Like the name suggests, it allows you to place text in your applications.

WxStaticText ( self, -1, ‘A bit of text.’ )

{mospagebreak title=Box Sizers}

Now let’s organize things. We’ll take a look at sizers throughout this tutorial. Sizers are simply devices that let you organize widgets. The most basic type of sizer is wxBoxSizer. It lets you organize widgets horizontally and vertically. It is also possible to nest sizers, as I’ll explain in a bit. First, let me show you the syntax. Here is how you would create  a horizontal wxBoxSizer:

wxBoxSizer ( wxHORIZONTAL )

Here’s how you create a vertical wxBoxSizer:

wxBoxSizer ( wxVERTICAL )

Of course, now we have to do something with our sizer. Let’s dive right in to some code:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button = wxButton ( self.panel, -1, ‘Click Me’ )
      self.sizer = wxBoxSizer ( wxVERTICAL )
      self.sizer.Add ( self.text )
      self.sizer.Add ( self.button )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

All right. This should be bite-size, but let’s tear it apart just in case there’s anything you don’t completely understand. We start our application as normal. We import everything we need and create a frame. We then add a panel and two controls. Notice that the panel is the parent of both of the controls. Next, we create a vertical wxBoxSizer. This organizes our conrols vertically. We then add our two controls and adjust the size of both the panel and the frame to match the sizes of the controls. Finally, we show our frame to the user.

Creating a horizontal sizer is done the same way, with the exception of one variable:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button = wxButton ( self.panel, -1, ‘Click Me’ )
      self.sizer = wxBoxSizer ( wxHORIZONTAL )
      self.sizer.Add ( self.text )
      self.sizer.Add ( self.button )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Neither looks especially pretty, especially the horizontal one. Let’s modify the vertical one a bit more and align the button in the center.

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button = wxButton ( self.panel, -1, ‘Click Me’ )
      self.sizer = wxBoxSizer ( wxVERTICAL )
      self.sizer.Add ( self.text )
      self.sizer.Add ( self.button, 0, wxALIGN_CENTER )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Notice how we pass three arguments to the Add method. The first, of course, is the control we want to add to the sizer. There’s nothing new there. The second is how the control should look in proportion to other controls. For example, if you want one control to be twice as big as another, pass 2 and 1, respectively. We pass 0, since we don’t want to alter the size of our button. The third and final argument can vary. Since we pass 0, we have the choice of aligning our control any way we want it. We choose to align it in the center. Here are other options:

wxALIGN_LEFT
wxALIGN_RIGHT
wxALIGN_TOP
wxALIGN_BOTTOM
wxALIGN_CENTER_VERTICAL
wxALIGN_CENTER_HORIZONTAL

{mospagebreak title=Box Sizers Continued}

Of course, what if we do choose to size it proportinally? Let’s take a look:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button1 = wxButton ( self.panel, -1, ‘Click Me’ )
      self.button2 = wxButton ( self.panel, -1, ‘Me as well.’ )
      self.sizer = wxBoxSizer ( wxVERTICAL )
      self.sizer.Add ( self.text, 1  )
      self.sizer.Add ( self.button1, 4 )
      self.sizer.Add ( self.button2, 6 )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Now let’s play around with the third argument. Execute this application:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button1 = wxButton ( self.panel, -1, ‘Click Me’ )
      self.button2 = wxButton ( self.panel, -1, ‘Me as well.’ )
      self.sizer = wxBoxSizer ( wxVERTICAL )
      self.sizer.Add ( self.text, 1, wxGROW  )
      self.sizer.Add ( self.button1, 4, wxGROW )
      self.sizer.Add ( self.button2, 6, wxGROW )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Resize the window a bit and notice the behavior of the controls. Let’s now change wxGROW to wxSHAPED:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.text = wxStaticText ( self.panel, -1, ‘Just some text. That is all. I promise.’ )
      self.button1 = wxButton ( self.panel, -1, ‘Click Me’ )
      self.button2 = wxButton ( self.panel, -1, ‘Me as well.’ )
      self.sizer = wxBoxSizer ( wxVERTICAL )
      self.sizer.Add ( self.text, 1, wxSHAPED  )
      self.sizer.Add ( self.button1, 4, wxSHAPED )
      self.sizer.Add ( self.button2, 6, wxSHAPED )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Again, resize the window and notice the behavior of the controls.

It is also possible to nest box sizers within one another. A good use for this would be centering a control – or another sizer – in a frame. First, we would create a vertical sizer and add a space with a proportion of 1. I’ll show you how to add a space in the example. It’s not hard at all. Next we would add a horizontal sizer to the vertical sizer. To the horizontal sizer we would add a space, our control and another space. Both spaces would have a proportion of 1, and the control would have a proportion of 0 ( unless you really wanted to resize it ). The horizontal sizer itself would have a proportion of 0. Finally, another space would be added to the vertical sizer. This may sound complicated, but it’s very simple when put into code:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.horizontal = wxBoxSizer ( wxHORIZONTAL )
      self.horizontal.Add ( ( 0, 0 ), 1, wxEXPAND )
      self.horizontal.Add ( wxStaticText ( self.panel, wxID_ANY, ‘Centered.’ ) )
      self.horizontal.Add ( ( 0, 0 ), 1, wxEXPAND )
      self.vertical = wxBoxSizer ( wxVERTICAL )
      self.vertical.Add ( ( 0, 0 ), 1, wxEXPAND )
      self.vertical.Add ( self.horizontal, 0, wxALIGN_CENTER )
      self.vertical.Add ( ( 0, 0 ), 1, wxEXPAND )
      self.panel.SetSizerAndFit ( self.vertical )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

{mospagebreak title=Grid Bag Sizers}

While box sizers are nice to work with, grid bag sizers are also nice. They allow controls to be put in a grid. For example, say we wanted four buttons arranged in a square. This can be done with a grid bag sizer. Let’s take a look at how it is done:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.sizer = wxGridBagSizer ( 2, 2 )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 1′ ), ( 0, 0 ) )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 2′ ), ( 0, 1 ) )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 3′ ), ( 1, 0 ) )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 7′ ), ( 1, 1 ) )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )
      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

As you can see, it’s not very hard. Let’s manipulate our grid a bit. Let’s widen the horizontal border to ten pixels instead of two and make the buttons expandable. Let’s also get rid of the second button and make the first button take up the whole row:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.sizer = wxGridBagSizer ( 2, 10 )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 1′ ), ( 0, 0 ), ( 1, 2 ), wxEXPAND )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 3′ ), ( 1, 0 ), ( 1, 1 ) )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 7′ ), ( 1, 1 ), ( 1, 1 ) )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Notice that every cell in the grid had the same size. We can change that using a flexible grid sizer:

from wxPython.wx import *

class SizerFrame ( wxFrame ):

   def __init__ ( self ):

      wxFrame.__init__ ( self, None, -1, ‘Sizers’ )

      self.panel = wxPanel ( self, -1 )
      self.sizer = wxFlexGridSizer ( 2, 2, 2, 2 ) # rows, columns, vertical gap, horizontal gap
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 1′, size = ( 50, 50 ) ), 0, wxEXPAND )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 2′ ), 0, wxEXPAND )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 3′ ), 0, wxEXPAND )
      self.sizer.Add ( wxButton ( self.panel, wxID_ANY, ‘Button 7′ ), 0, wxEXPAND )
      self.sizer.AddGrowableRow ( 0 )
      self.sizer.AddGrowableCol ( 0 )
      self.panel.SetSizerAndFit ( self.sizer )
      self.SetClientSize ( self.panel.GetSize() )

      self.Show ( True )

application = wxPySimpleApp()
window = SizerFrame()
application.MainLoop()

Conclusion

That’s it. You should now know enough about sizers to create organized applications instead of applications featuring controls thrown around the frame. Sizers make a lot more sense than absolute positioning and eliminate a lot of the work involved in the absolute positioning of controls. You also know a few more controls, enough to do a few small applications.

[gp-comments width="770" linklove="off" ]

chat sex hikayeleri Ensest hikaye