First UI trick, the submenu arrow in OwnerDraw menus

 

As Buz said, there are everyday a lot of things to solve to make a software like PixVillage work. C# and the .Net framework are really nice tools to develop fast, but there are still so much things you have to do yourself !

You've surely noticed the cool owner drawn menu of the PixVillage user interface. MS has always made fun UI stuffs for its own softwares but has never given tools for developers to use it. However you can find a lot of places all around the Internet where people explain how to do that kind of menus (e.g. CodeProject).

The main idea is to create a Component implementing the IExtenderProvider interface to add a Bitmap property to each menu item. I could come back later on this to provide a full implementation.

A problem arose while drawing the items. In the original windows menus, the text is black on white when the item is not selected and white on blue when selected (of course, it depends on your color preferences, but let say we have default settings). A more modern style is to always use a white background, always use a black text, and put a half-transparent blue background with a one pixel blue border, the kind of style you can find in VS.Net 2003.
Doing this is really easy, but when you add a submenu, you can see that the submenu arrow appears automatically. You could think 'cool, less work for me !'. But windows draws the arrow in white when selected. And that is not what we want !!

And now, how do we tell to windows not to draw that submenu arrow ? I've gone through all the MSDN and no one say anything about it. My first try was to add a clip region to my Graphics object, I thought it would prevent windows from drawing it, but it had no effect.

But this way I discovered something interesting : Gdi+ clipping and Gdi clipping are totally independent. If you define a clipping region with Gdi+, you can still draw in that region using Gdi, and the reverse thing is also true. To prevent windows from drawing the submenu arrow, you must clip the region using the Gdi API.
Once you known it, the answer is really simple :

private static void ProtectFromDrawing(Graphics g,

Rectangle rect)

{

IntPtr hdc = g.GetHdc();

try

{

ExcludeClipRect (hdc,

rect.Left,

rect.Top,

rect.Right,

rect.Bottom);

}

finally

{

g.ReleaseHdc(hdc);

}

}

 

[DllImport("Gdi32.dll")]

public static extern int ExcludeClipRect(

IntPtr hdc, // handle to DC

int nLeftRect, // x-coord of upper-left corner

int nTopRect, // y-coord of upper-left corner

int nRightRect, // x-coord of lower-right corner

int nBottomRect // y-coord of lower-right corner

);

You just have to call ProtectFromDrawing at the end of your drawing function.

There are so many things to say about Gdi+ and Gdi...

Skup

posted on Friday, March 04, 2005 6:20 PM

Feedback

# re: First UI trick, the submenu arrow in OwnerDraw menus 3/28/2005 5:36 PM vnpro

Thank you so much.

# re: First UI trick, the submenu arrow in OwnerDraw menus 3/28/2005 8:48 PM Skup

I've been strugguling so hard with it ! I'm happy it could help you !
It also helped me in understanding the links between Gdi and Gdi Plus...
Even if avalon will make things easier, I'm sure their will still be strange things like that...

Title
 
Name
 
Url
Comments   
Protected by Clearscreen.SharpHIPEnter the code you see: