User:Boldingd/Sandbox/GuiProgramming/Expanding on the Event Loop

From Wikibooks, open books for an open world
Jump to navigation Jump to search

Expanding on the Event Loop[edit | edit source]

In the first section, we covered the basic concepts of an event loop: we have an environment, into which we place entities; an 'event loop' will monitor the state of the environment and notify the entities of changes, which we view as events. We can see how this process describes how our widgets work, but there is one significant thing that widgets do that is not captured in this process: widgets can draw themselves.

Last chapter, we mentioned that 'progress bars' can be placed in 'indeterminate mode', in which they will run an animation; we asserted that this indicates to the user that the application has not terminated; we did not discuss why this is the case.

In this chapter, we will modify the event loop that we developed previously to include the entities 'updating' their representation, from which we will develop the idea of the widgets 'drawing'.

The Event Loop[edit | edit source]

Recall the event loop from chapter one. As an abstract:

  • Set up entities
  • Event Loop:
    • Detect changes
    • Generate events

This allows us to detect and respond to changes in the environment; if this loop runs quickly enough that the delay in responding to a change is imperceptible to a human user, we say that it runs in 'real time'.

Consider what form our responses take; in our simple example, we were only concerned with printing a message or calling some function in response to an event. But what if we want to change the properties of the entities themselves? In the particular case of widgets, what if we want to change their graphical representation - like when a button renders itself differently while it is being pressed?

Drawing[edit | edit source]

Let us add to the entities in our simple event loop a step in which the entities represent themselves to the environment - in the specific case of widgets, a step in which they 'draw' themselves. We will place it after the event-processing step, so that changes caused by the events will be reflected when the widgets redraw themselves. We then have the resulting loop:

  • Set up entities
  • Event Loop:
    • Detect changes
    • Generate events
    • Update representation (Draw)

Consider the placement of the represent/draw step; it is a distinct step, after events are generated (and handled). The reader might wonder why we do not redraw the widgets 'during' the event loop, perhaps when they receive events; it might reasonably seem that, if widgets were redrawn when and only when they received events, that this might save us having to redraw widgets that have not changed. There are several problems with this: on is that our widgets could potentially receive more than one event in a single pass of the event loop. This could result in our widgets needlessly re-drawing themselves several times. This problem is gets worse if a change in a widget's state (including its properties) caused it to change size, which might generate more events and cause an explosive growth of needles widget re-draws. Worse, in extreme cases, this might even cause recurrent event generation.

The solution is to mark the widgets when their properties are changed by an event, and only re-draw the widgets so marked (or 'damaged') in the drawing step. This allows us to only draw widgets that have changed, while not redrawing the same widget multiple times per pass.

Animations and the Indeterminate Progress Bar[edit | edit source]

Consider a widget that is displaying an 'animation' of some type, like the pulsing animation of the indeterminate progress-bar. The widget might do this by correlating each frame to a certain 'time', and then marking itself as 'damaged' in its own draw function. When its draw function is called, it checks the time; if the time for its next frame has elapsed, it redraws itself. Whether the time has elapsed or not, it marks itself as damaged, so that it will check as often as the event loop runs.

This scheme will allow the widget to show its animation, but it is inelegant; it requires the event loop to constantly poll our widget. What if we added a 'timer event' to our kit? Suppose that we attach a timer event to some object, and allow the object to set a time for the event-loop to trigger the timer event. Then the event loop could keep track of the progress of time for us.

In either case, the event loop must keep running for our widget to redraw itself: if the event loop stops, the animation stops. This is how the indeterminate progress bar tells the user that our application is still running - or, at the very least, that the event loop is still running.

Layouts and the Expanded Event Loop[edit | edit source]

As a final observation, consider what happens if an event results in a change in the physical configuration; then our layout needs to be re-computed. We can insert a 'perform layouts' step between the event-processing and drawing steps; we will put it after events have been processed for much the same reason that we placed the draw step after all events have been processed; before the draw step, so that the widgets will draw themselves with the appropriate size and positioning.

The resulting application process, with the event loop embedded with in, is:

  • Set up entities
  • Event Loop:
    • Detect changes
    • Generate events
      • Mark changed widgets
    • Update layout (of damaged widgets)
    • Draw (damaged widgets)

Layout and Draw as events[edit | edit source]

The student might wonder what the layout and drawing machinery looks like. If an entity is a class - like our AbstractWidget class - then that class might include 'layout' and 'draw' functions. The AbstractWidget might include useful default implementation of these functions (most will), so that AbstractWidget can lay their children out and draw themselves without requiring us to add any code. However, we may also be able to 'override' these functions, to provide our own drawing methods and our own sizing logic.

The student might wonder if 'layout' and 'draw' are (or can be viewed as) events; they are steps in the event loop, after all. This depends on the kit: in some kits, 'layouts' and 'draw' are event, while in others they are not; they are simply special functions, as described above.