In a Delphi 10.4 VCL Application, TCard (as container-item of TCardPanel) does not have public OnShow and OnHide events (like TTabSheet has).
Therefore, the TCard.OnEnter event-handler is NOT triggered when a specific TCard is ACTIVATED. The TCard.OnEnter event-handler is triggered ONLY when e.g. clicking on a control on the TCard.
Example code:
CardPanel1.ActiveCard := Card2;
In this case, the TCard.OnEnter event is NOT triggered!
Is it possible to upgrade the TCard class with public OnShow and OnHide events? Or is it possible to simulate those events?
Use the OnCardChange event of TCardPanel and compare PrevCard and/or NextCard with your actual card instances.
Related
Is it possible to have the Event list in the IDE for a frame extended by an event I define in a TFrame descendant:
TYPE
TFrame1 = CLASS(TFrame)
...
...
PRIVATE
FSomething : TNotifyEvent;
PUBLISHED
PROPERTY OnSomething : TNotifyEvent Read FSomething Write FSomething;
END;
and then have "OnSomething" Visible in the IDE when I select the dropped TFrame on a form?
In a similar vein:
Is it possible to not have the sub-component on a TFrame selectable in the IDE, so that I can expose only the Events for my TFrame and not allow the user to access the events for the sub-components? And is it possible to "suppress" the standard events for a TFrame so that only the events I PUBLISH is visible?
In RAD Studio 10.1 Berlin quite a few things has changed from previous version. In FMX there are a few previously published events that has now been changed to only be public.
I have a Multi Platform Project that uses a TStringGrid component and the OnDblClick event. When opening this project in Studio 10.1 I get warned that the Property OnDblClick does not exist.
The question is now how I can use the no longer published event?
(I must say that It's hard to understand why they haven't set mouse events to Published anymore. As far as I know most regular PCs and OSX machines doesn't have touch. A true Multi Target Project should be able to target these systems without hassle as they did in Studio 10 Seattle)
In case the event handlers already exist (which I imply by the error message), you can assign these handlers to their events in FormCreate.
procedure TForm1.FormCreate;
begin
StringGrid1.OnDblClick := StringGrid1DblClick;
end;
One solution is to make your own component where you extend the FMX.TStringGrid to have published event handlers again.
See here how to create a new FMX component: creating a firemonkey component
Here's the code to re-publish the mouse events.
unit MyStringGrid;
interface
uses FMX.Grids;
type
TMyStringGrid = class(TStringGrid)
published
property OnDblClick;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnMouseEnter;
property OnMouseLeave;
end;
procedure Register;
implementation
uses FMX.Types;
procedure Register;
begin
RegisterComponents('NewPage', [TMyStringGrid]);
end;
initialization
RegisterFmxClasses([TMyStringGrid]);
end.
This has been reported as a bug here.
Looking at the source code in Delphi 10.1 berlin the public OnDblClick event is actually inherited from TControl class.
Similar the OnDblClick event is also inherited from TControl class with the exception that it is made public, like many other events that are inherited from TControl˙ class.
Any way it seems that guys at Embarcadero have been doing some refactoring by cleaning the parent property redeclarations˙(not sure if this is the right term) like:
type
TParentClass = clas(Tobject)
public
property ParentPropery: Integer read GetParentProperty write SetParentProperty;
TExampleClass = class(TParentClass)
public
property ParentPropery;
end;
Redeclaring ParentProperty in the above case is not needed as it will be available in all child classes unless you want to change its visibility from public to published for instance.
If you look at Delphi 10 Seattle source code you see that property OnDblClick is redeclared in several TStringGrid parent classes being published in TCustomScrollBox for the first time.
I have many Forms on my project that uses the Form OnClose event.
However, I need to add another "generic" OnClose on all forms in runtime.
There is any way to just add the new event method, instead of replace it? So, the form will trigger both OnClose events.
Only one handler can be assigned to an event at a time.
What you could do is assign the "generic" handler to each Form's OnClose event, and then have each Form override its virtual DoClose() event to do their local work. It can call the inherited DoClose() method when ready to call the generic handler. For example:
type
TMyForm = class(TForm)
protected
procedure DoClose(var Action: TCloseAction); override;
end;
procedure TMyForm.DoClose(var Action: TCloseAction);
begin
// do something here...
inherited; // <-- call OnClose handler
end;
The alternative is to implement a multicast delegate for the actual event handler, and then the delegate can call other handlers as needed. Here are a few blogs on that topic:
Multicast events using generics
MultiCast Events - Part 1
MultiCast Events - Part 2
MultiCast Events - Conclusion
Alternatively, you can ignore the OnClose event altogether and implement an Observer Pattern instead (using DoClose() to call the observers). Here are a few blogs on that topic:
Observer Design Pattern in Delphi
Delphi and the Observer Pattern
The Observer Pattern
I have the code which shows a search form for a specific DBGrid which is placed in another form (the caller Form of TSearchGridForm):
procedure TSearchGridForm.FormDeactivate(Sender: TObject);
begin
// Pseudo
if NewActiveControl <> CallerForm.DBGrid then
Close;
end;
The TSearchGridForm is activated by the caller form with .Show (not Modal) and when it is deactivated I want to close/hide it only if the new active control <> CallerForm.DBGrid.
Only if the user clicked on DBGrid on the caller form the search form should remain visible, otherwise I need to close it.
How can I do this?
Delphi's TScreen object has events OnActiveControlChange and OnActiveFormChange. You can set up event handlers for these to monitor changes and react to them.
See the D7 Online Help for more info. There are Delphi VCL code examples of using both events.
How do I get the KeyDown event to work in a Delphi (2007) MDI Applications Parent window, even if a Child window has focus?
I would like to implement a shortcut key (F1) that brings up a help screen in a MDI application, I have added the KeyDown procedure to the MDI Parent window and enabled KeyPreview in both the Parent and Child windows, but it does not work as expected.
If I put a break point in the Parents KeyDown code I can see it never executes, even it there are no child windows open. But if I add the same code to the child window it works fine.
Is there a way to get the parent window to receive the key presses, even if the child window has focus, as adding the code to 25+ forms seams a little wasteful?
I had the exact same problem this week! I fixed it by creating an action in the ActionManager on the mainform. This action opens the help file and has the F1-key set as shortcut. It also works for all MDI child screens.
You could use a local (global is not needed) keyboard hook. You could also derive all your MDI Child forms from a signle form base class and implement it there once. You will find that this design comes in handy for other problems as well.
edit
Application wide hotkeys/shortcuts can also be implemented with the TApplication.OnShortCut event. See http://delphi.about.com/od/adptips2004/a/bltip0904_3.htm
F1 is already the standard help shortcut which triggers TApplication.OnHelp. So maybe you want to use the OnHelp event? And if you use the HelpFile, HelpContext, HelpType and HelpKeyword properties you probably don't even need to implement any code at all.
How do I get the KeyDown event to work in a Delphi (2007) MDI Applications Parent window, even if a Child window has focus?
As a more generic solution (for applications other than F1 for help) I use code similar to this to trap a keydown event in the main form. This gets all keys no matter what, even when an MDI child is active. In this example I'm doing the opposite of what you are trying to do (I want the message to be handled by my child form instead of the main form), but the concept of catching the keys in the parent is the same).
Application.OnMessage := AppMessage;
procedure TMainForm.Appmessage(var Msg: TMsg; var Handled: Boolean);
var
message: TWMKey;
begin
If (msg.message = WM_KEYDOWN) and
( LoWord(msg.wparam) = VK_TAB ) and
(GetKeyState( VK_CONTROL ) < 0 ) and
Assigned( ActiveMDIChild ) then
Begin
Move( msg.message, message.msg, 3*sizeof(Cardinal));
message.result := 0;
Handled := ActiveMDIChild.IsShortcut( message );
End;
end;
F1 help processing is built into Delphi, so all you have to do is handle the help messages properly. This may be as little as setting the helpfile property for the application. You can set particular pages using the form's help??? properties.
Basically, just use the help system supplied and forget keydown. This is Delphi - you don't have to work hard.