Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog RSS

Event-driven Programming

Basic approaches to handling user input:
Event-driven programming has become the standard in applications frameworks. In object-oriented languages it is implemented to some part through virtual functions and to another part through special functionality: Event listeners (Java), events and delegates (.NET), signals and slots (Qt). The idea of these special techniques is to allow calling one or several functions of some objects whenever a certain event occurs.

Why event-driven programming has become the standard for typical applications:

  • Your program requires processor time only when it needs to.
  • Most of the time programming is easier if you just have to handle events.
  • Demo: Second Life Scripting Language (LSL). Navigate to a sandbox. Create an object (right mouse click). Set it to "Physical" on the "Object" tab. Create a new script on the "Content" tab.

    Try llApplyImpulse(<0,0,5000>, FALSE); for the touch_start event of the default state.

    Append llSensorRepeat("", "", AGENT, 10.0, PI, 0.5); to the state_entry event of the default state. Add and fill a new event handler sensor (integer detected){...}.

    Create a new state: state blue with llSetColor(<0,0,1>, ALL_SIDES); in the state_entry event. Add llSetColor(<1,1,1>, ALL_SIDES); to the state_entry event of the default state. Use the commands state blue and state default to switch between the states on touch.

    Demo: Visually designing a graphical user interface with Microsoft Visual C# 2005. Designer-generated code. Events. Delegates. (Note: The all-new Microsoft Visual Studio 2007 uses an XML-based format called XAML to store the layout of forms. This is part of the new Windows Presentation Framework WPF that's contained in .NET 3.0.)

    Sometimes, however, event-driven programming can be a pain in the neck. Every routine that is invoked by some event has to return very quickly; otherwise, your program seems to hang. In particular, the routines invoked must not contain long or even infinite loops. For instance: If you want to capture strokes done with the mouse, you must store one mouse (x,y) position at a time, always returning immediately. In pseudocode this looks as follows:

    OnMouseDown

    Set MouseDown to true
    Create new stroke in memory
    Store first position in stroke

    OnMouseMove

    If MouseDown append position to stroke

    OnMouseUp

    Set MouseDown to false

    (Demo in C#)

    If you want something to happen at regular intervals, create a timer and handle the events that it fires.

    Painting with GDI+

    Virtually all current event-based systems trigger the repainting of the screen via a pseudo-event "Screen has to be repainted". The idea is to collect all drawing code at one place. (Avoid to spread functionality across your software!) If the runtime environment finds that it needs to redraw your graphical component, it will invoke this function. If you want to draw yourself, you will typically not invoke this function directly, but rather tell the runtime environment that your graphical component needs an update. Thus, the environment can organize the redrawing efficiently, in particular by collapsing several requests into one.

     
    Java 2D (Graphics API for Java Swing) GDI+ (Graphics API for .NET) Explanation
    repaint() Invalidate() member function of the widget to call for a display update
    protected void paintComponent(Graphics g)
    {
    super.paintComponent(g);
    //...
    }
    override void protected OnPaint(PaintEventArgs e)
    {
    base.OnPaint(e);
    //...
    }
    member function of the widget to override for your own drawing commands

    The .NET object e contains a reference e.Graphics to the graphics context. All popular windowing systems use such a graphics context to both store information about which part of the window has to be drawn etc. and as an object on which one invoke all kinds of drawing operations. For instance, we may write:
    using System.Drawing;
    // ...
    Pen p = new Pen(Color.Blue, 7);
    e.Graphics.DrawLine(p, 12, 34, 56, 78);
    You can consult the documentation or the automatic code completion for further drawing commands.

    Demo: Control the form of a painted shape by a UI element such as a slider. Nothing will appear on screen as long as we don't force a redraw either by manipulating the windows or by explicitly calling Invalidate(), e.g., on the change event of the slider. Note that if you hide and unhide a part of a window, only this part will be redrawn for reasons of efficiency.

    Demo: Create paint strokes with the mouse. Note that you have to store the strokes in order to reproduce them if the window has to be redrawn.

    As the program repaints the window's content, we perceive flickering: The window is cleared and then the drawing is completed. It is better (but more costly) to complete the drawing in an offscreen buffer (back buffer) and then to quickly copy the final image into the window (front buffer). This is called double buffering. It's enabled by setting the form's property of the same name. In Java 2D, double buffering is enabled by default.

    A transformation matrix Graphics.Transform controls the position, orientation, scaling, etc. of all (!) subsequent drawing commands. The effects of subsequent commands to change the matrix are cumulated to facilitate embedding graphics into graphics. (Again, this is similar in Java 2D.) The matrix can be changed through Graphics.RotateTransform(42) etc. The matrix cannot be changed through
    Graphics g = ...; g.Transform.Rotate(42);
    since a matrix is a C# struct, not a class; thus, the property g.Transform only returns a copy of the matrix.