Jump to content
Sign in to follow this  
shineworld

Update of Actions in ActionList in a DataModule

Recommended Posts

Hi all,

I'm trying to de-couple the actions lists, with related actions,

from a specific form to a data module.

 

These actions will be used so also in other views without duplicate them in every form.

 

The things work BUT they are not cyclic updated.

The OnActionUpdate is called only when I click on the assigned graphic button (for example),

but I would like that ActionXXX.Enabled si cyclically called as when they are in a form.

 

Some ideas?
Best Regards
Silverio

Share this post


Link to post
Guest

let's see if understand ... my english is bad ok?

image.thumb.png.6dde4072a21c0158481fceac8347ab8e.png

 

type
  TfrmFormMain = class(TForm)
    btn_SetDataModule_To_ActionList: TButton;
    btn_Execute_First_ActionList: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btn_SetDataModule_To_ActionListClick(Sender: TObject);
    procedure btn_Execute_First_ActionListClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  frmFormMain: TfrmFormMain;

implementation

{$R *.dfm}

uses
  uMyDataModule;

procedure TfrmFormMain.btn_SetDataModule_To_ActionListClick(Sender: TObject);
begin
  myDataModule.MyDataSource := myDataModule.dsMyCustomers;
  //
  ShowMessage('myDataModule.MyDataSource := myDataModule.dsMyCustomers'); // if all it's right, of course!
end;

procedure TfrmFormMain.btn_Execute_First_ActionListClick(Sender: TObject);
begin
  myDataModule.ActionList1.Actions[0].Execute;
end;

procedure TfrmFormMain.FormCreate(Sender: TObject);
begin
  myDataModule := TmyDataModule.Create(nil); // or self or application etc... you choice the end!
end;

procedure TfrmFormMain.FormDestroy(Sender: TObject);
begin
  myDataModule.Free;
end;
unit uMyDataModule;

interface

uses
  System.SysUtils,
  System.Classes,
  Data.DB,
  Vcl.DBActns,
  System.Actions,
  Vcl.ActnList,
  Vcl.DBClientActns;

type
  TmyDataModule = class(TDataModule)
    ActionList1: TActionList;
    DatasetFirst1: TDataSetFirst;
    DatasetPrior1: TDataSetPrior;
    DatasetNext1: TDataSetNext;
    DatasetLast1: TDataSetLast;
    DatasetInsert1: TDataSetInsert;
    DatasetDelete1: TDataSetDelete;
    DatasetEdit1: TDataSetEdit;
    DatasetPost1: TDataSetPost;
    DatasetCancel1: TDataSetCancel;
    DatasetRefresh1: TDataSetRefresh;
    dsMyCustomers: TDataSource;
    dsMyOrders: TDataSource;
    procedure DatasetFirst1Execute(Sender: TObject);
    procedure DatasetFirst1Update(Sender: TObject);
  private
    FDataSource: TDataSource;
    function GetDataSource: TDataSource;
    procedure SetDataSource(const Value: TDataSource);
    //
    procedure prcSetDataSourceToDSActionList(lNewDataSource: TDataSource);
  public
    property MyDataSource: TDataSource read GetDataSource write SetDataSource;
  end;

var
  myDataModule: TmyDataModule;

implementation

{%CLASSGROUP 'Vcl.Controls.TControl'}
{$R *.dfm}

uses
  Vcl.Dialogs;

procedure TmyDataModule.prcSetDataSourceToDSActionList(lNewDataSource: TDataSource);
var
  lALContained: TContainedAction;
begin
  if (lNewDataSource = nil) then
    exit;
  //
  // setting all my ActionList for my DataSource binded on my DataSet, in my myDataModule form!
  //
  for lALContained in ActionList1 do // if want use basic: "for i := Low to High do" way!
  begin
    if lALContained.ClassType.InheritsFrom(TDataSetAction) then
    begin
      TDataSetAction(lALContained).DataSource := lNewDataSource;
    end;
  end;
end;

function TmyDataModule.GetDataSource: TDataSource;
begin
  result := FDataSource;
end;

procedure TmyDataModule.SetDataSource(const Value: TDataSource);
var
  lALContained: TContainedAction;
begin
  if (FDataSource <> Value) then
  begin
    FDataSource := Value;
    //
    prcSetDataSourceToDSActionList(FDataSource);
  end;
end;

procedure TmyDataModule.DatasetFirst1Execute(Sender: TObject);
begin
  // what to do ...
  if not(TDataSetAction(Sender).DataSource = nil) and { }
    not(TDataSetAction(Sender).DataSource.DataSet = nil) then
  begin
    ShowMessage(TDataSetAction(Sender).DataSource.Name + ' - ' + TDataSetAction(Sender).DataSource.DataSet.Name);
  end
  else
    ShowMessage('TDataSetAction(Sender).DataSource = nil AND/OR TDataSetAction(Sender).DataSource.DataSet = nil');
end;

procedure TmyDataModule.DatasetFirst1Update(Sender: TObject);
begin
  // what to do ...
end;

end.

 

 

hug

Edited by Guest

Share this post


Link to post

Are you using the OnUpdate events of the individual actions? If so, IIRC, that only gets called if there is a control attached to the action and that control is visible.

Share this post


Link to post

Thanks to all for the support.

I guess to have understood the actions on a data module when linked to the GUI object at design time,

and when programmatically linked to run-time created frames and objects.

 

I've just added an override to IsShortCut in TForm to propagate shortcuts from actions.

 

 


 

actionsinmodule.zip

Share this post


Link to post
Guest

another tip:

for avoid create many codes/many errors, use create a "form-template"  (inherits) for your forms.

Then, you will have a "standard" between your forms, and, if any one needs a special code, stay easy do it!  you see?

 

easy management, easy updates!

Edited by Guest

Share this post


Link to post

Thanks for the suggestion,
I never thought about this option.

I'm an old Delphi programmer (from the first version) but I've increased in lines code and sometimes I've missed the good code planning.

At moment I'm trying to port a project from Delphi 2007 to Sydney.

There are about 1.300.000 code lines a lot of 3th parties libraries (someone to substitute because incompatible with Sydney).

Just a sample of the project (all native Delphi code here ): 

 

Share this post


Link to post

As you've probably discovered then only difference between having the TActionList on a form and having it on a datamodule is that the shortcuts isn't processed. You can see why in TCustomForm.IsShortCut. As far as I can see you can solve that by simply calling TActionList.IsShortCut from your forms OnShortCut event handler.

 

Apart from that, as @PiedSoftware wrote, the TAction.OnUpdate event only gets called when the action isn't suspended and the associated control(s) becomes visible. For example if you have an action linked to a menu item then the action is only updated when the sub menu that contains the menu item is shown. If you have an action linked to multiple controls then the action is updated if just one of them is visible. A classic goof is to update the actions Visible property in the OnUpdate handler and then wondering why the action isn't updated anymore - it's because the associated control has been hidden and hidden control don't cause the action to update.

 

Also if you use the TActionList.OnUpdate handler be aware that it's called once for each and every action in the list. If you just want an OnUpdate handler that called once for every "cycle" then you can create an action and assign it to the form and use that actions OnUpdate instead. You will have to control the form caption through the action though.

Share this post


Link to post
Guest

interessant project!

my tip:

1) eliminated any problem for incompatibility between old prj and Sydney... if necessary search new suites with same resulted.

2) eliminate old way to coding... try adapt it to new way in new IDE. for use the new potential

3) if possible, start a new project... can be better than fix old errors. test in parallel.

4) eliminate excess. minus is more!

5) more impotant!  FOR WHILE RAD 10.4.x it's clock-bomb!  10.3.3 it's more reliable - not at all, of course! and stay 1 step for new IDE.

 

Edited by Guest

Share this post


Link to post
2 minutes ago, emailx45 said:

3) if possible, start a new project... can be better than fix old errors. test in parallel.

Nope.

A rewrite of an old, large and complex system is not something that you just do. The history and literature is full of examples why. Remember Netscape, Lotus 123, etc.?

Share this post


Link to post
Guest

each one is each one!

each case is a case!

bad project manager, will be always with a bad ideas!

then, change it too!

yeah, this works!

the history show this - see when Steve Job was recalled to Apple! Some doubt?

How many times he ask to rewrite codes and code until the perfection (in him vision - w/o intergalactical travels  🙂) was showed.

Edited by Guest

Share this post


Link to post

Thanks for the info, very usefull!


I've already fought a lot (a couple of weeks) with ANSI string used often, in the old 2007 project, as byte storage media (communications, crypt algorithms, data storage, etc).
The use of string (AnsiString) was fine and simple but now had required a lot of checks and changes to work fine and moved to TByteArray or similar classes.


The reasons to move the project to Syndey (or Rio, I've also that) are:


- Memory
- Unicode support
- More updated 3rd parties libraries (as well as GLScene, etc).
- Gestures support

 

Memory

I already use FastMM to extend at maximum 32-bit capabilities.
SynEdit (ansi version) becomes critical when reaches more than 8 million g-code lines (G-Code is the language of CNC).
With FastMM I can reach more than 15 million g-code lines in the same 32-bit OS.
OpenGL graphics also eat a lot of memory (internal data of GLSCene).
With 64 bit available memory should not be a problem to have more memory for the process and threads.

Also the g-code language compiler is hungry for memory.

{$INCLUDE Settings.inc}

// TAKE CARE: If in the project there is an uses of IdComponent this add a critical section in initialization section
//            which will not be delete in finalization code signing for a Critical Section Leak. Don't care about this
//            leak because is wanted by Indy designers. Follow the note in IdComponent.pas:
//
//            initialization
//              GStackCriticalSection := TCriticalSection.Create;
//            finalization
//              // Dont Free. If shutdown is from another Init section, it can cause GPF when stack
//              // tries to access it. App will kill it off anyways, so just let it leak
//              // FreeAndNil(GStackCriticalSection);

// Use this CODE-CHUNK to restore automatically removed, by Project -> Add/Remove..., FastMM uses declaration
//
// {$IFDEF USES_EMBEDDED_FASTMM_MEMORY_MANAGER}
//   {$SetPEFlags $20}
//   {$DEFINE USES_FASTMM}
//   FastMM4 in 'sources\extra\FastMM4\FastMM4.pas',
//   FastMM4Messages in 'sources\extra\FastMM4\FastMM4Messages.pas',
// {$ENDIF}
uses
{$IFDEF USES_EMBEDDED_FASTMM_MEMORY_MANAGER}
  {$SetPEFlags $20}
  {$DEFINE USES_FASTMM}
  FastMM4 in 'sources\extra\FastMM4\FastMM4.pas',
  FastMM4Messages in 'sources\extra\FastMM4\FastMM4Messages.pas',
{$ENDIF}


Unicode support
Market increase and need to support not ANSI languages has come.
I already use dxgettext and .po files (I've modified the gnugettext.pas to work fine with Rio and Sydney).

More updated 3rd parties libraries (as well as GLScene, etc)
GLScene is an incredible OpenGL environment and is grown a lot in recent years.

Unfortunately, the latest compatible version with 2007 is old, very old and missing a lot of interesting things.
I need to move to it 🙂

Gesture support
I would like to fully support the touch screens with gestures management.

 

Edited by shineworld

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×