3
votes

I've gone from one book to another, one google search to another and I notice EVERY SINGLE ONE starts the main window in a completely different way.

I don't want to pick up bad habits so can someone please give me the best of these options and why its the better method. Below are all the ways i've seen it done

A)
class iFrame(wx.Frame): def init(....): wx.Frame._init_(...)

B)
class iFrame(wx.Frame): def init(...): super_init_(...)

C)
Then I see some that uses the Panel instead such as
class iPanel(wx.Panel) def init(...): wx.Panel.init(...)

D)
And even more confusing some are using the regular App class of wx
class iApp(wx.App): def OnInit(self): wx.Frame.init(...)

Forgive me if some of my structures are wrong but I'm recalling these off the top of my head, Question again...Which one of these, IF ANY is the best way to structure the GUI. It's hard following tutorials and books when they all do things in diff ways

edit: Sorry if format is not correct, but normally it works...

4

4 Answers

2
votes

My favorite way to start wx application development is:

import wx

class MainWindow(wx.Frame):
    def __init__(self, *args, **kwargs):
        wx.Frame.__init__(self, *args, **kwargs)

        self.panel = wx.Panel(self)
        self.button = wx.Button(self.panel, label="Test")

        self.sizer = wx.BoxSizer()
        self.sizer.Add(self.button)

        self.panel.SetSizerAndFit(self.sizer)  
        self.Show()

app = wx.App(False)
win = MainWindow(None)
app.MainLoop()

See also this question, which is related.

3
votes

Don't worry about it. You aren't going to ruin your future programming by making the wrong choice now.

None of the options you mention are wrong. They all do things differently because different applications have different requirements. No one way is best.

Just work on what you want and do what works for you, and once you have greater familiarity then you'll understand why different code does it differently.

2
votes

I have learned the hard way that, as in every application, encapsulation is important. And peculiar to wxPython, the main frame object should have precisely one panel widget, plus optional menu bar, toolbar and status bar widgets. Nothing else.

This is my basic pattern for new wxPython applications:

(Updated 2019 Feb 07: Wx Phoenix and Python 3)

import wx


class MainFrame(wx.Frame):
    """Create MainFrame class."""
    def __init__(self, *args, **kwargs):
        super(MainFrame, self).__init__(None, *args, **kwargs)
        self.Title = 'Basic wxPython module'
        self.SetMenuBar(MenuBar(self))
        self.ToolBar = MainToolbar(self)
        self.status_bar = StatusBar(self).status_bar
        self.Bind(wx.EVT_CLOSE, self.on_quit_click)
        panel = MainPanel(self)
        sizer = wx.BoxSizer()
        sizer.Add(panel)
        self.SetSizerAndFit(sizer)
        self.Centre()
        self.Show()

    def on_quit_click(self, event):
        """Handle close event."""
        del event
        wx.CallAfter(self.Destroy)


class MainPanel(wx.Panel):
    """Panel class to contain frame widgets."""
    def __init__(self, parent, *args, **kwargs):
        super(MainPanel, self).__init__(parent, *args, **kwargs)

        """Create and populate main sizer."""
        sizer = wx.BoxSizer(wx.VERTICAL)
        cmd_quit = wx.Button(self, id=wx.ID_EXIT)
        cmd_quit.Bind(wx.EVT_BUTTON, parent.on_quit_click)
        sizer.Add(cmd_quit)
        self.SetSizer(sizer)


class MenuBar(wx.MenuBar):
    """Create the menu bar."""
    def __init__(self, parent, *args, **kwargs):
        super(MenuBar, self).__init__(*args, **kwargs)
        # File menu
        file_menu = wx.Menu()
        self.Append(file_menu, '&File')

        quit_menu_item = wx.MenuItem(file_menu, wx.ID_EXIT)
        parent.Bind(wx.EVT_MENU, parent.on_quit_click, id=wx.ID_EXIT)

        file_menu.Append(quit_menu_item)


class MainToolbar(wx.ToolBar):
    """Create tool bar."""
    def __init__(self, parent, *args, **kwargs):
        super(MainToolbar, self).__init__(parent, *args, **kwargs)

        #quit_bmp =  wx.ArtProvider.GetBitmap(wx.ART_QUIT)
        #self.AddTool(wx.ID_EXIT, 'Quit', wx.Bitmap(quit_bmp))
        #self.SetToolShortHelp(wx.ID_EXIT, 'Quit')
        #self.Bind(wx.EVT_TOOL, parent.on_quit_click, id=wx.ID_EXIT)
        #self.Realize()


class StatusBar(object):
    def __init__(self, parent):
        """Create status bar."""
        self.status_bar = parent.CreateStatusBar()


if __name__ == '__main__':
    """Run the application."""
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()
0
votes

In response to a comment by XilyummY, I have added this additional answer to show how the main classes can be organised in separate files.

This is my solution based on four files:

  1. main.py: the main frame for the application and the application loader;
  2. main_panel.py: the main panel for the application;
  3. menu_bar.py: the menu bar definition for the frame;
  4. tool_bar.py: the tool bar from the frame.

The code follows in this order:

main.py

import wx

from main_panel import MainPanel
from menu_bar import MenuBar
from tool_bar import MainToolbar


class MainFrame(wx.Frame):
    """Create MainFrame class."""
    def __init__(self, *args, **kwargs):
        super(MainFrame, self).__init__(None, *args, **kwargs)
        self.Title = 'Basic wxPython module'
        self.SetMenuBar(MenuBar(self))
        self.ToolBar = MainToolbar(self)
        self.status_bar = StatusBar(self).status_bar
        self.Bind(wx.EVT_CLOSE, self.on_quit_click)
        panel = MainPanel(self)
        sizer = wx.BoxSizer()
        sizer.Add(panel)
        self.SetSizerAndFit(sizer)
        self.Centre()
        self.Show()

    def on_quit_click(self, event):
        """Handle close event."""
        del event
        wx.CallAfter(self.Destroy)


class StatusBar(object):
    def __init__(self, parent):
        """Create status bar."""
        self.status_bar = parent.CreateStatusBar()


if __name__ == '__main__':
    """Run the application."""
    screen_app = wx.App()
    main_frame = MainFrame()
    screen_app.MainLoop()

main_panel.py

import wx


class MainPanel(wx.Panel):
    """Panel class to contain frame widgets."""
    def __init__(self, parent, *args, **kwargs):
        super(MainPanel, self).__init__(parent, *args, **kwargs)

        """Create and populate main sizer."""
        sizer = wx.BoxSizer(wx.VERTICAL)
        cmd_quit = wx.Button(self, id=wx.ID_EXIT)
        cmd_quit.Bind(wx.EVT_BUTTON, parent.on_quit_click)
        sizer.Add(cmd_quit)
        self.SetSizer(sizer)

menu_bar.py

import wx


class MenuBar(wx.MenuBar):
    """Create the menu bar."""
    def __init__(self, parent, *args, **kwargs):
        super(MenuBar, self).__init__(*args, **kwargs)
        # File menu
        file_menu = wx.Menu()
        self.Append(file_menu, '&File')

        quit_menu_item = wx.MenuItem(file_menu, wx.ID_EXIT)
        parent.Bind(wx.EVT_MENU, parent.on_quit_click, id=wx.ID_EXIT)

        file_menu.Append(quit_menu_item)

tool_bar.py

import wx


class MainToolbar(wx.ToolBar):
    """Create tool bar."""
    def __init__(self, parent, *args, **kwargs):
        super(MainToolbar, self).__init__(parent, *args, **kwargs)

        new_bmp =  wx.ArtProvider.GetBitmap(wx.ART_NEW)
        #preferences_bmp = wx.Bitmap('images/preferences.png')
        quit_bmp =  wx.ArtProvider.GetBitmap(wx.ART_QUIT)

        self.AddTool(wx.ID_NEW, 'New', new_bmp)
        #self.AddTool(wx.ID_PREFERENCES, 'Preferences', preferences_bmp)
        self.AddTool(wx.ID_EXIT, 'Quit', quit_bmp)

        self.SetToolShortHelp(wx.ID_NEW, 'New ...')
        self.SetToolShortHelp(wx.ID_PREFERENCES, 'Preferences ...')
        self.SetToolShortHelp(wx.ID_EXIT, 'Quit')

        self.Bind(wx.EVT_TOOL, parent.on_quit_click, id=wx.ID_EXIT)

        self.Realize()