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

23 thoughts on “wxPython 101: Using Frame Styles”

  1. Pingback: Mike Driscoll: wxPython 101: Using Frame Styles | The Black Velvet Room

  2. Your Create a Frame Without a System Menu Example is wrong.
    no_sys_menu = wx.MINIMIZE_BOX | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER | wx.CAPTION | wx.CLIP_CHILDREN | wx.CLOSE_BOX
    It doesn’t work like you wrote it on WinXPSP3

    It should be just style=wx.CAPTION.

    That will create a frame with no system menu, no buttons, and just a caption.

  3. Hiya,

    I see that you’re again covering wxPython although you did explore PyQt/PySide somewhat.

    wx3 is finally released, but I see there is still no wxPython-Phoenix release and considering I’m fine with GPL, would you still recommend wxPython over PyQt(5) for starting multi-platform GUI app *today* ?

  4. I plan to continue covering both of them. As for your question, that depends on what you need. If you want something that will look and behave like a native application, I think wxPython is still the best option. However, their release cycle is painfully slow.

    If you need the ability to theme your app, then PySide/PyQT, Tkinter, or Kivy might be more to your liking. PySide/Qt have a nice WYSIWYG editor. wxPython still has one of the best Python communities.

  5. Well, wxPython has a pretty small community of developers. PySide/Qt certainly has more. PySide seems a bit unstable as they don’t seem to know when or if they are going to support Qt5 whereas PyQt is already there. It’s kind of confusing what to go with these days.

  6. > PySide seems a bit unstable as they don’t seem to
    know when or if they are going to support Qt5 whereas PyQt is already
    there.

    If I decide for Qt, then I’ll go with PyQt which is nicely supported, including Python-3 support, but possible problem is lack of Qt5 port for *BSD

    Otoh, I like wx(Python), but a bit worried with lack of Python3 support.

    > It’s kind of confusing what to go with these days.

    Yeah, I agree…

  7. I’ve asked on #wxpython, but got no reply…any news about wxpython release based on Phoenix and supporting python-3.x?

  8. Hi Mike
    Thanks for your article.
    On Linux (KDE) your code for removing CLOSE is working fine.
    However, nothing I have tried seems to remove (disable) the minimize/maximize icons – including your code snippets above.
    Any idea?

  9. Basically, I have already tried Tkinter and wxPython and I even tried threading them both, but I can’t seem to create message boxes simultaneously. Is that possible at all?

  10. I have an event driven program that prompts users with a message box, but I can’t seem to display them simultaneously when multiple events coincide. One has to first close, and then the other will open.

  11. The message box in wxPython (if shown modally) will block until it’s dismissed, so I don’t think you can show more than one at a time. This is also most likely an operating system thing as it’s using the native message box widget, which may be limited to only one widget shown at a time.

    You should just create your own dialog. I think there’s a generic message dialog that might work for you.

  12. Well, according to the documentation, it should work on Windows. Yet it’s not for me. Any ideas?

  13. I tried your StackOverflow example out on Linux and Windows 7 and it worked on both. Of course, it will only stay on top of your app’s main window, but not necessarily other programs

  14. Well, my app doesn’t have a visible main window. Is there anyway to make it stay on top of other programs tho?

  15. My understanding is that it depends on the OS. You should ask on the wxPython Google group. There are a couple of Windows guys on there who might know more.

  16. Pingback: wxPython 101: Simple Frames - The Mouse Vs. The Python

Comments are closed.