TouchUI - Controls (part 8)

by Chris 28. November 2009 14:02

As I showed in a previous part of this series, I don't use any controls for the simpler dialog painting (i.e. for heading, line, etc). For more advanced painting and logic, the notion of controls is welcome, and is obviously a part of the TouchUI framework.

I started off in the traditional way, building WinForm controls, but soon realized that I really don't like all the overhead that comes with that. Also, I wanted the central control that is not natural when each control receive their own (mouse) events. So I ended up creating something new from scratch, and the root TouchUI control ended up being defined like this:

public class Control
{
   
public Rectangle Rectangle { get; set; }
   
public int ScreenFactor { get; set; }
   
public Color BackColor { get; set; }

    public virtual void Paint(Graphics g) { }
   
public virtual void MouseDown(Point p) { }
   
public virtual void MouseMove(Point p) { }
   
public virtual void MouseUp(Point p) { }
   
public virtual void Resize(Rectangle r) { }
   
public virtual void KeyDown(KeyEventArgs e) { }
   
public virtual void KeyUp(KeyEventArgs e) { }
}

Note that a rectangle is used for placement, and the important screen factor to handle painting on high-res devices. Also note how each event is actually a plain method reversing the "event bubbling" to push the "events" down the control hierarchy.

The pain is that each level explicitly need to forward the calls, but the gain is that none of the controls need to be aware of any events happening in the system. The end result is a few more calls and a minimum of overhead.

Currently rated 4.3 by 3 people

  • Currently 4.333333/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Chris | Compact Framework | Windows Mobile | User Interface

TouchUI - Active UI (part 7)

by Chris 21. November 2009 14:01

When creating a highly active user interface, there is a main difference with a traditional WinForms app, and it is the frequency that the screen is updates. In a WinForms app, only the parts of the screen that has changed is updated, and that logic creates a lot of overhead. Also, with that model it's harder to do things like soft scrolling and animations.

No, I needed something different, and I started to think about games. I guess my recent implementation of the Animeter utility also made me think along those lines. In games you typical find an active user interface as things mostly change all the time, and the screen is updated at a certain frame rate (number of times per second). As you may know, the standard screen refresh rate in an ordinary movie is around 24 frames per second, but for animated moves a more common frequency is about half of that. For most cases in a mobile app, that is sufficient to allow for things to come alive.

In TouchUI, that frequency is handled by a timer set to fire at every 80 milliseconds creating a frame rate of 12.5:

timer = new Timer();
timer.Interval = 80;

timer.Tick += new EventHandler(timer_Tick);
timer.Enabled =
true;

Each time that happens, the screen is redrawn by triggering a simple form refresh:

private void timer_Tick(object sender, EventArgs e)
{
   
this.Refresh();
}

That, in turn, will trigger the OnPaint method to be called, that is responsible for all the painting (as you saw in the previous part of this series).

While this allows for a very responsive and flexible user interface, you need to realize that it really puts the processor to work. Therefore, you probably want to turn all these updates off as soon as the user switch to another app or when the device is put in sleep mode. It can be done by catching the form's activate and deactivate events, like this:

private void MainForm_Activated(object sender, EventArgs e)
{
    timer.Enabled = true;
}

private void MainForm_Deactivate(object sender, EventArgs e)
{
   
timer.Enabled = false;
}

With all this in place, we have a great foundation for creating a highly active user experience with soft scrollling and animations.

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Chris | Compact Framework | Windows Mobile | User Interface

TouchUI - Painting (part 6)

by Chris 14. November 2009 14:00

As most things happening in a TouchUI app, the action begins in the main form (MainForm), and that is also true for the painting of all the graphics. To take full control over how the graphics is drawn in an app, the form's OnPaint method should be overridden, like this:

protected override void OnPaint(PaintEventArgs e)
{
   
base.OnPaint(e);

    dialogStack.Last().Paint(Common.Instance.PaintGraphics);
   
Rectangle r = Common.Instance.ClientRectangle;
    e.Graphics.DrawImage(Common.Instance.PaintBitmap, r, r, GraphicsUnit.Pixel);
}

The Common.Instance is a singleton used to store global things in the app, and is hold the current screen dimensions (ClientRectangle). It also holds an instance of the GDI Graphics class (PaintGraphics) pointing to a bitmap (PaintBitmap) that is used to draw to the screen (via e.Graphics). The bitmap is used as a buffer instead of doing the different GDI painting operations directly to the screen, and that is a good practice (called "double buffering") that will help you avoid things like screen flickering. Another important measure to avoid flickering is to override the OnBackGround like this:

 

protected override void OnPaintBackground(PaintEventArgs e) { }

Note that I don't call the form's (base class) implementation (base.OnPaintBackground).

So, we have a way of making the currently active dialog responsible for the painting of the screen, and this is an example of the Paint method of the main dialog:

public override void Paint(Graphics g)
{
    g.Clear(BackColor);

    g.DrawString(this.Text, NormalFont, HighBrush, 8, 5);
    g.DrawLine(Normal
Pen, 0, 23, Rectangle.Width, 23);
}

This code takes care of painting (clearing) the background, the heading text, and the horizontal line below the heading. The result looks something like this:

image

As we will see in some of the upcoming parts of this series, the dialog continues to pass the responsibility of painting to each of its controls, that does their work in much the same way.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Chris | Compact Framework | Windows Mobile | User Interface

TouchUI - One Form, Many Dialogs (part 5)

by Chris 7. November 2009 13:59

One of the hardest parts of writing apps for CF is the handling of the different forms, and also the navigation between the forms. The handling involves loading the forms (that takes time), showing the forms (and hiding the other forms to prevent strange behavior when switching between apps), and the memory management of forms (especially if they contain many controls, they use a lot of memory). After years with different form handling solutions (stacks with preloaded forms, etc), I finally decided to leave all those troubles behind by only having one form in my apps.

The single form in my TouchUI apps is usually called MainForm and even if it's not a part of the framework, it's really the main controller for the user interface. That is where initialization takes place, and all the events are fired in that single form. Each event (or overridden method) then gets passed on to the currently active dialog. A dialog is a TouchUI class that represent a logical form in the app, and the MainForm host a stack of currently loaded dialogs to ease navigation back up the dialog hierarchy. This is the first code (in the form's Load event) that runs when the app starts:

dialogStack = new List<Dialog>();
MainDialog mainDialog = new MainDialog(...);
dialogStack.Add(mainDialog);

As the dialog stack is a simple List, most of the other code in the MainForm will access the currently shown dialog with:

dialogStack.Last()

 

Here are some examples:

private void MainForm_MouseUp(object sender, MouseEventArgs e)
{
    dialogStack.Last().MouseUp(
new Point(e.X, e.Y));
}
private void MainForm_KeyDown(object sender, KeyEventArgs e)
{
    dialogStack.Last().KeyDown(e);
}
if(dialogStack.Last() is MainDialog)
{
   
MainDialog mainDialog = (MainDialog)dialogStack.Last();
   
DetailDialog detailDialog = new DetailDialog(...);
    dialogStack.Add(detailDialog);
}

 

The last code snippet is from the logic that navigates from the main dialog to a new dialog, and as you can see it resembles the initial code above. Therefore, moving up the hierarchy means to simply remove the last dialog in the stack (list).

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Chris | Compact Framework | Windows Mobile | User Interface

Powered by BlogEngine.NET 1.4.5.0
Theme by Mads Kristensen