shineworld 73 Posted December 27, 2020 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 Posted December 28, 2020 (edited) let's see if understand ... my english is bad ok? 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 December 28, 2020 by Guest Share this post Link to post
PiedSoftware 3 Posted December 28, 2020 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
shineworld 73 Posted December 29, 2020 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 Posted December 29, 2020 (edited) 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 December 29, 2020 by Guest Share this post Link to post
shineworld 73 Posted December 29, 2020 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
Anders Melander 1784 Posted December 29, 2020 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 Posted December 29, 2020 (edited) 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 December 29, 2020 by Guest Share this post Link to post
Anders Melander 1784 Posted December 29, 2020 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 Posted December 29, 2020 (edited) 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 December 29, 2020 by Guest Share this post Link to post
shineworld 73 Posted December 29, 2020 (edited) 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 December 30, 2020 by shineworld Share this post Link to post