Click here to Skip to main content
15,879,184 members
Articles / Desktop Programming / Windows Forms
Article

OSD window with animation effect, in C#

Rate me:
Please Sign up or sign in to vote.
4.98/5 (34 votes)
25 May 20066 min read 181.1K   4.3K   94   48
The article explains how to create an OSD window with animation/semi-transparent effects, in C#, using the NativeWindow class.

Image 1

Introduction

I needed an OSD-like window to show some important information from my WinForms application. I looked everywhere for samples in C#/.NET, but the samples that I could find were weak (from my point of view) and written in C++ (or C). So, I had no choice but to write my own OSD window (hereafter, just OW). But the excellent article "Floating, collapsible transparent window in C#" by olvio had some great code that helped me a lot. Thank you very much, olvio!

Background

First of all, what is an OSD? OSD is a short text message, displayed to the user when some event occurs – like the user presses the key, file downloading is complete, a new mail has arrived, and so on. An OSD (and OW, obviously) must possess three main characteristics:

  • Should always be the top most window: User must see our message even if he/she is working in Word, IE, or reading a mail.
  • Should always be completely transparent: User must see the text, and not the background of OW.
  • Should always be completely transparent to mouse/keyboard events: This means that the user must be able to select an icon positioned "under" OW through OW. Or, if the user is working in Word, and OSD's text is displayed "above" Word's main area and the user moves the mouse pointer in OSD's client area, then the mouse pointer must not change its appearance to "Arrow". Instead, it must keep the "Text select" form. In other words, the mouse/keyboard doesn't "see" OW, but the user does. :) Needless to say, OW must be transparent to the system as a whole – no button on the task bar, no entry in Task Manager, etc.

The suggested solution completely fulfills all the three requirements. Moreover, it offers additional features (optional, of course) – a bunch of animation effects when OW is shown/hidden, the OSD text itself may be fully opaque, fully transparent, or in between, and some others.

General architecture

As said earlier, the great code from olvio serves as the starting point. But I have "stripped off" a few redundant functions from the original FloatingWindow and kept only the required ones for OSD. So, my FloatingWindow is much, much simpler than the original. To be brief, the FloatingWindow is created as a System.Windows.Forms.NativeWindow with some special ExStyle flags:

  • WS_EX_TOPMOST helps OW to be the top most window.
  • WS_EX_TRANSPARENT helps OW to be completely transparent (by sight).
  • WS_EX_LAYERED (this flag is supported by Windows 2000 and above!) and WS_EX_TOOLWINDOW help OW to be completely transparent to the mouse/keyboard/system.

Now, we can show a new window (with or without animation) and also hide it (also with optional animation). From this window inherits FloatingOSDWindow, our main "work horse". It overrides the PerformPaint() method of the base class to show the OSD text, and gives us the public method Show(…) with many parameters. As a matter of fact, I have used the OW suffice to know what each parameter of this single method means, and nothing more. Let's jump to this method.

Using the code

We instantiate the new OW by calling a parameter-less constructor:

C#
FloatingOSDWindow osd1 = new FloatingOSDWindow();

Now, we are ready to call Show(…):

C#
public void Show(Point pt, byte alpha, 
    Color textColor, Font textFont, int showTimeMSec, 
    AnimateMode mode, uint time, string text)

The purpose of these parameters:

  • pt - Coordinate of the top-left corner of OW in screen coordinates.
  • alpha - Degree of transparency of the OSD text. This is not the transparency of OW's background. This window doesn't have the background. So this parameter is for the text's transparency. As you may expect, 0 means totally transparent (no text) and 255 means totally opaque – any object "under" the text is hidden. As a general rule, any value in the range 100-210 is fine.
  • textColor - OSD text color.
  • textFont - OSD text font. Again, the font must be large enough (18-48 point) to attract the user's attention.
  • showTimeMSec - For how long the OSD text will be displayed on the screen, in milliseconds. After this, OW will be automatically closed and disposed.
  • mode - One of the AnimateMode enum members. Determines the effect that will be used when OW opens/closes. Also see the next parameter, time.
  • time - If this parameter is zero, no animation effect is used, the mode parameter is just ignored, and OW opens/closes at once. If it is greater than 0, it specifies how long it takes to play the animation, in milliseconds. This time is not included in showTimeMSec but used twice – when OW opens, and when it closes. Example: showTimeMSec = 3500 and time = 500. In this case, after calling Show(…), for 0.5 sec, OW will be opened with the effect specified in mode. Next, the fully opened window will be displayed for 3.5 sec. Finally, during the same 0.5 sec, OW will be closed with the same effect. Again, a general (if we want animation) value in the range 100-500 is fine for this parameter.
  • text - OSD text itself, at last. :)

Example of calling the function:

C#
osd1.Show(new Point(20, 45), 155, Color.Lime, 
    new Font("Verdana", 26f, FontStyle.Bold | FontStyle.Italic), 
                 2400, FloatingWindow.AnimateMode.ExpandCollapse, 
                 370, "Hello! I am OSD window...");

After calling Show(…), you don't need to call the Hide()/Close() method explicitly. See the description of the showTimeMSec parameter if you have forgotten. But, of course, you can do it if, for example, if you want to force OW to close before showTimeMSec expires.

Points of interest

When I tried to override the PerformPaint() method in the FloatingOSDWindow class to provide the drawing of the OSD text, my first approach was to draw the string with:

C#
Graphics g = e.Graphics;
g.TextRenderingHint = 
   System.Drawing.Text.TextRenderingHint.AntiAlias;
g.DrawString(…);

It works, but in spite of the AntiAlias rendering mode for the text, the OSD text comes into view with a black edge around the letters. This edging is very thin, but noticeable. So I tried another way – create GraphicsPath from the given string and fill up this path with the given color:

C#
Graphics g = e.Graphics;
this._gp = new GraphicsPath();
this._gp.AddString("OSD text", …..);
g.SmoothingMode = SmoothingMode.HighQuality;
g.FillPath(this._brush, this._gp);

This approach works perfectly as you can see from the demo project. The interesting problem was with this._gp.AddString(…). This string of code, as you expect, adds the given text string to the path. One of the parameters for this method, float emSize, is the font size. Of course, this size must be the same as the size of the textFont font, which is passed to Show(…). At first glance, there is no problem: use textFont.SizeInPoints and we have the needed value. But this is tricky: AddString(…) expects float emSize in pixel, but we try to pass it as point. So, we need to convert between points and pixels, which in turn requires detailed knowledge of the DPI of the device we are drawing on. The last value returned by the Graphics.DpiY property:

C#
Graphics g = e.Graphics;
…
this._gp.AddString(..., ..., ..., 
    g.DpiY * textFont.SizeInPoints / 72, ..., ...);

We divide by 72, since point is 1/72 of an inch, no matter on what device we draw. And, Graphics.DpiY returns in dots (and, in fact, pixels) per inch. So this formula works just fine.

Final notes

This solution was developed under VS2005/FW2.0. So it may not open in VS2003. But the code will, no doubt, work in VS2003/FW1.1(1.0). Just create a new solution and use the *.cs files from the pack.

History

  • 1/1/2006: Version 1.0 - First release.
  • 5/25/2006: Version 1.1 - Fixed problem with handles leak.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Russian Federation Russian Federation
Professional C#/.NET/WinForms/ADO.NET developer. Microsoft Certified Solution Developer (MCSD) for Microsoft .NET since 2003.

Comments and Discussions

 
QuestionHow to display this OSD in Client rectangle of parent wpf window Pin
Member 428453330-Jun-15 21:34
Member 428453330-Jun-15 21:34 
GeneralMy vote of 5 Pin
Anton Ustyuzhanin17-Mar-15 21:59
Anton Ustyuzhanin17-Mar-15 21:59 
QuestionNot visible on Screenshot with CopyFromScreen Pin
Commerzpunk_cp4-Jun-13 1:52
Commerzpunk_cp4-Jun-13 1:52 
QuestionLittle problem in .net framework 4.0 Pin
super10227-May-13 16:12
super10227-May-13 16:12 
QuestionThis is AWESOME!!!!!! Pin
flippydeflippydebop16-Jan-13 3:44
flippydeflippydebop16-Jan-13 3:44 
QuestionWay to create OSD window in the bottom level? Pin
QMasters26-Nov-11 21:58
professionalQMasters26-Nov-11 21:58 
Generalmulti monitor Pin
proximus98313-Oct-10 22:28
proximus98313-Oct-10 22:28 
QuestionHow can I change it's color when it's displaying? Pin
baihualin198328-Sep-10 22:15
baihualin198328-Sep-10 22:15 
GeneralThanks, but it wont work in my app Pin
Fullmetal9901227-Feb-10 15:34
Fullmetal9901227-Feb-10 15:34 
GeneralGood, but ... Pin
Kartun20-Jan-10 4:04
Kartun20-Jan-10 4:04 
QuestionAny way to get it to Update faster? Pin
Kir Birger2-Jun-09 3:35
Kir Birger2-Jun-09 3:35 
NewsJust a little correction Pin
Siamoen10-Mar-09 14:55
Siamoen10-Mar-09 14:55 
GeneralExcellent work Pin
jtradke28-Aug-08 16:36
jtradke28-Aug-08 16:36 
Generalthank you :o) Pin
sqweez8-Feb-08 14:12
sqweez8-Feb-08 14:12 
GeneralDisplaying Images Pin
kevinwebster839-Oct-07 0:57
kevinwebster839-Oct-07 0:57 
GeneralProblem when using OSD with BSPlayer, or other DirectX software Pin
Vandra Akos9-Apr-07 23:31
Vandra Akos9-Apr-07 23:31 
Questionvery good article, but some small questions... Pin
mmaddin26-Mar-07 3:17
mmaddin26-Mar-07 3:17 
GeneralChanging the text Pin
TTCDave9-Mar-07 19:11
TTCDave9-Mar-07 19:11 
AnswerRe: Changing the text Pin
Vladimir N.2-Sep-07 20:48
Vladimir N.2-Sep-07 20:48 
QuestionLicense Pin
godfatherb5-Mar-07 10:37
godfatherb5-Mar-07 10:37 
QuestionMouseMove/MouseEnter/MouseLeave on control beneath it Pin
lok_tan31-Aug-06 17:45
lok_tan31-Aug-06 17:45 
QuestionNice, but.. Pin
seq-24-Aug-06 21:09
seq-24-Aug-06 21:09 
First of all great work!
But I was wondering if there is a way to make it work on DirectX application.
I mean I have a game, and would like to display a message while running the game.

Any Ideas how to do it ?

Regards,
Pawel
QuestionCan have 100% opaque window text while 70% transparent window background? [modified] Pin
Alexandru Matei30-May-06 23:03
Alexandru Matei30-May-06 23:03 
AnswerRe: Can have 100% opaque window text while 70% transparent window background? [modified] Pin
Mr.Smarty31-May-06 2:47
Mr.Smarty31-May-06 2:47 
GeneralRe: Can have 100% opaque window text while 70% transparent window background? [modified] Pin
Alexandru Matei31-May-06 5:37
Alexandru Matei31-May-06 5:37 

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.