|
Its easy to reproduce, simply right click in the right part (the contextual part with the arrow) of the button named "Paste History Menu".
Then try to click another button... it's now stuck.
The same bug occurs with all buttons that have same kind of contextuel part ("Write & Close" for example).
Anyway, pretty cool control, really good work.
Alexis.
modified on Monday, January 14, 2008 5:20:39 PM
|
|
|
|
|
Thank you I love you so much
|
|
|
|
|
First i'd like to say that this is the control that many many many many many people are looking for. It includes may features of lots of seperate controls out there. Someone made a split button (a boring one too). someone made a glowing one. someone made a colorful one. You joined all that together. Now people like me can have a common button throughout their app and still have all the functions they need. Thank you.
Second, I can't quite figure out a few things. First of all, i can't seem to get the arrow to point right, even though that's what i set it as. Second, the color part is a little confusing, can you discribe that a little more? What does ispressed and keepressed mean and theres just a few things that don't seem to be working visually. The Grouppos for example.
|
|
|
|
|
When I click the ribbonmenubutton lots of OnPaint events was send by the "set" method in the ColorBase, ColorOn and ColorPress properties:
public Color ColorBase<br />
{<br />
get { return _baseColor; }<br />
set<br />
{<br />
_baseColor = value;<br />
R0 = _baseColor.R;<br />
B0 = _baseColor.B;<br />
G0 = _baseColor.G;<br />
A0 = _baseColor.A;<br />
RibbonColor hsb = new RibbonColor(_baseColor);<br />
if (hsb.BC < 50)<br />
{<br />
hsb.SetBrightness(60);<br />
}<br />
else<br />
{<br />
hsb.SetBrightness(30);<br />
}<br />
if (_baseColor.A > 0)<br />
_baseStroke = Color.FromArgb(100, hsb.GetColor());<br />
else<br />
_baseStroke = Color.FromArgb(0, hsb.GetColor());<br />
here---> this.Invalidate();<br />
}<br />
}
I fix this executing the set code only when the property change:
public Color ColorBase<br />
{<br />
get { return _baseColor; }<br />
set<br />
{<br />
if (_baseColor != value)<br />
{<br />
_baseColor = value;<br />
R0 = _baseColor.R;<br />
B0 = _baseColor.B;<br />
G0 = _baseColor.G;<br />
A0 = _baseColor.A;<br />
RibbonColor hsb = new RibbonColor(_baseColor);<br />
if (hsb.BC < 50)<br />
{<br />
hsb.SetBrightness(60);<br />
}<br />
else<br />
{<br />
hsb.SetBrightness(30);<br />
}<br />
if (_baseColor.A > 0)<br />
_baseStroke = Color.FromArgb(100, hsb.GetColor());<br />
else<br />
_baseStroke = Color.FromArgb(0, hsb.GetColor());<br />
this.Invalidate();<br />
}<br />
}<br />
}<br />
Thanks for reading and excuse my poor English
|
|
|
|
|
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<br />
{<br />
this.Refresh();<br />
}
Obviously the timer went out of control, so I added a timer1.Stop() statement before this.Refresh():
else<br />
{<br />
timer1.Stop();<br />
this.Refresh();<br />
}
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<br />
{<br />
if (i_factor == 0)<br />
timer1.Stop();<br />
this.Refresh();<br />
}
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) {<br />
if (mouse & this.SplitButton == e_splitbutton.Yes) {<br />
xmouse = PointToClient(Cursor.Position).X;<br />
ymouse = PointToClient(Cursor.Position).Y;<br />
this.Refresh();<br />
}<br />
base.OnMouseMove(mevent);<br />
}
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)<br />
{<br />
if (mouse & this.SplitButton == e_splitbutton.Yes)<br />
{<br />
prev_xmouse = xmouse;<br />
prev_ymouse = ymouse;<br />
xmouse = PointToClient(Cursor.Position).X;<br />
ymouse = PointToClient(Cursor.Position).Y;<br />
if (prev_xmouse != xmouse || prev_ymouse != ymouse)<br />
this.Refresh();<br />
}<br />
base.OnMouseMove(mevent);<br />
}
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.
|
|
|
|
|
TextAlign requests are being ignored, even in the demo application. Any suggestions? They don't shift at all from their current locations.
Other than that, I love it!
|
|
|
|
|
I want to do this:
Unable a button, that means, the button could not be clicked and the image on it is showed as grey-color.
I tried to set the RibbonMenuButton.enable to false, the result is: yes, the button could not be clicked, BUT, the image on it is still a colorful one, just looks like a common button.
So If I don't click it, I can't tell an enable button or an unable button from appearance. I thinks this is not good.
thanks!
123
|
|
|
|
|
Hi, I read your answers that you get the icons from the gnome.
Sorry for my stupid, I don't know how to download the icons there. Could you tell me?
For example, I found an icons set at:
http://art.gnome.org/themes/icon/1112
I tried to download it, but the .rar package could not be opened(report an error). and The context seem to be .tar file, not the icon file. How do you get the png out?
thanks.
123
|
|
|
|
|
Some are icons from the Tango theme. They have a normal RAR file, which I have decompressed with WinRAR suceesfully.
|
|
|
|
|
Hi nice work! I'd like to put the ribbon menu button in my toolstrip. Anyone has any suggestion how to do it? Thanks in advance!
Any way this is really a brilliant control!!
|
|
|
|
|
Hi,
I have added the reference and the control to my toolbox, but I don't have RibbonMenu control in my toolbox!
How can I add it to my project?
Thanks for your help,
Kamal
|
|
|
|
|
hello
you should add the RibbonMenuButton.cs into the SolutionExplorer, then reset it.
|
|
|
|
|
Hi there,
Many thanks for this control; we need more people in the community that contribute stuff like this.
I'm sure this is trivial, but I'm not sure where to start. If I set an image for the button (which gets scaled down to fit quite nicely), which has a radius of 25, the top left of it gets 'rounded' correctly; however, the top right remains rectangular. I'd send you a screen shot, but I'm not sure how on this thing.
Any suggestions, or further clarification by me, please let me know.
Many thanks again,
Jon.
The words of the prophets are written on the subway walls...
|
|
|
|
|
hi, first of all, this project is great and the look and feel is very professional.
but! when you're working on graphics, thing that takes a lot of cpu power you have to make a close look on the performances issues.
i saw that the worst problem with your code is that when you start timers, you refresh the controls even if it's not needed. this thing is simple to solve, here are two methods:
1. refresh it only if the painting parameters has changed.
2. stop the timer when the colors transformations has been completed.
i would go on to 2, since it's more elegant and frugal.
i hope you make a new release with fixed peroformance.
Roey
Don't believe to what you hear on the news...
|
|
|
|
|
one more thing, i was talking about you're reounded buttons...
Don't believe to what you hear on the news...
|
|
|
|
|
it's not paint the ribbonbutton at the begining when its IsPressed property is set true and that's the solution;
<br />
protected override void OnCreateControl()<br />
{<br />
base.OnCreateControl();<br />
.......<br />
if (_keeppress && _ispressed) this.UpdateEnter();
}<br />
<br />
protected override void OnMouseEnter(EventArgs e)<br />
{<br />
base.OnMouseEnter(e);<br />
UpdateEnter();
}<br />
<br />
public void UpdateEnter()<br />
{<br />
_colorStroke = ColorOnStroke;<br />
_tempshowbase = _showbase;<br />
_showbase = e_showbase.Yes;<br />
i_mode = 1;<br />
xmouse = PointToClient(Cursor.Position).X;<br />
mouse = true;<br />
A0 = 200;<br />
if (i_factor == 0)<br />
{<br />
R0 = _onColor.R; G0 = _onColor.G; B0 = _onColor.B;<br />
}<br />
timer1.Start();<br />
}<br />
-- modified at 19:23 Thursday 26th July, 2007
Ismail SEZEN
Physicist
|
|
|
|
|
Hi
very very nice Button. I think I found a small bug. When you set the ImageLocation to "Left", SplitButton to "Yes" and the Arrow to "ToDown" and then klick on the part of the Button which should open the context menu I ve geht an exception.
The problem ist in file "RibbonMenuButton.cs" in the "ClickSplit" region. I think this
if (_arrow == e_arrow.ToDown)
{
if (this.ContextMenuStrip != null)
this.ContextMenuStrip.Opacity = 1.0;
this.ContextMenuStrip.Show(this, 0, this.Height);
}
has to be this
if (_arrow == e_arrow.ToDown)
{
if (this.ContextMenuStrip != null)
{
this.ContextMenuStrip.Opacity = 1.0;
this.ContextMenuStrip.Show(this, 0, this.Height);
}
}
Best regards,
Bastian
|
|
|
|
|
Altough My English is not very well, I read an article about Office 2007 UI Licensing and I wonder whether or not it's possible to use this nice-look buttons on our products without Office 2007 UI Licence? Microsoft suggests some guidelines how to implement a ribbon controls as office 2007 UI style. But this ribbon buttons are made without this guideline. Anybody can give more explanation about this issue? below some links about this subject.
Licensing the 2007 Microsoft Office User Interface
Office 2007 UI License
Ismail SEZEN
Physicist
|
|
|
|
|
If you're interested, that had been already discussed on other article of Juan Pablo about Ribbon Form and Round button
|
|
|
|
|
I set attribute Radius = 0 (default : 6),then report mistake,deadliness
|
|
|
|
|
Hi!
first of all i'd like you to know that your control looks really great. all this stuff like split button, group pos is really cool..
but when i look at the code hell begins..
public enum e_splitbutton<br />
{<br />
No, Yes<br />
} isn't this something like bool but more memory consuming??
public enum e_showbase<br />
{<br />
Yes, No<br />
} ...
set { _showbase = value; this.Refresh(); } i guess Invalidate() would be more appropriate
if (A + A0 > 255) { A = 255; } else { A = A + A0; } A = Math.Min(255, A + A0); just look better..
xmouse = PointToClient(Cursor.Position).X;<br />
ymouse = PointToClient(Cursor.Position).Y; xmouse and ymouse could be a Point.. and you call PointToClient(Cursor.Position) twice :/..
and so on..
on my machine (Sempron3000+ 1GiB DDR400) with 7 buttons when hovering cpu goes up to 80%...
the title of your article is "Improved and Recoded RibbonMenuButton".. man.. i wonder how it looked before..
my suggestion - work on the performance of the button, because as I said, it looks just great!!
life is study!!!
|
|
|
|
|
It also has a bug in click handling, when you click a ribbonbutton which opens a dialog, then you close that dialog the button sends the message again and it opens the dialog again, you close that dialog again and then it sends the message to it's parent too.
|
|
|
|
|
this control is great. May I ask where you got your icon library?
-Shawn
|
|
|
|
|
Of course, is one the unofficial tango icons library from gnome
|
|
|
|
|
Take a look at :
http://www.codeplex.com/CustomerBorderForm
Why not integrate with this library, at least for the form.
Krys
|
|
|
|
|