Click here to Skip to main content
15,042,336 members
Articles / Multimedia / GDI+
Posted 8 Sep 2009


45 bookmarked

Destination Flicker Board (GDI+ Made Easy)

Rate me:
Please Sign up or sign in to vote.
4.94/5 (19 votes)
8 Sep 2009CPOL3 min read
Shows how easy it can be to create a WinForms UserControl using only GDI+
Frankfurt International Airport Departure Board


This article will show you how to use the System.Drawing classes (also known as GDI+) to create a .NET UserControl for displaying information similar to the old Arrival/Departure boards at airports. As each row changes, the board will flicker through the alphabet to display the new entry.

This article is not meant to teach you how to become a GDI+ expert. It’s really designed to show that GDI+ isn't as hard as many people think. It's designed to encourage developers to create custom controls when existing controls don't meet the requirement, or when you want to add some gloss to your Winforms UI presentation.

Using the Code

Once you have added the AirportDepartureBoard control to your form, you will find that you can not add or remove rows to the control. So the only way of changing a row’s text is to call the control's UpdateRow method. It is best to update the row with the flicker set to Flicker.No while initializing the form. This will avoid slowing down the load time of the form.

MyDepartureBoard.UpdateRow(0, "Hello World" Flicker.No);

Once initialized, to get the flicker working, set the Flicker parameter to Flicker.Yes when updating a row's text.

MyDepartureBoard.UpdateRow(1, "It’s a beautiful day" Flicker.Yes);

The AirportDepartureBoard control, in the download source code, is an example of how to use the Croll.Windows.Forms.DestinationBoard control which does most of the work. The DestinationBoard control has a number of properties you can set at design or run time. These are BoardBackColor, BoardRowDividerColor and BoardFlickerHingeColor. You will find as you change these properties at design time, the changes will be reflected in the form designer (which is nice). One thing worth noting is that the control only displays whole rows using the BoardBackColor. Any space left at the bottom of the control will be displayed using the control's BackColor property.

Using GDI+ to Create a UserControl

GDI+ sounds a bit scary. It gives the impression that you're going to have to do some low level programming to use GDI+. But that’s not the case because the .NET Framework has abstracted the GDI+ functionality into the System.Drawing namespace making the developer's life a whole lot easier and simpler. The centrepiece of the System.Drawing namespace is the Graphics object. Graphics has a number of methods for drawing. This demonstration will highlight some of the easier methods to use when creating your own UserControls. Below is a code snippet that uses two simple graphics methods, FillRectangle and DrawLine.

private void PaintPanel()
    //Get the control's Graphics object used to paint
    Graphics g = this.CreateGraphics();
    // Used to paint the row dividers
    Pen dividerPen = new Pen(this.boardRowDividerColor);
    // Used to paint the hinge in the middle of each row
    Pen hingePen = new Pen(this.boardFlickerHingeColor);

    // Paint the control with the board's BoardBackColor
    g.FillRectangle(new SolidBrush(this.boardBackColor), 0, 0,
        	base.Width, this.rowCount * this.rowHeight);

    // Paint row dividers
    for (int i = 0; i <= this.rowCount; i++)
        g.DrawLine(dividerPen, 0, i * this.rowHeight, 
				base.Width, i * this.rowHeight);

    // Paint flicker hinge lines
    for (int i = 0; i < this.rowCount; i++)
        g.DrawLine(hingePen, 0, i * this.rowHeight + (this.rowHeight / 2) + 1,
    	       	base.Width, i * this.rowHeight + (this.rowHeight / 2) + 1);

    // Paint the text values for each row
    for (int i = 0; i < rows.Count; i++)
        PaintRow(new PaintRowParameters(i, Flicker.No, rows[i]));

In the next snippet, you will also notice the use of the DrawRectangle and DrawString methods. All these methods are so well named that no explanation is needed making the System.Drawing namespace relatively intuitive. Just as important is the use of Brushes. In this case, a simple SolidBrush has been used, but there are a variety of brushes that can be used to really bring your new control to life. It should also be noted that a number of objects need disposing, so don't forget to dispose of the objects when you have finished using them.

private void PaintCharacter(char c, int colIndex, int rowIndex)
    Graphics g = this.CreateGraphics();
    SolidBrush brush = new SolidBrush(ForeColor); //Used to DrawString
    // Used to paint the hinge in the middle of each character
    Pen pen = new Pen(this.boardFlickerHingeColor);

        int x = (this.colWidth * colIndex);
        int y = (this.rowHeight * rowIndex) + 1;
        Rectangle topHalfRect = new Rectangle(x, y, this.colWidth, 
					(this.rowHeight / 2) - 1);
        Rectangle fullRect = new Rectangle(x, y, this.colWidth, this.rowHeight - 1);

        // Just paint the top half of the character first to give
        // the impression that the flap is flicking over
        g.FillRectangle(new SolidBrush(this.boardBackColor), topHalfRect);
        g.DrawString(c.ToString(), this.Font, brush, topHalfRect);
        g.DrawLine(pen, x, y + (this.rowHeight / 2), x +
        	this.colWidth, y + (this.rowHeight / 2));

        // Now paint the whole character
        g.FillRectangle(new SolidBrush(this.boardBackColor), fullRect);
        g.DrawString(c.ToString(), this.Font, brush, fullRect);
        g.DrawLine(pen, x, y + (this.rowHeight / 2), x +
        	this.colWidth, y + (this.rowHeight / 2));

As you can see, no rocket science required, no low level programming. Pretty simple code for what I think is a pretty cool control. Definitely, this has just scratched the surface of what can be done with GDI+ but it shows for most custom controls, all you need is a bit of imagination.

Helpful Tip

When working in the System.Drawing space, or charting for that matter, you come across a lot of x and y parameters. The easy way to remember what’s x and what’s y is as simple as reading this page. First you read across (x) and then you read down (y).


  • 7th September, 2009: Initial version


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Australia Australia
Enjoying life developing mobile device software for Contractors Apps and Ezi App.

I also teach C#, Java and Project Management a couple of evenings a week.

Prior to moving to DCB, I'd been a Windows software developer for nearly 15 years

Comments and Discussions

GeneralMy vote of 2 Pin
dwivediknahal17-Sep-09 16:29
Memberdwivediknahal17-Sep-09 16:29 
QuestionRe: My vote of 2 Pin
RobCroll19-Sep-09 23:33
MemberRobCroll19-Sep-09 23:33 
GeneralSimply Brilliant Pin
Scott G Blood16-Sep-09 0:18
MemberScott G Blood16-Sep-09 0:18 
GeneralRe: Simply Brilliant Pin
RobCroll20-Sep-09 23:58
MemberRobCroll20-Sep-09 23:58 
Generalgreat tutorial on GDI+ Pin
BillWoodruff11-Sep-09 19:25
mveBillWoodruff11-Sep-09 19:25 
Hi, Robert,

Thanks for this article; I have been having lots of fun studying your code Smile | :)

A control that has a 'flicker' as a feature shoud get extra points !

imho one of the most interesting things you are doing involves your use of threading here, and I think if you cared to expand on your strategy there, and your implementation, that would make this even more valuable an article.

There's also a commented out section of code where you were using 'BeginInvoke that's very tantalizing, and you comment using it would be make the UI unresponsive; I'd appreciate any comments on that (no idea if that would interest other CPians).

Whenever I read GDI+ code in the Paint events, I'm always curious if there would be any "payoff" (less memory use, less cpu cycles, faster painting ?) in moving outside the Paint event the instantiation of the Bruhes and/or Pens that are invariant.

On that same topic : I experimented with setting SmoothingMode, CompositingMode, and CompositingQuality in both the code that draws the lines, and the code that draws the text characters : some of the variations resulted in interference with the lines being drawn. Whether the text looked a little smoother : hard for my old eyes to say.

A few very trivial comments :

-1. you might want to mention in your article that your code sample is compiled against FrameWork 3.5 ?

0. was able to convert to use in VS2010 beta 1 with no problem, and re-compile to use FrameWork 4.0

1. it was easy to modify the anchoring of the usercontrols so the rows would expand at run-time properly ... but with a fair amount of re-draw flicker : a problem with all usercontrols. while the "brute force" way to take care of that is to use SuspendLayout and ResumeLayout on your usercontrols in the Form ResizeBegin and ResizeEnd events ... sometimes using SetStyle variations will help with that : of course on some usercontrol you cannot use OptimizedDoubleBuffer.

2. i find it interesting i could "get away with" using : SetStyle(ControlStyles.OptimizedDoubleBuffer, true);

on the AirportDestinationBoard usercontrol, but not surprised that using it on the DestinationBoard usercontrol screwed up the redraw.

summary : somewhere out there a great article for CP exists in a mind (like yours ?) explaining in detail every possible strategy for the run-time control of moving and resizing UserControls without flicker.

"Many : not conversant with mathematical studies, imagine that because it [the Analytical Engine] is to give results in numerical notation, its processes must consequently be arithmetical, numerical, rather than algebraical and analytical. This is an error. The engine can arrange and combine numerical quantities as if they were letters or any other general symbols; and it fact it might bring out its results in algebraical notation, were provisions made accordingly." Ada, Countess Lovelace, 1844

GeneralRe: great tutorial on GDI+ Pin
RobCroll11-Sep-09 22:09
MemberRobCroll11-Sep-09 22:09 
GeneralRe: great tutorial on GDI+ Pin
BillWoodruff11-Sep-09 22:35
mveBillWoodruff11-Sep-09 22:35 
GeneralRe: great tutorial on GDI+ (faster painting) Pin
RobCroll11-Sep-09 22:20
MemberRobCroll11-Sep-09 22:20 
GeneralInteresting article. Pin
SalizarMarxx10-Sep-09 10:42
MemberSalizarMarxx10-Sep-09 10:42 
GeneralRe: Interesting article. Pin
RobCroll11-Sep-09 14:07
MemberRobCroll11-Sep-09 14:07 
GeneralThat's a new one... Pin
Johnny J.8-Sep-09 11:19
professionalJohnny J.8-Sep-09 11:19 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.