2019年4月27日 星期六

[ Python 文章收集 ] wxPython - Layout management in wxPython

Source From Here 
Layout management in wxPython 
A typical application consists of various widgets. Those widgets are placed inside container widgets. A programmer must manage the layout of the application. This is not an easy task. In wxPython it is possible to lay out widgets using absolute positioning or using sizers. 

Absolute Positioning 
The programmer specifies the position and the size of each widget in pixels. Absolute positioning has several disadvantages
* The size and the position of a widget do not change if we resize a window.
* Applications look different on various platforms.
* Changing fonts in the application might spoil the layout.
* If we decide to change our layout, we must completely redo our layout, which is tedious and time consuming.

There might be situations where we can possibly use absolute positioning. For instance, small test examples. But mostly, in real world programs, programmers use sizers

In our example we have a simple skeleton of a text editor. If we resize the window, the size of out wx.TextCtrl does not change as we would expect: 
absolute.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4. """  
  5. ZetCode wxPython tutorial  
  6.   
  7. In this example, we lay out widgets using  
  8. absolute positioning.  
  9.   
  10. author: Jan Bodnar  
  11. website: www.zetcode.com  
  12. last modified: April 2018  
  13. """  
  14.   
  15. import wx  
  16.   
  17.   
  18. class Example(wx.Frame):  
  19.   
  20.     def __init__(self, parent, title):  
  21.         super(Example, self).__init__(parent, title=title,  
  22.             size=(500400))  
  23.   
  24.         self.InitUI()  
  25.         self.Centre()  
  26.   
  27.     def InitUI(self):  
  28.   
  29.         self.panel = wx.Panel(self)  
  30.   
  31.         self.panel.SetBackgroundColour("gray")  
  32.   
  33.         self.LoadImages()  
  34.   
  35.         self.mincol.SetPosition((2020))  
  36.         self.bardejov.SetPosition((20160))  
  37.         self.rotunda.SetPosition((25020))  
  38.   
  39.   
  40.     def LoadImages(self):  
  41.   
  42.         self.mincol = wx.StaticBitmap(self.panel, wx.ID_ANY,  
  43.             wx.Bitmap("mincol.jpg", wx.BITMAP_TYPE_ANY))  
  44.   
  45.         self.bardejov = wx.StaticBitmap(self.panel, wx.ID_ANY,  
  46.             wx.Bitmap("bardejov.jpg", wx.BITMAP_TYPE_ANY))  
  47.   
  48.         self.rotunda = wx.StaticBitmap(self.panel, wx.ID_ANY,  
  49.             wx.Bitmap("rotunda.jpg", wx.BITMAP_TYPE_ANY))  
  50.   
  51.   
  52. def main():  
  53.     app = wx.App()  
  54.     ex = Example(None, title='Absolute positioning')  
  55.     ex.Show()  
  56.     app.MainLoop()  
  57.   
  58.   
  59. if __name__ == '__main__':  
  60.     main()  


In the above example, we position three images using absolute coordinates. With the SetPosition() method we place the image at exact position in coordinates we want. 

Using sizers 
Sizers do address all those issues we mentioned by absolute positioning. wxPython has the following sizers: 
wx.BoxSizer 
wx.StaticBoxSizer (tutorialspoint)
wx.GridSizer
wx.FlexGridSizer
wx.GridBagSizer

wx.BoxSizer 
wx.BoxSizer enables us to put several widgets into a row or a column. We can put another sizer into an existing sizer. This way we can create very complex layouts: 
  1. box = wx.BoxSizer(integer orient)  
  2. box.Add(wx.Window window, integer proportion=0, integer flag = 0, integer border = 0)  
The orientation can be wx.VERTICAL or wx.HORIZONTAL. Adding widgets into the wx.BoxSizer is done via the Add() method. In order to understand it, we need to look at its parameters. The proportion parameter defines the ratio of how widgets change in the defined orientation. Let's assume we have three buttons with the proportions 0, 1, and 2. They are added into a horizontal wx.BoxSizer. Button with proportion 0 will not change at all. Button with proportion 2 will change twice more than the one with proportion 1 in the horizontal dimension. 

With the flag parameter you can further configure the behaviour of the widgets within a wx.BoxSizer. We can control the border between the widgets. We add some space between widgets in pixels. In order to apply border we need to define sides, where the border will be used. We can combine them with the | operator; for instance wx.LEFT | wx.BOTTOM. We can choose between these flags: 
wx.LEFT
wx.RIGHT
wx.BOTTOM
wx.TOP
wx.ALL

The sizer is set to the panel widget with SetSizer() method. 
border.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4. """  
  5. ZetCode wxPython tutorial  
  6.   
  7. In this example we place a panel inside   
  8. another panel.  
  9.   
  10. author: Jan Bodnar  
  11. website: www.zetcode.com  
  12. last modified: April 2018  
  13. """  
  14.   
  15. import wx  
  16.   
  17.   
  18. class Example(wx.Frame):  
  19.   
  20.     def __init__(self, parent, title):  
  21.         super(Example, self).__init__(parent, title=title)  
  22.   
  23.         self.InitUI()  
  24.         self.Centre()  
  25.   
  26.     def InitUI(self):  
  27.   
  28.         panel = wx.Panel(self)  
  29.   
  30.         panel.SetBackgroundColour('#4f5049')  
  31.         vbox = wx.BoxSizer(wx.VERTICAL)  
  32.   
  33.         midPan = wx.Panel(panel)  
  34.         midPan.SetBackgroundColour('#ededed')  
  35.   
  36.         vbox.Add(midPan, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)  
  37.         panel.SetSizer(vbox)  
  38.   
  39.   
  40. def main():  
  41.   
  42.     app = wx.App()  
  43.     ex = Example(None, title='Border')  
  44.     ex.Show()  
  45.     app.MainLoop()  
  46.   
  47.   
  48. if __name__ == '__main__':  
  49.     main()  
In the above example, we place some space around a panel by: 
  1. vbox.Add(midPan, wx.ID_ANY, wx.EXPAND | wx.ALL, 20)  
In border.py we have placed a 20 px border around a midPan panel. wx.ALL applies the border size to all four sides. 

If we use wx.EXPAND flag, our widget will use all the space that has been allotted to it. Lastly, we can also define the alignment of our widgets. We do it with the following flags: 
wx.ALIGN_LEFT
wx.ALIGN_RIGHT
wx.ALIGN_TOP
wx.ALIGN_BOTTOM
wx.ALIGN_CENTER_VERTICAL
wx.ALIGN_CENTER_HORIZONTAL
wx.ALIGN_CENTER



GoToClass example 
In the following example we introduce several important ideas. 
goto_class.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4.   
  5. """  
  6. ZetCode wxPython tutorial  
  7.   
  8. In this example we create a Go To class  
  9. layout with wx.BoxSizer.  
  10.   
  11. author: Jan Bodnar  
  12. website: www.zetcode.com  
  13. last modified: April 2018  
  14. """  
  15.   
  16. import wx  
  17.   
  18. class Example(wx.Frame):  
  19.   
  20.     def __init__(self, parent, title):  
  21.         super(Example, self).__init__(parent, title=title)  
  22.   
  23.         self.InitUI()  
  24.         self.Centre()  
  25.   
  26.     def InitUI(self):  
  27.   
  28.         panel = wx.Panel(self)  
  29.   
  30.         font = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT)  
  31.   
  32.         font.SetPointSize(9)  
  33.   
  34.         vbox = wx.BoxSizer(wx.VERTICAL)  
  35.   
  36.         hbox1 = wx.BoxSizer(wx.HORIZONTAL)  
  37.         st1 = wx.StaticText(panel, label='Class Name')  
  38.         st1.SetFont(font)  
  39.         hbox1.Add(st1, flag=wx.RIGHT, border=8)  
  40.         tc = wx.TextCtrl(panel)  
  41.         hbox1.Add(tc, proportion=1)  
  42.         vbox.Add(hbox1, flag=wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, border=10)  
  43.   
  44.         vbox.Add((-110))  
  45.   
  46.         hbox2 = wx.BoxSizer(wx.HORIZONTAL)  
  47.         st2 = wx.StaticText(panel, label='Matching Classes')  
  48.         st2.SetFont(font)  
  49.         hbox2.Add(st2)  
  50.         vbox.Add(hbox2, flag=wx.LEFT | wx.TOP, border=10)  
  51.   
  52.         vbox.Add((-110))  
  53.   
  54.         hbox3 = wx.BoxSizer(wx.HORIZONTAL)  
  55.         tc2 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)  
  56.         hbox3.Add(tc2, proportion=1, flag=wx.EXPAND)  
  57.         vbox.Add(hbox3, proportion=1, flag=wx.LEFT|wx.RIGHT|wx.EXPAND,  
  58.             border=10)  
  59.   
  60.         vbox.Add((-125))  
  61.   
  62.         hbox4 = wx.BoxSizer(wx.HORIZONTAL)  
  63.         cb1 = wx.CheckBox(panel, label='Case Sensitive')  
  64.         cb1.SetFont(font)  
  65.         hbox4.Add(cb1)  
  66.         cb2 = wx.CheckBox(panel, label='Nested Classes')  
  67.         cb2.SetFont(font)  
  68.         hbox4.Add(cb2, flag=wx.LEFT, border=10)  
  69.         cb3 = wx.CheckBox(panel, label='Non-Project classes')  
  70.         cb3.SetFont(font)  
  71.         hbox4.Add(cb3, flag=wx.LEFT, border=10)  
  72.         vbox.Add(hbox4, flag=wx.LEFT, border=10)  
  73.   
  74.         vbox.Add((-125))  
  75.   
  76.         hbox5 = wx.BoxSizer(wx.HORIZONTAL)  
  77.         btn1 = wx.Button(panel, label='Ok', size=(7030))  
  78.         hbox5.Add(btn1)  
  79.         btn2 = wx.Button(panel, label='Close', size=(7030))  
  80.         hbox5.Add(btn2, flag=wx.LEFT|wx.BOTTOM, border=5)  
  81.         vbox.Add(hbox5, flag=wx.ALIGN_RIGHT|wx.RIGHT, border=10)  
  82.   
  83.         panel.SetSizer(vbox)  
  84.   
  85.   
  86. def main():  
  87.   
  88.     app = wx.App()  
  89.     ex = Example(None, title='Go To Class')  
  90.     ex.Show()  
  91.     app.MainLoop()  
  92.   
  93.   
  94. if __name__ == '__main__':  
  95.     main()  

Figure: A GoToClass window 

wx.GridSizer 
The wx.GridSizer lays out widgets in two dimensional table. Each cell within the table has the same size: 
  1. wx.GridSizer(int rows=1int cols=0int vgap=0int hgap=0)  
In the constructor we specify the number of rows and columns in the table and the vertical and horizontal space between our cells. In our example we create a skeleton of a calculator. 
calculator.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4.   
  5. """  
  6. ZetCode wxPython tutorial  
  7.   
  8. In this example we create a layout  
  9. of a calculator with wx.GridSizer.  
  10.   
  11. author: Jan Bodnar  
  12. website: www.zetcode.com  
  13. last modified: April 2018  
  14. """  
  15.   
  16. import wx  
  17.   
  18.   
  19. class Example(wx.Frame):  
  20.   
  21.     def __init__(self, parent, title):  
  22.         super(Example, self).__init__(parent, title=title)  
  23.   
  24.         self.InitUI()  
  25.         self.Centre()  
  26.   
  27.   
  28.     def InitUI(self):  
  29.   
  30.         menubar = wx.MenuBar()  
  31.         fileMenu = wx.Menu()  
  32.         menubar.Append(fileMenu, '&File')  
  33.         self.SetMenuBar(menubar)  
  34.   
  35.         vbox = wx.BoxSizer(wx.VERTICAL)  
  36.         self.display = wx.TextCtrl(self, style=wx.TE_RIGHT)  
  37.         vbox.Add(self.display, flag=wx.EXPAND|wx.TOP|wx.BOTTOM, border=4)  
  38.         gs = wx.GridSizer(5455)  
  39.   
  40.         gs.AddMany( [(wx.Button(self, label='Cls'), 0, wx.EXPAND),  
  41.             (wx.Button(self, label='Bck'), 0, wx.EXPAND),  
  42.             (wx.StaticText(self), wx.EXPAND),  
  43.             (wx.Button(self, label='Close'), 0, wx.EXPAND),  
  44.             (wx.Button(self, label='7'), 0, wx.EXPAND),  
  45.             (wx.Button(self, label='8'), 0, wx.EXPAND),  
  46.             (wx.Button(self, label='9'), 0, wx.EXPAND),  
  47.             (wx.Button(self, label='/'), 0, wx.EXPAND),  
  48.             (wx.Button(self, label='4'), 0, wx.EXPAND),  
  49.             (wx.Button(self, label='5'), 0, wx.EXPAND),  
  50.             (wx.Button(self, label='6'), 0, wx.EXPAND),  
  51.             (wx.Button(self, label='*'), 0, wx.EXPAND),  
  52.             (wx.Button(self, label='1'), 0, wx.EXPAND),  
  53.             (wx.Button(self, label='2'), 0, wx.EXPAND),  
  54.             (wx.Button(self, label='3'), 0, wx.EXPAND),  
  55.             (wx.Button(self, label='-'), 0, wx.EXPAND),  
  56.             (wx.Button(self, label='0'), 0, wx.EXPAND),  
  57.             (wx.Button(self, label='.'), 0, wx.EXPAND),  
  58.             (wx.Button(self, label='='), 0, wx.EXPAND),  
  59.             (wx.Button(self, label='+'), 0, wx.EXPAND) ])  
  60.   
  61.         vbox.Add(gs, proportion=1, flag=wx.EXPAND)  
  62.         self.SetSizer(vbox)  
  63.   
  64.   
  65. def main():  
  66.   
  67.     app = wx.App()  
  68.     ex = Example(None, title='Calculator')  
  69.     ex.Show()  
  70.     app.MainLoop()  
  71.   
  72.   
  73. if __name__ == '__main__':  
  74.     main()  
Notice how we managed to put a space between the Bck and the Close buttons. We simply put an empty wx.StaticText there. In our example we have used the AddMany() method. It is a convenience method for adding multiple widgets at one time. 

Widgets are placed inside the table in the order, they are added. The first row is filled first, then the second row etc: 

Figure: Calculator 

wx.FlexGridSizer 
This sizer is similar to wx.GridSizer. It does also lay out its widgets in a two dimensional table. It adds some flexibility to it. wx.GridSizer cells are of the same size. All cells in wx.FlexGridSizer have the same height in a row. All cells have the same width in a column. But all rows and columns are not necessarily the same height or width
  1. wx.FlexGridSizer(int rows=1int cols=0int vgap=0int hgap=0)  
rows and cols specify the number of rows and columns in a sizer. vgap and hgap add some space between widgets in both directions. 

Many times developers have to develop dialogs for data input and modification. I find wx.FlexGridSizer suitable for such a task. A developer can easily set up a dialog window with this sizer. It is also possible to accomplish this with wx.GridSizer, but it would not look nice, because of the constraint that each cell must have the same size. 
review.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4. """  
  5. ZetCode wxPython tutorial  
  6.   
  7. In this example we create review  
  8. layout with wx.FlexGridSizer.  
  9.   
  10. author: Jan Bodnar  
  11. website: www.zetcode.com  
  12. last modified: April 2018  
  13. """  
  14.   
  15. import wx  
  16.   
  17. class Example(wx.Frame):  
  18.   
  19.     def __init__(self, parent, title):  
  20.         super(Example, self).__init__(parent, title=title)  
  21.   
  22.         self.InitUI()  
  23.         self.Centre()  
  24.         self.Show()  
  25.   
  26.     def InitUI(self):  
  27.   
  28.         panel = wx.Panel(self)  
  29.   
  30.         hbox = wx.BoxSizer(wx.HORIZONTAL)  
  31.   
  32.         fgs = wx.FlexGridSizer(32925)  
  33.   
  34.         title = wx.StaticText(panel, label="Title")  
  35.         author = wx.StaticText(panel, label="Author")  
  36.         review = wx.StaticText(panel, label="Review")  
  37.   
  38.         tc1 = wx.TextCtrl(panel)  
  39.         tc2 = wx.TextCtrl(panel)  
  40.         tc3 = wx.TextCtrl(panel, style=wx.TE_MULTILINE)  
  41.   
  42.         fgs.AddMany([(title), (tc1, 1, wx.EXPAND), (author),  
  43.             (tc2, 1, wx.EXPAND), (review, 1, wx.EXPAND), (tc3, 1, wx.EXPAND)])  
  44.   
  45.         fgs.AddGrowableRow(21)    # Only cell(2, *) can grow in row direction  
  46.         fgs.AddGrowableCol(11)     # Only cell(*, 1) can grow in column direction      
  47.   
  48.         hbox.Add(fgs, proportion=1, flag=wx.ALL|wx.EXPAND, border=15)  
  49.         panel.SetSizer(hbox)  
  50.   
  51.   
  52. def main():  
  53.   
  54.     app = wx.App()  
  55.     ex = Example(None, title='Review')  
  56.     ex.Show()  
  57.     app.MainLoop()  
  58.   
  59.   
  60. if __name__ == '__main__':  
  61.     main()  
One code snippet is worthy of more description: 
  1. fgs.AddGrowableRow(21)  
  2. fgs.AddGrowableCol(11)  
We make the third row and second column growable. This way we let the text controls grow when the window is resized. The first two text controls will grow in horizontal direction, the third one will grow in both directions. We must not forget to make the widgets expandable with wx.EXPAND in order to make it work. 


wx.GridBagSizer 
wx.GridBagSizer is the most flexible sizer in wxPython. to use. This kind of sizer is not typical only for wxPython. We can find it in other toolkits as well. This sizer enables explicit positioning of items. Items can also optionally span more than one row or column. The wx.GridBagSizer has a simple constructor. 
  1. wx.GridBagSizer(integer vgap, integer hgap)  
The vertical and the horizontal gap defines the space in pixels used among all children. We add items to the grid with the Add() method. 
  1. Add(self, item, tuple pos, tuple span=wx.DefaultSpan, integer flag=0,   
  2.     integer border=0, userData=None)  
Item is a widget that you insert into the grid. The pos specifies the position in the virtual grid. The top-left cell has pos of (0, 0). The span is an optional spanning of the widget; e.g. a span of (3, 2) spans a widget across 3 rows and 2 columns. The flag and border were discussed earlier by wx.BoxSizer. The items in the grid can change their size or keep the default size, when the window is resized. If we want your items to grow and shrink, we can use the following two methods: 
AddGrowableRow(integer row)
AddGrowableCol(integer col)

Rename window example 
In our first example, we create a Rename window. It will have one wx.StaticText, one wx.TextCtrl and two wx.Button widgets. 
rename.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4. """  
  5. ZetCode wxPython tutorial  
  6.   
  7. In this example we create a rename layout  
  8. with wx.GridBagSizer.  
  9.   
  10. author: Jan Bodnar  
  11. website: www.zetcode.com  
  12. last modified: April 2018  
  13. """  
  14.   
  15. import wx  
  16.   
  17.   
  18. class Example(wx.Frame):  
  19.   
  20.     def __init__(self, parent, title):  
  21.         super(Example, self).__init__(parent, title=title)  
  22.   
  23.         self.InitUI()  
  24.         self.Centre()  
  25.   
  26.     def InitUI(self):  
  27.   
  28.         panel = wx.Panel(self)  
  29.         sizer = wx.GridBagSizer(44)  
  30.   
  31.         text = wx.StaticText(panel, label="Rename To")  
  32.         sizer.Add(text, pos=(00), flag=wx.TOP|wx.LEFT|wx.BOTTOM, border=5)  
  33.   
  34.         tc = wx.TextCtrl(panel)  
  35.         sizer.Add(tc, pos=(10), span=(15),  
  36.             flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=5)  
  37.   
  38.         buttonOk = wx.Button(panel, label="Ok", size=(9028))  
  39.         buttonClose = wx.Button(panel, label="Close", size=(9028))  
  40.         sizer.Add(buttonOk, pos=(33))  
  41.         sizer.Add(buttonClose, pos=(34), flag=wx.RIGHT|wx.BOTTOM, border=10)  
  42.   
  43.         sizer.AddGrowableCol(1)  
  44.         sizer.AddGrowableRow(2)  
  45.         panel.SetSizer(sizer)  
  46.   
  47.   
  48. def main():  
  49.   
  50.     app = wx.App()  
  51.     ex = Example(None, title='Rename')  
  52.     ex.Show()  
  53.     app.MainLoop()  
  54.   
  55.   
  56. if __name__ == '__main__':  
  57.     main()  

Figure: Rename window 

We must look at the window as a one big grid table. Firstly, the text "Rename to" goes to the left upper corner. So we specify the (0, 0) position. And we add some space to the bottom, left, and bottom. 
  1. text = wx.StaticText(panel, label="Rename To")  
  2. sizer.Add(text, pos=(00), flag=wx.TOP|wx.LEFT|wx.BOTTOM, border=10)  
The wx.TextCtrl goes to the beginning of the second row (1, 0). Remember, that we count from zero. It expands 1 row and 5 columns (1, 5). And we put 5 pixels of space to the left and to the right of the widget: 
  1. tc = wx.TextCtrl(panel)  
  2. sizer.Add(tc, pos=(10), span=(15),   
  3.     flag=wx.EXPAND|wx.LEFT|wx.RIGHT, border=5)  
We put two buttons into the fourth row. The third row is left empty, so that we have some space between the wx.TextCtrl and the buttons. We put the OK button into the fourth column and the Close button into the fifth one. Notice that once we apply some space to one widget, it is applied to the whole row. That's why we did not specify bottom space for the OK button. A careful reader might notice that we did not specify any space between the two buttons; that is, we did not put any space to the right of the OK button, or to the right of the Close button. In the constructor of the wx.GridBagSizer, we put some space between all widgets. So there is some space already. 
  1. sizer.Add(buttonOk, pos=(33))  
  2. sizer.Add(buttonClose, pos=(34), flag=wx.RIGHT|wx.BOTTOM, border=10)  
The last thing we must do is to make our dialog resizable. We make the second column and the third row growable. Now we can expand or shrink our window. Try to comment those two lines and see what happens. 
  1. sizer.AddGrowableCol(1)  
  2. sizer.AddGrowableRow(2)  
New class example 
In the next example is we create a window, which can be found in JDeveloper. It is a window for creating a new class in Java. 
new_class.py 
  1. #!/usr/bin/env python3  
  2. # -*- coding: utf-8 -*-  
  3.   
  4. """  
  5. ZetCode wxPython tutorial  
  6.   
  7. In this example we create a new class layout  
  8. with wx.GridBagSizer.  
  9.   
  10. author: Jan Bodnar  
  11. website: www.zetcode.com  
  12. last modified: April 2018  
  13. """  
  14.   
  15. import wx  
  16.   
  17. class Example(wx.Frame):  
  18.   
  19.     def __init__(self, parent, title):  
  20.         super(Example, self).__init__(parent, title=title)  
  21.   
  22.         self.InitUI()  
  23.         self.Centre()  
  24.   
  25.     def InitUI(self):  
  26.   
  27.         panel = wx.Panel(self)  
  28.   
  29.         sizer = wx.GridBagSizer(55)  
  30.   
  31.         text1 = wx.StaticText(panel, label="Java Class")  
  32.         sizer.Add(text1, pos=(00), flag=wx.TOP|wx.LEFT|wx.BOTTOM,  
  33.             border=15)  
  34.   
  35.         icon = wx.StaticBitmap(panel, bitmap=wx.Bitmap('exec.png'))  
  36.         sizer.Add(icon, pos=(04), flag=wx.TOP|wx.RIGHT|wx.ALIGN_RIGHT,  
  37.             border=5)  
  38.   
  39.         line = wx.StaticLine(panel)  
  40.         sizer.Add(line, pos=(10), span=(15),  
  41.             flag=wx.EXPAND|wx.BOTTOM, border=10)  
  42.   
  43.         text2 = wx.StaticText(panel, label="Name")  
  44.         sizer.Add(text2, pos=(20), flag=wx.LEFT, border=10)  
  45.   
  46.         tc1 = wx.TextCtrl(panel)  
  47.         sizer.Add(tc1, pos=(21), span=(13), flag=wx.TOP|wx.EXPAND)  
  48.   
  49.         text3 = wx.StaticText(panel, label="Package")  
  50.         sizer.Add(text3, pos=(30), flag=wx.LEFT|wx.TOP, border=10)  
  51.   
  52.         tc2 = wx.TextCtrl(panel)  
  53.         sizer.Add(tc2, pos=(31), span=(13), flag=wx.TOP|wx.EXPAND,  
  54.             border=5)  
  55.   
  56.         button1 = wx.Button(panel, label="Browse...")  
  57.         sizer.Add(button1, pos=(34), flag=wx.TOP|wx.RIGHT, border=5)  
  58.   
  59.         text4 = wx.StaticText(panel, label="Extends")  
  60.         sizer.Add(text4, pos=(40), flag=wx.TOP|wx.LEFT, border=10)  
  61.   
  62.         combo = wx.ComboBox(panel)  
  63.         sizer.Add(combo, pos=(41), span=(13),  
  64.             flag=wx.TOP|wx.EXPAND, border=5)  
  65.   
  66.         button2 = wx.Button(panel, label="Browse...")  
  67.         sizer.Add(button2, pos=(44), flag=wx.TOP|wx.RIGHT, border=5)  
  68.   
  69.         sb = wx.StaticBox(panel, label="Optional Attributes")  
  70.   
  71.         boxsizer = wx.StaticBoxSizer(sb, wx.VERTICAL)  
  72.         boxsizer.Add(wx.CheckBox(panel, label="Public"),  
  73.             flag=wx.LEFT|wx.TOP, border=5)  
  74.         boxsizer.Add(wx.CheckBox(panel, label="Generate Default Constructor"),  
  75.             flag=wx.LEFT, border=5)  
  76.         boxsizer.Add(wx.CheckBox(panel, label="Generate Main Method"),  
  77.             flag=wx.LEFT|wx.BOTTOM, border=5)  
  78.         sizer.Add(boxsizer, pos=(50), span=(15),  
  79.             flag=wx.EXPAND|wx.TOP|wx.LEFT|wx.RIGHT , border=10)  
  80.   
  81.         button3 = wx.Button(panel, label='Help')  
  82.         sizer.Add(button3, pos=(70), flag=wx.LEFT, border=10)  
  83.   
  84.         button4 = wx.Button(panel, label="Ok")  
  85.         sizer.Add(button4, pos=(73))  
  86.   
  87.         button5 = wx.Button(panel, label="Cancel")  
  88.         sizer.Add(button5, pos=(74), span=(11),  
  89.             flag=wx.BOTTOM|wx.RIGHT, border=10)  
  90.   
  91.         sizer.AddGrowableCol(2)  
  92.   
  93.         panel.SetSizer(sizer)  
  94.         sizer.Fit(self)  
  95.           
  96.   
  97. def main():  
  98.   
  99.     app = wx.App()  
  100.     ex = Example(None, title="Create Java Class")  
  101.     ex.Show()  
  102.     app.MainLoop()  
  103.   
  104.   
  105. if __name__ == '__main__':  
  106.     main()  
 
Figure: New class window 

This part of the wxPython tutorial was dedicated to layout management. 

Supplement 
Tutorialspoint - wxPython - GridBagSizer

[Git 文章收集] Differences between git merge and git rebase

Source From  Here Preface Merging and rebasing are the two most popular way to applying changes from one branch into another one. They bot...