CRO_Tomislav 0 Posted yesterday at 07:06 AM I need a help. If I make a project with one form and two units a showed basic code is working ok. unit Prva; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Mask, Vcl.ExtCtrls, Vcl.DBCtrls; type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses Druga; {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin Druga.Demo; end; end. unit Druga; interface uses Dialogs; function Demo:boolean; implementation uses Prva; function demo: boolean; begin ShowMessage(Form1.Edit1.Text); end; end. If I press a button on Form1 it run function in Druga.pas and show message with a text filled in Edit1 component. The problem is If I try to do the same thing with a Form and units which are in dynamic loaded bpl package. It doesn’t work. It seams that it can’t found a Form or component by its name… How to solve this? THX in advance Share this post Link to post
Lars Fosdal 1859 Posted 22 hours ago I would decouple the action by having a handler. unit Druga; interface uses Dialogs; function Demo:boolean; type TOnShowMessage = reference to procedure; var OnShowMessage: TOnShowMessage; implementation // No circular ref here function demo: boolean; begin if Assigned(OnShowMessage) then OnShowMessage else raise Exception.Create('Someone forgot to set the OnShowMessage handler'); end; initalization OnShowMessage := nil; end. In Prva, I'd connected the handler in f.x. FormCreate; procedure TForm1.FormCreate(sender: TObject); begin Druga.OnShowMessage(Self.MyShowMessage); end; procedure TForm1.MyShowMessage; begin ShowMessage(Form1.Edit1.Text); end; This avoids the circular unit ref, and since you initialize the handler from the main form, it shouldn't matter if the bpl is dynamically loaded? If you want to, you can of course also add parameters to the handler to display a text generated in unit Druga or have multiple handlers for different uses. Share this post Link to post
CRO_Tomislav 0 Posted 22 hours ago This is intrested but; Exactly my goal is: I inherited a project in Delphi which has a huge units with a lot of code. Mostly of that code is used to create some XML files. Idea is to separate from this unit a code which is generate this XML files to separate units. But for do that I need to access from this (sub)units to Form and grab query results to populate this XML files or even modify and run a querys As this is doesn’t work "ProfileID.Text := Form1.Query_User.FieldByName('userID').AsString;" in a (sub)unit; do You have some idea what would be elegant solution for this? Share this post Link to post
Lajos Juhász 322 Posted 21 hours ago You can send the query as a parameter to the function that generates the XML. Share this post Link to post
CRO_Tomislav 0 Posted 20 hours ago (Sub)Unit2 doesn't know for Form1 in code: ProfileID.Text := Form1.Query_User.FieldByName('userID').AsString; As my form is opened from package by menue item in Main form by: procedure TForm_Maom.Button1Click(Sender: TObject); var AClass :TFormClass; begin if not IsMDIChildOpen(Form_Glavna,'Form1') then begin if PackageModule <> 0 then begin AClass := TFormClass(GetClass('TForm1')); if AClass <> nil then TComponentClass(AClass).Create(Self); end; end; end; Share this post Link to post
Pat Foley 54 Posted 18 hours ago One thing about XML is on a treeview each node needs a unique caption so as tabSheets or the parent of control wanted are added a number is added to the node's caption as the forms are added. Second thing is the Control could have data reference added. type // On the UI controls side carry some data references for convenience // the data side could use Dependance Injection to tie in UI controls TDataButton = class(TButton) Form: TControl; Strs: TStrings; end; What's neat about MDI you can create a new childform inside a begin..end. To access the form elsewhere use Application.Screen Share this post Link to post
CRO_Tomislav 0 Posted 18 hours ago 15 minutes ago, Pat Foley said: One thing about XML is on a treeview each node needs a unique caption so as tabSheets or the parent of control wanted are added a number is added to the node's caption as the forms are added. Second thing is the Control could have data reference added. type // On the UI controls side carry some data references for convenience // the data side could use Dependance Injection to tie in UI controls TDataButton = class(TButton) Form: TControl; Strs: TStrings; end; What's neat about MDI you can create a new childform inside a begin..end. To access the form elsewhere use Application.Screen XML is not a problem, Accessing to Quer1 on MDI Form1 is a problem... Can You provide me an example for Application.Screen to access a Query1 on a MDI form Form1? Share this post Link to post
Lars Fosdal 1859 Posted 18 hours ago Isolate your business logic from the UI. Use an intermediate class to pass the data around. 1 Share this post Link to post
Pat Foley 54 Posted 18 hours ago This should yield control asked for. procedure TTaskMaster.findControl(AtaskDetail: TInstruction; var AC: TControl); var ff, ii : integer; sForm, sControl: string; begin with AtaskDetail do begin if Control <> nil then AC := Control else begin sForm := controlForm + ' not found.'; sControl := controlName + ' not found.'; //screens move about on windows list top window usually 0 :( for ff := 0 to Screen.FormCount - 1 do if Screen.Forms[ff].name = controlform then begin sform := controlForm; with Screen.Forms[ff] do begin for ii := 0 to componentcount - 1 do if Components[ii].Name = ControlName then begin sControl := controlName + ' comps ' + ii.ToString; Control := Components[ii] as Tcontrol; //onBS(False, format('Item %d Found %s',[ii,controlName])); break; end //else//if name //run := false; // onBS(False, format('Item %d not found %s',[ii, controlName])); end;// with screen forms end; //if screen.forms onBS(False, sForm + ' ' + sControl); end;// else end;//with taskdetail end; What TInstruction is TInstruction = class //position in Db Atom: PAtom; Control: TControl; ControlForm: string; //3 ControlName: string; //2 Description: string;//6 //Nu: integer; //0 Kind: string; //1 was integer KindNU: integer; referenceValue: Double;//5 tagName: string; //4 tagValue: Double; //no data in table end; Share this post Link to post
Pat Foley 54 Posted 17 hours ago You might to study and use this to move cursor to control being selected. I want to add it to IDE <F6> or <Ctrl>. function it only jumps to selection without any animation 🙂 procedure TTaskmaster.moveMouse(AtaskDetail: TInstruction); var x, y, MouseXError, MouseYError: integer; ControlCenter: Tpoint; AC: TControl; begin findControl(AtaskDetail, AC); if not assigned(AC) then exit; if assigned(AC.Parent) then AC.Parent.Show; AC.Show; x := AC.ClientOrigin.X + AC.width div 2; y := AC.ClientOrigin.y + AC.height div 2; begin MouseXError := round(1.12 *(x - mouse.CursorPos.X)); MouseYError := round(1.12 * (y - mouse.cursorPos.y)); // MouseXError := min(MouseXError, 10 * sign(MouseXError)); // MouseYError := min(MouseYError, 10 * sign(MouseYError)); controlCenter.X := mouse.CursorPos.x + MouseXError; controlCenter.Y := Mouse.CursorPos.y + mouseYError; mouse.CursorPos := ControlCenter; end; repeatTask := (abs(MouseXError) > 7) or (abs(MouseYError) > 7); end; Share this post Link to post