Fix for Enabled changing button "Down" status - delphi

I have some TSpeedButtons on a form that has multiple uses. In one mode I don't want one button to be clicked so I just set "Enabled:=False;"
But, if it was Down and I force it to Enabled:=False it goes to the Up-State. How can I prevent "Enabled" affecting the current Up/Down State as I still need it to visually show the current State.

In short, you cannot do what you are asking for with a standard TSpeedButton. This is just the way it is coded to work.
When you set Enabled to false on a TSpeedButton, the button gets drawn in a disabled state regardless of its Down property. The TSpeedButton.Paint() method forces the State property to bsDisabled, wiping out any current Up/Down state. In Delphi 5, this causes the button to be drawn with an Up appearance. In more modern versions of Delphi, if visual styles are enabled, the button gets drawn with a flat appearance that is neither Up nor Down.
The only way to change this behavior is to either:
derive a new class from TSpeedButton and override the virtual Paint() method so you can custom-draw the button yourself however you want. You will have to draw the entire button, though.
make a copy of the VCL's Buttons.pas source file (Vcl.Buttons.pas in XE2 and later), add the copied file to your project (make sure Runtime Packages are disabled), and then you can modify the implementation of TSpeedButton.Paint() itself however you want. Just know that this will affect every TSpeedButton in your project.

Related

How to make TdxBarButton always visible in TdxBarManager.Bars[i], even when user is removed this button (made invisible) previous time?

I am using DevExpress TdxBarManager for Delphi, which is very complex component. It contains set of TdxBarButton's (or its descendants) - commands. And it also contains set of TdxBars - panels in which those commands are placed.
During the design time the developer creates TdxBarButton instance, assings properties to it in the object inspector and then drags-and-drops it on the TdxBar instance.
During the runtime the user can call 'Add or Remove Buttons' and this opens the dialog, in which the user can opt to make some buttons from this bar invisible. The visible/invisible button selection is preserved in the user registry.
My question is - how can I press the TdxBarButton to be always visible? Even when the user has opted to make it invisible. I know that dxBarButton has Visible property whose possible values include ivAlways, but this value ir preserved and resetting it does not make the invisible button visible again.
I am currently developing using Delphi 6, but I guess the same applies to TdxBarManager in the more recent Delphi as well like Delphi 2009 or Delphi Sydney.

Why can't I use ToolButtons after assigning them an Action?

I am learning Delphi and building a simple NotePad. However, as soon as I add an Action to some ToolButtons (note the align left, center, and right buttons and Bold), they are disabled in the running app, although the Enabled property is set to true in the Object Inspector. They become enabled in the running app if I remove the Action from them in the Object Inspector, but then they are just useless clickable buttons. I have added some pictures below.
I have Googled and tried myself almost to insanity and I really can't figure it out myself.
A normal TAction needs an OnExecute event to become enabled. You can control this with the property DisableIfNoHandler, which defaults to True.

How do I prevent menu and toolbar clicks stealing focus from a floating form?

I want to achieve the same effect as in Visual Studio 2010+, where if you float an editor on top of the main form, clicking on a main form menu or toolbar button doesn't cause the main form to steal focus; instead the floating window retains focus.
Without this it becomes impossible to invoke any main menu command that operates on a focused control when the focused control is in a floating window - because the control you wanted to operate on loses focus just as the command is invoked.
(Ironically, if you look closely at this image you'll see that the selection in the editor is muted, indicating that the editor control doesn't have focus. Visual Studio seems to be doing something slightly devious to achieve the illusion that the floating window is still focused.)
The solution is very easy if you are using TActionMainMenuBar and TActionToolBar.
First the menu bar: TActionMainMenuBar has a property AutoFocus, which is True by default. Set this to False and then clicking on the menu won't automatically give focus to the form containing the menu. Instead, the form that previously had focus will retain it.
Now the tool bar: TActionToolBar doesn't have an AutoFocus property. Instead you need to handle its OnMouseActivate event and return maNoActivate.
Note that returning maNoActivate from an OnMouseActivate handler doesn't work for all controls. Some controls such as TButton will give themselves the focus when clicked regardless of the return result from the OnMouseActivate handler. But in the case of TActionToolBar we do get the effect we are after.
It took me a while to find this though, and even searching Google for a page containing both 'AutoFocus' and 'OnMouseActivate' elicits no useful results (other than, presumably, this page once it gets indexed). So I hope this answer will help someone else.

Firemonkey: TSpeedButton IsPressed no visible Effect?

How do I set a TSpeedButton (on a TToolbar) to look pressed down? It's only highlighted when clicking but gets normal when the mouse leaves it. I set the property Stayspressed to True and indeed the property IsPressed becomes and stays True, but this state is not visible.
What style are you using? Some of the included ones do not have every effect included.
First, revert back to the windows style. If that works, then it's definitely a styling issue, rather than a code issue.
If you want to add an effect (actually an animation) to another style:
Right click on a button and select Edit Default Style.
Find the Fill.Color property of the Rectangle you want to show the anmimation.
Click the animation icon and add a TColorAnimation
Set: the StartValue (the existing value).
The StopValue
The Trigger: IsPressed=True
Repeat the above to add a second animation with the Start and StopValues reversed and Trigger of IsPressed=False
This is a tough one - the standard TButton style includes effects which work - the button will look pressed when "IsPressed" is true. However, other styles (and especially your own) can be much more problematic. I have found the best solution is to have 2 styles and change the style when the button is pressed.
I found it pretty impossible to get "mouseover" animation to work with "pressed" animation in buttons - normally you want to highlight the button slightly when the mouse passes over and then add an effect when you press - especially when you don't want the default shadow effect but a colour effect (which I prefer, I don't like the inner shadow effect of a default button press), but I always seemed to end up with issues. Either one effect wouldn't fire OR the button state wouldn't return to what you'd expect (visually I mean).
My advice - add a little bit of extra code to change the style for the pressed button, you might go mad otherwise :-)

Design-time drag and drop in Delphi?

Before Delphi 2006 (I think) introduced the TFlowPanel and TGridPanel, I did a control that was similar in concept. It still does a couple of things those controls do not do, and when upgrading my code to Delphi 2009, I decided to add a couple of enhancements to that as well.
Right now, the order of the child controls is determined by their creation order. The FlowPanel and GridPanel show a better way with ControlIndex and other filtered properties, but I was wondering if there is a way to handle drag and drop reordering in design-time? As far as I can tell, dragging an edit control and dropping it onto my panel doesn't call anything that I can access at design-time.
I was half-fantasising about a way to either detect the drop operation directly, or to perhaps detect when a control is moved so I can determine where it should go.
Any ideas?
Update:
OK, got it working. The container control was already overriding AlignControls to manage the placement of the controls. When you drag the nested control and drop it, AlignControls is again called. I then compared the new coordinates of the control with the other controls in the list and moved it to the appropriate position.
There were a couple of problems that I had to work through (mostly related to the many calls to AlignControls) but the basic concept is simple enough. Thanks to all the commenters for all the help.
You can't drag a control that's already on the form and drop it onto your panel. Dragging is only for moving a control, not for changing its parent. To change the parent, cut and paste.
If the control is already on your panel, and you want to move it to another position on your panel, then the panel can control the layout by overriding the TWinControl.AlignControls method. When a control is moved, its SetBounds method is called, and among the things tha happens is that it calls AlignControl(Self) on its parent window. That calls AlignControls. Look in Controls.pas, and you'll see that that's a complicated method, but it's what is responsible for the layout of the children on a control, and that's exactly what you're planning to change.
Perhaps some of these suggestions might help.
You can re-parent a control in the designer without having to do cut-and-paste. View the structure pane, and simply drag the visual control to the node of another parent in the structure pane. If you have things in a flowpanel, drag everything out of the flow panel and drag them back in the order that you want them to be.
(You can re-parent ANY visual control this way, without changing anything other than its parent. I highly recommend doing it this way.)
You can view the form as text, and move the declaration order around in there -- but obviously you'll need to be careful when editing the "resource" file directly.
You can set tab order in the designer, so you could make a different control based on tab order that works as you want. You can right click on the form and change the creation order of the non-visual controls, but that doesn't work with visual controls.
Have you tried to write an "OnDragDrop" event for your grid component, where you check if your component is in design mode?
I haven't written such a component yet, but I don't see why the event shouldn't trigger.

Resources