Click here to Skip to main content
Licence 
First Posted 14 May 2007
Views 225,488
Downloads 7,700
Bookmarked 472 times

Improved and Recoded RibbonMenuButton

By | 5 Jun 2007 | Article
A new version with many functionalities
Screenshot - presentation.png

Introduction

First of all, thanks to everyone. I am grateful to know that people value this effort. I remember like yesterday when I was sixteen, more or less, and I saw many types of software, apps and games. For me, it was impossible to access and develop software then. I have learned a lot since, however, and I realize that it's now one million times easier to access this kind of software. Furthermore, if I can help anyone to create eye-candy apps, I've decided that they can use my code freely.

Background

I was thinking about how to make a fully customizable button and about how difficult it was changing RGB components. I decided to make RibbonColor, which has many options to operate with colors. If you play the demo app, you will understand quickly as you move the Hue, Sat and Brightness track bar. I have to admit that I have approximately 70% of the new RibbonControl library finished. However, as people are anxious to have improved code and have told me that I did not explain practically anything about my code, I've decided to do this like for dummies. So, here we go.

How to Use the Code

First of all, create a new Windows application. From the Solution Explorer, choose the option Add Existing Item. Then choose RibbonMenuButton.cs and Rebuild the project. Now, if you go to the form1 designer, in the toolbox you will have RibbonMenuButton. Drag it to the form. You will see a control without sense, but let's play with the properties. First, set properties for the RibbonMenuButton:

Screenshot - ribbonmenubuttonprops.png

When you have set the properties, add an image, set the text you want and set the font to Segoe UI if you have it. You will have something like this:

Screenshot - trialbutton.png

If you have compiled the project and you get this, the next step is to change the properties of the control. Let's see what each property represents. I recommend that you look at the button's Properties settings in the demo project:

  • Arrow: Paints an arrow ToRight or ToDown; this only paints, as the double functionality is in another property.
  • Colors: I think this doesn't need explanation; I recommend you to use the PlayGround app to choose your colors.
  • FadingSpeed: This facilitates fading between colors; choose 0 to avoid fading.
  • GroupPos: This is to make round corners on the Left, Right, Center (None), Top or Bottom.
  • ImageLocation: To put the image on the Left, Right, Top or Bottom.
  • ImageOffset: To offset from the borders.
  • MaxImageSize: To make buttons larger with a scaling image limit.
  • Radius: The corner radius.
  • ShowBase: If you want to show the BaseColor and BaseStroke color where Transparent is a color and makes fading. If set to No, it doesn't make fading.
  • SplitButton: Creates a double function button; the arrow section opens the associated ContextMenu and the other section, the main event.
  • SplitDistance: How big the arrow section button is.
  • Title: If you set this different from "", it automatically puts the title bold and under the text.
  • Text: If you have a title and want two lines of text, add \n to the text to make two lines.
  • KeepPress, IsPressed: If KeepPress is active on some buttons, when one of them is pressed, it keeps the press and the others in the containers lose the IsPress.

I have tried to crash the app, but it always works. So, I think the code is effectively error-free.

Points of Interest

If you want to learn more about these controls, I recommend that you take a look at:

  • this.Region: That's a good way to avoid matters of transparency.
  • LinearGradient With multiple colors, that makes the gradients easy.
  • MeasureString: That's a good method to position the text because you have to take away the base.OnPaint -> you have to do everything, including write the text.
  • TransformColors Method including the alpha opacity.
  • DrawArc method: As you can see, with the radius you can make smooth corners.
  • OnMouseUp: Here you can see what happens when the SplitButton is activated and IsPressed activated.
  • RibbonColor: I took the formulas from Wikipedia and Gimp. The System.Drawing.Color.GetHue, Sat and Brightness don't work well.

History

  • 5 June, 2007. 1.6 - Solved Repaint, ChangingSize and excessive CPU consumption. Added KeepPress and IsPress functionality.
  • 16 May, 2007. 1.5 - Because I had to recode everything when I learned how to use Hue, Saturation and Brightness.

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

About the Author

Juan Pablo G.C.

Software Developer

Spain Spain

Member

I'm Electronic Engineer, I did my end degree project at Astrophysical Institute and Tech Institute. I'm HP Procurve AIS and ASE ,Microsoft 3.5 MCTS
I live in Canary Islands ,developing customized solutions
 
I'm developing with WPF4, SL4 MVVM, MVC3 Razor and WP7 projects, more info at my websites. Improving with Android and IOS.
 
Websites:
MemCards
Mareinsula


Take a look to my blog Juan Pablo G.C.
Mareinsula

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralTab key press Pinmemberpiyush741982020:21 5 May '08  
Generalstrip menu does not work by me Pinmembertrupik20:14 27 Feb '08  
GeneralFound a bug on right clicking a button... [modified] PinmemberOctopod5:50 10 Jan '08  
Generalso cool PinmemberJackChen198722:11 7 Jan '08  
GeneralI'm confused Pinmembertcsoccerman13:49 4 Dec '07  
GeneralAnother CPU bug PinmemberJordiproatec2:30 29 Nov '07  
General3 bug fixes (includin CPU issues) Pinmembergpgemini11:01 13 Oct '07  
Hi,
 
First of all - Jaun, I LOVE your control, it's probably one of the best in CodeProject.
 
But as soon as I started using it, i noticed it has CPU consumption issues (I always have SiMeter on, so noticing it was a breeze).
It has two CPU problems, first is that moving the mouse around the buttons causes major CPU usage, which probably happens due to over-painting the buttons (and should be fixed by optimizing the code), and second that it has bursts of massive CPU usage with no user/mouse interaction. The latter is obviously a bug.
 
all bugs/fixes here relate to the RibbonMenuButton.cs file.
(fixed file is linked at the end of the post)
 
Bug #1: when moving the mouse quickly over a split button, or two non-split buttons, the CPU usage jumps to 100% until the mouse is moved over the buttons again (do it too many times and you are stuck with 100%).
This is a major application killer, and obviously cannot be left unfixed.
To locate the CPU leakage, I went to the immediate suspect: OnPaint().
Added a WriteLine("Paint" + DateTime.Millisecond) to see each time a button is painted, and I saw it was bombarding with OnPaint() calls for no reason.
Add a breakpoint AFTER the bombardment has started and you find the perpetrator:
timer1_Tick() is being called, and executes the following in the "Leaving" region:
else
{
this.Refresh();
}

Obviously the timer went out of control, so I added a timer1.Stop() statement before this.Refresh():
else
{
timer1.Stop();
this.Refresh();
}

And what do you know, the bug is gone.
Hurray !
But obviously this timer is good for something ...
Since I only use non-fading buttons (I want maximum performance) I tried the fix on a fading button, and sadly it broke.
So I tested to see if the bug is unique to non-fading buttons, or affects all buttons, and turns out it only happens with non-fading buttons.
So I patched the fix to affect only non-fading buttons:
else
{
if (i_factor == 0)
timer1.Stop();
this.Refresh();
}

 
Bug #1 fixed.
 
Bug #2: When the mouse is hovering over a button, periodic OnPaint() calls are executed.
With the WriteLine() thing in OnPaint I was able to notice a weird behavior, that had little effect on CPU usage but was clearly a bug - a hovering non-moving mouse over a button was producing OnPaint() calls, slowly but constantly (around 2-10 per second), with varying effect on different buttons.
To catch this, I added a breakpoint in OnPaint that hit after 50 passes (to avoid regular OnPaint calls) and put the mouse over a button. After a few seconds I found the second perpetrator:
The overrriden OnMouseMove() method.
protected override void OnMouseMove(MouseEventArgs mevent) {
if (mouse & this.SplitButton == e_splitbutton.Yes) {
xmouse = PointToClient(Cursor.Position).X;
ymouse = PointToClient(Cursor.Position).Y;
this.Refresh();
}
base.OnMouseMove(mevent);
}

After taking a look at it, I found nothing wrong about it (except the really weird way to get xmouse and ymouse, why not use the mevent.X and mevent.Y values ?).
The only suspicious thing was using this.Refresh() inside a OnMoueMove() event handler.
So I tested it in a small program outside, and indeed, calling this.Refresh() (or this.Invalidate()) inside a OnMouseMove() handler is a BAD idea - it causes the OnMouseMove() event to be called repeatedly and indefinitely.
It's probably some internal WinForms bug/feature (or maybe it's an abuse of the API), but either way I fixed it by checking that the mouse has ACTUALLY moved, before calling this.Refresh():
protected override void OnMouseMove(MouseEventArgs mevent)
{
if (mouse & this.SplitButton == e_splitbutton.Yes)
{
prev_xmouse = xmouse;
prev_ymouse = ymouse;
xmouse = PointToClient(Cursor.Position).X;
ymouse = PointToClient(Cursor.Position).Y;
if (prev_xmouse != xmouse || prev_ymouse != ymouse)
this.Refresh();
}
base.OnMouseMove(mevent);
}

 
Bug #2 fixed.
 
Bug #3: This one is a non-CPU related, when RIGHT-clicking the arrow of a split-button, AND then clicking outside the opened context menu, ALL the RibbonButtons stop reacting to mouse events (except click events) until the context menu is clicked properly.
This one was obviously related to mouseDown and mouseUp events, so I cheched them out.
I found that when clicking the button, there is a check in the MouseUp event if the click was inside the arrow area (hmmmm, suspicious already) and if so, the conetxt menu is opened under the button, if not, the event is passes to the base.
First attempt: lets pass the event to the base either way. Quickly enough it turned out to be a bad idea. But why ? Since this causes the context menu to open under the mouse, and then in a split of a second to move under the button. Taking another look at the problem I noticed that when right-clicking the button NOT in the arrow area, the context menu is opened under the mouse, and in the arrow area it is overridden and is opened under the button. But in the latter case, the base class event handler is never called. The mouseUp event never reaches the base class and the mouse state is messed up.
To fix this, I added a check in the MouseUp method, if the click is a RIGHT-click, pass the event to the base class and return, the effect of this is that the context menu is opened naturally and all is good, if the click is a LEFT-click the context menu is opened manually under the button, and all is good.
 
Bug #3 fixed.
 

Ce tout.
The fixed file is here:
http://gpgemini.googlepages.com/RibbonMenuButton.zip
Notice that these are plain patches to the found bugs, I hope Juan takes a look at them and fixes them properly in the next release.
GeneralTextAlign requests are ignored PinmemberGrantM10:19 2 Oct '07  
QuestionHow to unable a RibbonMenuButton? Pinmemberivanchain@hotmail.com14:43 16 Sep '07  
GeneralHi, about the icons Pinmemberivanchain@hotmail.com3:44 11 Sep '07  
GeneralRe: Hi, about the icons PinmemberAlpha Nerd7:32 24 May '08  
GeneralUsing this button as toolstripbutton PinmemberVincent_ws17:09 10 Sep '07  
Generalmissing Ribbon Menu PinmemberKamalmostofi11:40 31 Aug '07  
AnswerRe: missing Ribbon Menu Pinmemberqien22:32 15 Oct '07  
QuestionImage clipping Pinmemberjoncle1237:50 12 Aug '07  
GeneralCPU problems PinmemberRoey C11:05 4 Aug '07  
GeneralRe: CPU problems PinmemberRoey C11:07 4 Aug '07  
QuestionIsPressed = true paint bug [modified] Pinmemberalleph9:51 26 Jul '07  
QuestionBug? Pinmemberjdem5:33 26 Jul '07  
Generalabout Office 2007 UI Licence Pinmemberalleph21:43 24 Jul '07  
AnswerRe: about Office 2007 UI Licence PinmemberPraded3:26 5 Aug '07  
Generalmistake ,deadliness Pinmemberqingtianyu919:43 11 Jul '07  
Generalthe code.. PinmemberSeishin#5:00 19 Jun '07  
GeneralRe: the code.. [modified] PinmemberMario M.5:15 16 Sep '07  
GeneralIcons Pinmembershawn322:31 19 Jun '07  

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

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

Permalink | Advertise | Privacy | Mobile
Web03 | 2.5.120529.1 | Last Updated 5 Jun 2007
Article Copyright 2007 by Juan Pablo G.C.
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid