Implementing Button Click in Firemonkey - delphi

I am missing TButton.Click Method in FireMonkey TButton.
Is there any way to fire click event in the code in fire monkey? If there is no such event, just use the click method to fire the action assigned to the button?

Well, you can simply write:
Button1.OnClick(Button1);
If there is an action attached to the button you can invoke it with
Button1.Action.Execute;
But that is not really to be recommended. The right way to do this is to create a method to do the work. Then call that method from either your OnClick event handler, or the other location in your code that wants to invoke this action. Like this:
procedure TForm1.DoSomething;
begin
// do whatever it is
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DoSomething;
end;
Then anywhere in your code you can just call DoSomething. It's best to leave GUI event handlers just for handling GUI events.

You can use this method :
first declare this new type to access TButton Click procedure :
type
TButtonHack = type TButton;
Then caste your button to TButtonHack class and call Click procedure :
TButtonHack(Button1).Click;

Related

Extend the event OnClick of all MenuItems in the screen to execute another block of code

I want to set an event OnClick to all TMenuItems on the screen to do what the event currently does, and another few lines of code. I am currently using Delphi 5
For example, say that I have a TMenuItem with the code:
procedure TdesktopForm.MenuFoo1Click(Sender: TObject);
begin
ShowMessage(TComponent(Sender).Name)
end;
and I also have the following procedure:
procedure TdesktopForm.bar;
begin
ShowMessage('extra')
end;
And I want to everytime I click the TMenuItem the program show the TMenuItem's name and also the 'extra' message.
The example shown is just a demonstration of my problem, as in the real software I have over 300 menu items, I want to do this generically, so I won't have to add extra lines of code to all current menu clicks, nor add them when I add new menu items. The order of execution (between the menu click and the extra block of code) doesn't matter.
I tried using TActionList but I couldn't retrieve the object triggering the action, hence, I can't print it's name. I tried using ActiveControl but it always return the focused currently focused object, not the actual menu that I clicked. And also, the TAction execute event overwrites my TMainMenu.OnClick event
As long as all your event handlers are assigned at some point (either at design time or at run time) and don't change afterwards, you can do something like this:
Enumerate all menu items in the menu
For each create an object like the one described below
type
TEventInterceptor = class(TComponent)
private
FOrigEvent: TNotifyEvent;
FAdditionalEvent: TNotifyEvent;
procedure HandleOnClick(_Sender: TObject);
public
constructor Create(_MenuItem: TMenuItem; _AdditionalEvent: TNotifyEvent);
end;
constructor TEventInterceptor.Create(_MenuItem: TMenuItem; _AdditionalEvent: TNotifyEvent);
begin
inherited Create(_MenuItem);
FOrigEvent := _MenuItem.OnClick;
FAdditionalEvent := _AdditionalEvent;
_MenuItem.OnClick := HandleOnClick;
end;
procedure TEventInterceptor.HandleOnClick(_Sender: TObject);
begin
FOrigEvent(_Sender);
FAdditinalEvent(_Sender);
end;
Note that this code is completely untested and may not even compile.
I'm also not sure whether this works with Delphi 5. It does with Delphi 6 though, so chances are good.
Edit:
Some additional notes (thanks for the comments):
Inheriting this class from TComponent makes the form free it automatically when it is being destroyed.
HandleOnClick should possibly check if FOrigEvent is assigned before calling it.

How to execute an ActionList item from a TListViewItem

I'm trying to execute an action (TakePhotoFromCameraAction) in a TActionList, when a TListViewItem is selected.
Neither TlistView nor TListViewItem have an Action property, so I've tried calling ActionList[0].Execute in the event, but nothing happens.
Any ideas?
Further:
The code is very simple, as it was just a test for this problem. I was focussing on the ActionList as that was what I will use (when I sort it out).
Button1 doesn't work (it always fails, even when button 2 doesn't), whereas the (new) Button2 does work OK.
type
TForm1 = class(TForm)
ActionList1: TActionList;
Memo1: TMemo;
TakePhotoFromCameraAction1: TTakePhotoFromCameraAction;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.fmx}
procedure TForm1.Button1Click(Sender: TObject);
begin
ActionList1[0].Execute;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if TakePhotoFromCameraAction1.Execute
then
Memo1.Lines.add('Photo OK')
else
Memo1.Lines.add('Photo Fail');
end;
You can use good old tag property of TListViewItem to store pointer to TAction you want to use with this item. Of course, you can't set it in object inspector, but can do it programmaticaly in TForm.onCreate event or some other convenient place. It has type NativeInt which has the same size as pointer be it 32-bit or 64-bit architecture, so it should work properly.
Something like this:
//in formCreate or other place to initialize actions:
TakePhotoItem.Tag:=NativeInt(TakePhotoFromCameraAction);
SavePhotoItem.Tag:=NativeInt(SavePhotoAction);
//...
//onitemchange event handler
if AItem.Tag<>0 then
TAction(AItem.Tag).Execute;
Maybe it's better to introduce your own descendant of TListViewItem which has Action property, that way you'll have to populate your listview in code only, adding not basic TListViewItem, but TActionListViewItem (name of your class), that has more work to do but will yield more understandable code.
There is no difference (except being ugly) to call ActionList1[0].Execute; versus Action1.Execute;.
You didn't show the the .fmx file so I can't know what linkage you may have setup between the components, but, it seems you haven't assigned anything to the actions OnExecute event, and therefore do not get the expected response to the Execute call.
The FMX Version of the documentation is not very clear, but the VCL version is (IMO) better (In a brief test I don't see any difference in actual functionality):
From documentation :
Responds when a client control "fires".
Execute is called automatically when a client control "fires" (for
example, when the user clicks a button or selects a menu item). It
returns True if an event handler is found to handle the action, False
if there was no event handler or if the action was not enabled.
but you can ofcourse also call Execute directly as you tried. And further
Execute first ensures that the action is updated. Then, if the Enabled
property is True, it attempts to handle the action by generating an
OnExecute event on the action list that contains this action (if the
action belongs to an action list). If the action list's OnExecute
event handler does not handle the action, Execute generates an
OnActionExecute event on the application itself. If neither the action
list nor the application handles the action in response to these
events, Execute generates an OnExecute event on itself. If this action
has no OnExecute event handler, Execute instructs the application to
locate the current target control and call the ExecuteTarget method,
which is the mechanism by which predefined action classes perform
their function.
Note that you can handle the actions in TActionList.OnExecute or in the TAction.OnExecute

execute an event but the coding from my own class [duplicate]

I have one button on my form. Following is the click event of that button
procedure Form1.btnOKClick(Sender: TObject);
begin
//Do something
end;
This event will be called only when I click the button, right?
How can I call this event automatically without any user intervention?
The best way to invoke the OnClick event handler attached to a control is to call the Click method on the control. Like this:
btnOK.Click;
Calling the event handler directly forces you to supply the Sender parameter. Calling the Click method gets the control to do all the work. The implementation of the windows message handler for a button click calls the Click method.
But I second the opinion expressed in whosrdaddy's answer. You should pull out the logic behind the button into a separate method.
Do not put your businesslogic into event handlers. This will make your code unreadable when the application grows larger.
Normally you would do this:
procedure TForm1.DoSomething;
begin
// do something
end;
procedure TForm1.btnOKClick(Sender: TObject);
begin
DoSomething;
end;
then all you need to do is call DoSomething from other parts in your code
You can call this event in code like any other method.
...
btnOkClick(Self.btnOk); // Sender in this case is the btnOk
...
The Sender can be whatever object you like or nil.

How to intercept user defined message twice?

I'm using a component that internally has a KeyDown handler, which sends a user defined PostMessage(WM_GROUPUNGROUP), and also has a custom message handler to handle WM_GROUPUNGROUP.
I want my app to do something after this message handler has executed, without modifying the component code.
(How) Can this be done?
One way to achieve this is via the WindowProc property.
Simply supply your own window procedure by assigning to WindowProc on the instance you want to hook. You'll need to take a copy to the previous value of WindowProc so that you can make sure that the original handling is carried out.
Roughly it goes like this:
type
TMyClass = class
....
FOldWindowProc: TWndMethod;
procedure NewWindowProc(var Message: TMessage);
....
end;
To redirect the window procedure you do this:
FOldWindowProc := SomeControl.WindowProc;
SomeControl.WindowProc := NewWindowProc;
Then implement the new window procedure like this:
procedure TMyClass.NewWindowProc(var Message: TMessage);
begin
FOldWindowProc(Message);
if Message.Msg = WM_GROUPUNGROUP then
....
end;
When you are done with the control, put the old window procedure back in place:
SomeControl.WindowProc := FOldWindowProc;
Another way to do it is to take advantage of the fact that the message is queued. You can add an Application.OnMessage handler, most likely by using a TApplicationEvents object. This will get a look at all queued messages. However, OnMessage fires before the message is dispatched to the control which sounds like it may be the wrong way round for you.

How to call events in delphi without user intervention?

I have one button on my form. Following is the click event of that button
procedure Form1.btnOKClick(Sender: TObject);
begin
//Do something
end;
This event will be called only when I click the button, right?
How can I call this event automatically without any user intervention?
The best way to invoke the OnClick event handler attached to a control is to call the Click method on the control. Like this:
btnOK.Click;
Calling the event handler directly forces you to supply the Sender parameter. Calling the Click method gets the control to do all the work. The implementation of the windows message handler for a button click calls the Click method.
But I second the opinion expressed in whosrdaddy's answer. You should pull out the logic behind the button into a separate method.
Do not put your businesslogic into event handlers. This will make your code unreadable when the application grows larger.
Normally you would do this:
procedure TForm1.DoSomething;
begin
// do something
end;
procedure TForm1.btnOKClick(Sender: TObject);
begin
DoSomething;
end;
then all you need to do is call DoSomething from other parts in your code
You can call this event in code like any other method.
...
btnOkClick(Self.btnOk); // Sender in this case is the btnOk
...
The Sender can be whatever object you like or nil.

Resources