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
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
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
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
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
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
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
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
- wxPython documentation about wx.Frame
- wxWidgets documentation about wxFrame
Pingback: Mike Driscoll: wxPython 101: Using Frame Styles | The Black Velvet Room
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.
It works fine for me on Windows 7. I’ve updated the article slightly to reflect your findings though and to state what I used for testing.
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* ?
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.
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.
> 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…
Technically, the Phoenix release of wxPython supports Python 3.x, however only the core widgets have been ported to Phoenix.
I’ve asked on #wxpython, but got no reply…any news about wxpython release based on Phoenix and supporting python-3.x?
Your solution doesn’t work on win 8.1. Metallicow’s one do 😉
Thanks. Currently I do not have a Windows XP or Windows 8 box to test with.
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?
wx.STAY_ON_TOP doesn’t seem to play well with wx.MessageDialog.
Yeah, that dialog uses whatever the operating system uses, so it’s native. That dialog may not support that flag on some systems. It’s up the OS to decide.
I have another question Mike, if you could answer.
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?
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.
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.
Well, according to the documentation, it should work on Windows. Yet it’s not for me. Any ideas?
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
Well, my app doesn’t have a visible main window. Is there anyway to make it stay on top of other programs tho?
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.
Pingback: wxPython 101: Simple Frames - The Mouse Vs. The Python