Recent

Author Topic: Sending local data to a TAction defined in another unit  (Read 1298 times)

magu

  • New Member
  • *
  • Posts: 37
Sending local data to a TAction defined in another unit
« on: May 18, 2020, 11:52:35 pm »
I am wondering whether there is a better solution to send local variables to an Action defined in another unit then the following:

I am currently trying to share a set of actions across a number of different forms.
The difficulty I face is to send the relevant data to the action: in my situation I want to ensure that the action receives the value of the current row in a particular dataset and the action will take place on that value.

I have come up with the following method which is to create an event in the datamodule that is then assigned to a procedure in the calling form, in the following manner:

Data module holding actions:

Code: Pascal  [Select][+][-]
  1. unit actions.contacts;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, ActnList
  9.   , Dialogs;
  10.  
  11. type
  12.  
  13.   TActionParameter = procedure(var aStrParam:string) of object;
  14.  
  15.   { Tcln_actions }
  16.   Tcln_actions = class(TDataModule)
  17.     Trial: TAction;
  18.     ActionList1: TActionList;
  19.     procedure TrialExecute(Sender: TObject);
  20.   private
  21.  
  22.   public
  23.     OnGetActionParameter :  TActionParameter;
  24.     Function GetClientNumber : string;
  25.   end;
  26.  
  27. var
  28.   cln_actions: Tcln_actions;
  29.  
  30. implementation
  31.  
  32. {$R *.lfm}
  33.  
  34. { Tcln_actions }
  35.  
  36. procedure Tcln_actions.TrialExecute(Sender: TObject);
  37. begin
  38.   showMessage(GetClientNumber);
  39. end;
  40.  
  41. function Tcln_actions.GetClientNumber: string;
  42.   var x : string;
  43. begin
  44.   x := '';
  45.   if Assigned(OnGetActionParameter) then // tests if the event is assigned
  46.   begin
  47.      OnGetActionParameter(x); // calls the event.
  48.   end;
  49.   result := x;
  50. end;
  51.  
  52. end.
  53.  

The main form will then assign a local procedure to 'OnGetActionParameter' so as to define the data to be sent to the action. While the action 'cln_actions.Trial' is assigned to whichever gui element necessary (eg a menu item).

Code: Pascal  [Select][+][-]
  1. uses
  2.         ..., actions.contacts, ...
  3.  
  4. Type
  5.         ...
  6.         procedure SendParameter(var Something:string);
  7.                
  8. <Create Form or Show Form>
  9.   cln_actions.OnGetActionParameter:= @SendParameter;
  10.  
  11. ...  
  12.  
  13. procedure TForm.SendParameter(var Something: string);
  14. begin
  15.   Something := 'hello there!';
  16. end;    
  17.  

And ideas would be helpful

jamie

  • Hero Member
  • *****
  • Posts: 7660
Re: Sending local data to a TAction defined in another unit
« Reply #1 on: May 19, 2020, 03:11:30 am »
If I understand you correctly...

You have several forms you wish to receive notification of some action that took place in a single component, like a database etc... ?

 This is what I would do..
 
   In the module have a FormRegister function where as you can add the form to it as part of a list of forms that get notified when something happens..

 So this means you should have  aTlist object holding your forms some class that can receive messages.
 
 And for each form that is expected to receive a notice you should implement a Message handler.
 This message would be a user message because any others that are not standard will get filtered..

 LM_USER+?  so pick a value for example LM_USER+1; or use a constant.
LM_USER+DataBaseHasSomething;

 So when this message arrives to each form it will handle it and the most respective operation would be to query the database in the data module etc... basically this would be a trigger action.

 The Data module does not need to include all the forms in the users list because if you tried you most likely would have compiling issues..

 So these are the steps

 1. Make a form Register function in the Module, this will add the form to the list..

 2. When ever the data base needs to notify these forms, it will do so but using POSTMessage to each form via the standard handle method. This is why you need the list of forms registered.

 3. Each form in turn will process this message and its a USER message of course..

These messages can contain optional data to …

 all you need to do is include the Data Module in every form unit.. so that it can register itself during the Create process. for that, You can use the OnCreate of each form.

 Also make sure you pay close attention to the creation order for the Module, it must be created first before any form.

 Am I on the track of your thinking ?
The only true wisdom is knowing you know nothing

cdbc

  • Hero Member
  • *****
  • Posts: 2723
    • http://www.cdbc.dk
Re: Sending local data to a TAction defined in another unit
« Reply #2 on: May 19, 2020, 05:42:26 am »
Hello
Why don't you have a look at the observer pattern built into fpc ie.:
Code: Pascal  [Select][+][-]
  1. { ---------------------------------------------------------------------
  2.   Free Pascal Observer support
  3.   ---------------------------------------------------------------------}
  4.  
  5.  
  6. Const
  7.   SGUIDObserved = '{663C603C-3F3C-4CC5-823C-AC8079F979E5}';
  8.   SGUIDObserver = '{BC7376EA-199C-4C2A-8684-F4805F0691CA}';
  9.  
  10. Type
  11.   // Notification operations :
  12.   // Observer has changed, is freed, item added to/deleted from list, custom event.
  13.   TFPObservedOperation = (ooChange,ooFree,ooAddItem,ooDeleteItem,ooCustom);
  14. {$INTERFACES CORBA}
  15.  
  16.   { IFPObserved }
  17.  
  18.   IFPObserved = Interface [SGUIDObserved]
  19.     // attach a new observer
  20.     Procedure FPOAttachObserver(AObserver : TObject);
  21.     // Detach an observer
  22.     Procedure FPODetachObserver(AObserver : TObject);
  23.     // Notify all observers of a change.
  24.     Procedure FPONotifyObservers(ASender : TObject; AOperation : TFPObservedOperation; Data : Pointer);
  25.   end;
  26.  
  27.   { IFPObserver }
  28.  
  29.   IFPObserver = Interface  [SGUIDObserver]
  30.     // Called by observed when observers are notified.
  31.     Procedure FPOObservedChanged(ASender : TObject; Operation : TFPObservedOperation; Data : Pointer);
  32.   end;
  33. {$INTERFACES COM}
  34.  
  35.   EObserver = Class(Exception);
  36.  
This snippet, you can find in "classesh.inc".
All you need to do is implement the observer method in each of your units, and the observed-methods in your data-module.... ;)
Works like a charm :o)
Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

magu

  • New Member
  • *
  • Posts: 37
Re: Sending local data to a TAction defined in another unit
« Reply #3 on: May 19, 2020, 04:19:50 pm »
Not exactly. What I am trying to do is define my Tactions in one central area (a data module) and then call them from various forms. So the Actions need to receive the references to the dataset for the processing to take place. [Eg. one action would be to 'tag' a table row for future reference].

One solution would be to include the forms which use these Tactions in the implemenation area of the datamodule (so the Taction has access to the methods and properties of these forms) however the data may come from different sources: one form would have a dbgrid where the row is selected another would not have a dbgrid but other controls: given that at the end of the day you are carrying out the same action in both forms I am trying to centralise the actions so as to exclude repetition.

That said what you both suggest is all very interesting but these suggestions do go slightly above my head - i'll try doing some reading on them to understand them better.

 

TinyPortal © 2005-2018