A GUI library for pygame

User Guide - Elements

What is a ThorPy element

Element is the main concept of ThorPy. There are two types of elements : non-graphical elements and graphical elements. Non-graphical elements are represented by only one class : thorpy.Ghost (base class for elements). In the other hand, there is plenty of graphicals elements such as, for example thorpy.Element (base class for graphical elements), thorpy.Slider, and so on.

An important point is that any element has:

  • a list of children elements (it may be empty)
  • a list of reactions to pygame events
  • a 'ghost rect', which is a delimiting zone defined by a pygame Rect instance. The ghost rect, as the name says, is not visible ; its purpose is to define an area of the screen that can be used by some reactions related to the element.

Creating an element

There are many different elements that are summarized in the cheat sheet table ; since they differ all a little bit from each other, the all have different parameters that can be passed during creation. The best way to discover how they can be created is to see the overview example and the different tutorials. Moreover, a short declaration example is also given in the table.


A tree hierarchy naturally arises from the fact that an element can be the the 'father' of other elements. However, a given element has only one father at a given time, though its father can change during execution.

The minimal code for instanciating a non-graphical element is my_element = thorpy.Ghost(). You can pass a list of elements to the constructor so that the created ghost is the father of the elements in the list (by default, it has no children): my_element = thorpy.Ghost(elements=a_list_of_elements). The father of the concerned children is then set to be the element you just created. It is also possible to change and acess the children at any time with the following methods:

  • Add elements: my_element.add_elements(list_of_elements)
  • Remove elements: my_element.remove_elements(list_of_elements)
  • Get elements: my_element.get_elements()
Note also that you can get all the descendants with my_element.get_descendants() and all the ancesters with my_element.get_descendants().


You can modify the location of any element with the following methods:

  • Move: my_element.move(shift), with a 2-tuple shift argument that indicates the movement in pixels.
  • Set topleft: my_element.set_topleft(topleft), with a 2-tuple topleft argument that indicates the new topleft coordinate in pixels. If you set None as a component of the tuple, the location on the correspond axis won't be changed.
  • Set center: my_element.set_center(center), with a 2-tuple topleft argument that indicates the new center coordinate in pixels. If you set None as a component of the tuple, the location on the correspond axis won't be changed.
More methods permit to have a fine and easy controle on element's location. You can discover them through the examples and the tutorials.


In pygame you can blit and update surfaces ; blitting a surface on another changes the target surface, but an update need to be performed in order to make the change appearing to the user. ThorPy is working the same way, plus the fact that it handles elements unblitting too. Any element can be blitted, unblitted and updated on the screen. Non-graphical elements only blit, unblit or update their children (again, the process is done along the tree defined by the elements hierarchy). These three fundamental operations are done by calling:

  • Blit: my_element.blit()
  • Unblit: my_element.unblit()
  • Update: my_element.update()

Graphical elements

Although you may use non-graphical elements for multiple reasons, it is likely that the most common elements you instanciate will be graphical elements. As said below, only graphical elements blit themselves on the screen, while ghost elements blit their children. In what follows, we will use the word 'element' to denote graphical element.

Instanciating elements

The difference between an element and a non-graphical element is that the former has a pygame surface, that is ready at anytime for blitting. However, this surface is not produced right at the element's declaration - the surface is built only at the my_element.finish() call, for performance reasons. Indeed, imagine you need to produce a large amount of elements, each one needing a special graphical treatment: you will instanciate the elements, then tell them how their surface must look like, and then finally build the surface only when all its determining parameters are set. If not, you would produce twice the surfaces of each element ; and if some children also have a special graphical treatment, they would be produced four times, and so on. This could result in dramatical performances since the surface building can often be a bottlneck. For this reason a graphical element is created in two steps:

Always call finish method of elements instanciated from a constructor.
A graphical element is created in two steps for performance reasons:
  1. Declaration: my_element = thorpy.MyElementClass(...)
  2. Finish: my_element.finish()
Eventually, you would precise some graphical parameters between the two steps. It is important to finish the elements you create as soon as possible, since any method of the element that needs one of its graphical components will fail if the element is not finished! However, you can modify how your elements look like at anytime before or after the finish call, though not the same way.

Note that ThorPy provides functions that returns ready-made elements, such as thorpy.make_button(...) or thorpy.make_text(...) ; if you get elements this way, you do not explicitely instanciate any element from a constructor, and so the above rule does not apply and you do not have to call the finish method.

Setting graphical properties

For advanced graphical operations, please see the documentation and the tutorial on advanced graphics. Advanced graphical operations are ofthen done between the constructor and the finish call.

ThorPy provides several built-in methods for setting graphical properties of elements. Here is a few of them:

  • Scale element to its text content: my_element.scale_to_title(). Elements have a fixed default size that depends on their type. It is up to the user to indicates if the element has to change its size.
  • Set font color: my_element.set_font_color(color), with the color argument as a tuple.
  • Set font size: my_element.set_font_size(size).
  • Set image: my_element.set_image(surface), with a pygame surface as surface argument. Note that this do not adapt the size of the element if the new image is not of the same size as the previous one.
  • Set main color: my_element.set_main_color(color), with the color argument as a tuple. This ask the element's painter for producing a new image with the specified color argument.
  • Set size: my_element.set_size(size), with a 2-tuple as size argument.
  • Set text: my_element.set_text(text).

Size and Rects

For producing its image, an element calls its Painter and its Title, which are then combined by its Fusionner. Thus, an element possess a fus_rect in addition to its ghost_rect and storer_rect inherited from the non-graphical elements. Here is a summary of what all these rects correspond to.

  • Ghost rect: obtained via my_element.get_ghost_rect(). It is used by some reactions, for example to determine when an element is hovered by mouse.
  • Storer rect: obtained via my_element.get_storer_rect(). This is the 'domain' needed by the element when it is stored next to other elements. This rect is asked by the storers objects.
  • Fusionner rect: obtained via my_element.get_fus_rect(). This is the actual size of the element that you see on the screen. For this reason, this is also what you get by simply calling my_element.get_rect(). Note that for non-graphical elements, this returns the ghost rect.
If not specified, most of the elements will have by default the three rects initialized to the same size and at the same location.