wxPython 101: Using Frame Styles

The wxPython Frame widget is used in almost all wxPython applications. It has the minimize, maximize and close buttons on it as well as the caption along the top that identifies the application. The wx.Frame allows you to modify its styles in such a way that you can remove or disable various buttons and features. In this article, we will look at some of the ways that you can change the behavior of the wx.Frame widget. Specifically, we will cover the following:

  • Different ways to create a default frame
  • How to create a frame without a caption (i.e. no title bar)
  • How to create a frame with a disabled close button
  • How to create a frame without a maximize or minimize button
  • How to create a frame that cannot be resized
  • How to create a frame without the system menu
  • How to make your frame stay on top of other windows

Getting Started

default_frame

It's always a good idea to look at how the default style works and then modify that to see what happens. So let's start with the frame's default style: wx.DEFAULT_FRAME_STYLE. You can create a frame that uses wx.DEFAULT_FRAME_STYLE (or its equivalent) in 3 different ways. The first an easiest is to just do something like this:

import wx

########################################################################
class DefaultFrame(wx.Frame):
    """
    The default frame
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Default Frame")
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = DefaultFrame()
    app.MainLoop()

This will create a normal frame with all the normal functionality any user would expect. Now let's change it slightly by passing it the wx.DEFAULT_FRAME_STYLE.

import wx 

########################################################################
class DefaultFrame(wx.Frame):
    """
    The default frame
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title="Default Frame", style=wx.DEFAULT_FRAME_STYLE)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = DefaultFrame()
    app.MainLoop()

This code does EXACTLY the same thing as the previous code. Now if you do a little research, you'll find out that wx.DEFAULT_FRAME_STYLE is the equivalent of passing the following:

wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN

So let's modify out code one more time to show how that would work.

import wx

########################################################################
class DefaultFrame(wx.Frame):
    """
    The default frame
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        default = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN
        wx.Frame.__init__(self, None, title="Default Frame", style=default)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = DefaultFrame()
    app.MainLoop()

That was easy. Now we're ready to start experimenting!

Create a Frame Without a Caption

no_caption_frame

Let's create a frame that doesn't have a caption. The caption is what holds the buttons along the top of the frame along with the title of the application.

import wx

########################################################################
class NoCaptionFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        no_caption = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CLOSE_BOX | wx.CLIP_CHILDREN
        wx.Frame.__init__(self, None, title="No Caption", style=no_caption)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = NoCaptionFrame()
    app.MainLoop()

When this code is run, the panel is squashed up in the upper left hand corner of the frame. You can resize the frame and the panel will "snap" into place, but it's kind of weird looking. You might also note that you cannot close this application since there is no close button on it. You will need to kill your Python process to close this application.

Create a Frame With a Disabled Close Button

no_close_frame

Some programmers think they need a frame where there's no close button. Well you can't really remove the close button and keep the other buttons at the same time, but you can disable the close button. Here's how:

import wx

########################################################################
class NoCloseFrame(wx.Frame):
    """
    This frame has no close box and the close menu is disabled
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        no_close = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLIP_CHILDREN
        wx.Frame.__init__(self, None, title="No Close", style=no_close)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = NoCloseFrame()
    app.MainLoop()

Of course, you cannot close this application either, so this is a rather annoying piece application. You'll probably want to add a wx.Button that can close it instead.

Create a Frame Without Maximize/Minimize

no_max_min_frame

Sometimes you'll want to create an application that you cannot minimize or maximize. If you're going to go that far, let's make an application that also doesn't show up in the taskbar!

import wx

########################################################################
class NoMaxMinFrame(wx.Frame):
    """
    This frame does not have maximize or minimize buttons
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        no_caption = wx.RESIZE_BORDER | wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.CLIP_CHILDREN | wx.FRAME_NO_TASKBAR
        wx.Frame.__init__(self, None, title="No Max/Min", style=no_caption)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = NoMaxMinFrame()
    app.MainLoop()

As you can see, we just removed the wx.MINIMIZE_BOX and wx.MAXIMIZE_BOX style flags and added the wx.FRAME_NO_TASKBAR style flag.

Create a Un-Resizable Frame

no_resize_frame

Occasionally you'll want to create a frame that cannot be resized. You could use SetSizeHints or you could just set some frame style flags. We'll be doing the latter here:

import wx

########################################################################
class NoResizeFrame(wx.Frame):
    """
    This frame cannot be resized. It can only be minimized, maximized
    and closed
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        no_resize = wx.DEFAULT_FRAME_STYLE & ~ (wx.RESIZE_BORDER | 
                                                wx.RESIZE_BOX | 
                                                wx.MAXIMIZE_BOX)
        wx.Frame.__init__(self, None, title="No Resize", style=no_resize)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = NoResizeFrame()
    app.MainLoop()

Note that here we use bitwise operators to remove 3 style flags from the wx.DEFAULT_FRAME_STYLE. As you can see, this gives us a frame that we cannot resize in any way.

Create a Frame Without a System Menu

no_sys_menu_frame

This is a rather silly requirement, but I've seen people ask for it. Basically, they want to remove ALL the buttons, but leave the title. Here's how to do that:

import wx

########################################################################
class NoSystemMenuFrame(wx.Frame):
    """
    There is no system menu, which means the title bar is there, but
    no buttons and no menu when clicking the top left hand corner
    of the frame
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        no_sys_menu = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.CAPTION | wx.CLIP_CHILDREN | wx.CLOSE_BOX
        wx.Frame.__init__(self, None, title="No System Menu", style=no_sys_menu)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = NoSystemMenuFrame()
    app.MainLoop()

As you can see, there is a title and you can resize the frame, but you cannot maximize, minimize or close the application.

Update: I've had a report that this one doesn't work on Windows XP or Windows 8.1. While I don't particularly care much about that OS at this point, the solution provided was to pass the following style instead of the one above:

no_sys_menu=wx.CAPTION

Create a Frame That Stays on Top

stay_on_top_frame

A lot of programmers ask about this one. They want their application to stay on top of all the others. While there isn't a completely foolproof way to accomplish this, the little recipe below will work most of the time.

import wx

########################################################################
class StayOnTopFrame(wx.Frame):
    """
    A frame that stays on top of all the others
    """

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        on_top = wx.DEFAULT_FRAME_STYLE | wx.STAY_ON_TOP
        wx.Frame.__init__(self, None, title="Stay on top", style=on_top)
        panel = wx.Panel(self)
        self.Show()

#----------------------------------------------------------------------
if __name__ == "__main__":
    app = wx.App(False)
    frame = StayOnTopFrame()
    app.MainLoop()

Here we just use the default style flag and add on wx.STAY_ON_TOP.

Wrapping Up

At this point, you should know how to edit almost all the frame's styles. There are a couple of other style flags that are OS dependent (like wx.ICONIZE) or just aren't that useful. If you're interested in those, check out the links below. Otherwise, go forth and use your knowledge wisely.

Note: This code was tested on Windows 7 using Python 2.6.6 with wxPython 2.8.12.1

Related Links

Copyright © 2024 Mouse Vs Python | Powered by Pythonlibrary