Designing a Button UI Module for Pygame

Pygame is a 2D graphics and gaming library for Python. It’s pretty nifty because it essentially gives you a blank window that you can draw any shapes or lines or images you want on it. But it doesn’t come with any UI elements like buttons, scrollbars, or check boxes. This post will go through not only creating a button class for Pygame, but also the reasoning behind why I’ve set up the code as it is. This is more of a “how to create a module other people can use” tutorial than a UI or Pygame tutorial.

This tutorial assumes you know the basics of Pygame and Python programming. If you don’t, it’s probably easy enough to follow anyway.

A button is a common user interface (UI) control that is used in many software applications. It seems simple enough: there’s a button on the window and you click on it and something happens. But there’s a lot of details we should plan out ahead of time. Remember, we want to make a generic button class so that other programmers can use this in their games and programs. Once you’ve read through the process here, you’ll be familiar with how to make your own modules for UI elements.

Designing a UI button class is good a good programming practice exercise.

Download the PygButton module here. You can also look at just the pygbutton.py file itself.

The Feature List (and the Non-Feature List)

First, let’s create a list of design details for the buttons:

  1. Can have any width or height.
  2. The buttons can have text on them. The font and size can be customized.
  3. The background color of the button can be changed to any RGB value, as can the foreground (text) color.
  4. The button’s properties (bgcolor, bgcolor, text, font, size, etc.) can be dynamically changed.
  5. The button has three states: normal, down (when the mouse cursor has pressed down on the button), and highlight (when the mouse cursor is over the button but not pressing down).
  6. Pygame’s mouse events are passed to the button’s handleEvent() method, which update’s the button’s state and calls any event-handling code.
  7. The button recognizes 6 different types of events: mouse enter, mouse exit, mouse down, mouse up, mouse click, and mouse move. (These are explained later.)
  8. Instead of text, the user will be able to specify images for the three different states. We’ll call these image-based buttons.
  9. The button’s visibility can be toggled on and off.

And it’s always a good idea to come up with a list of things we specifically won’t implement (to avoid feature creep each time we think, “Hey, it’d be cool if we could…”). These features could always be implemented later.

  1. Must be rectangular (i.e. can’t be oval).
  2. No transparency.
  3. No more than the three states.
  4. No hotkeys attached to them, or keyboard focus.
  5. No special “double click” event (it’ll just be two click events).
  6. For now, the highlight state looks identical to the normal state for text-based buttons.
  7. A button is either text-based or image-based, there’s no hybrid.
  8. No “disabled” state.
  9. Only one font & color at a time for text-based buttons.
  10. The text caption will always be centered, not left- or right-aligned.

(But you can add these features to your own code if you want.)

Design Details

Whenever you’re designing something, always do a prior art search first. Looking at how buttons on a web page work is a good case to examine, for example.

The buttons have three states and can have a different appearance for each state.

  • The “normal” state is what the button looks like when it has not been clicked and the mouse is not over it.
  • The “highlight” state is what the button looks like when the mouse is hovering over it, but not clicking it. We can use this to add some kind of highlighting behavior when the mouse glides over the button. For normal text-based buttons, this state will look identical to the normal state.
  • The “down” state is what the button looks like when it is being clicked down.

There are also six different “button events” that the buttons can produce based on the Pygame mouse events that are passed to them:

Page 1 of 6 | Next page