Page 1 of 2 12 Last
  • Jump to page:
    #1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1

    How to transfer current value on another form at Delphi ?


    I have DBAdvGrid on Form1, There is another form Form2 in order to edit current record at DBAdvGrid.

    On Form1 there is a function named UniQuery1.AfterScroll in order to get current record value from DBAdvGrid.

    procedure TFrmMain.UniQuery1AfterScroll(DataSet: TDataSet);
    begin
    labelpub := Form1.FrmMain.DBAdvGrid1.DataSource.DataSet.FieldByName('label').AsString;
    idpub := Form1.FrmMain.DBAdvGrid1.DataSource.DataSet.FieldByName('id').Value;
    end;
    How to pass this value idpub and labelpub on another Form depending on the current record ?
  2. #2
  3. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    The situation, as I understand, is that when the user scrolls to a new record on the current form, you want another form to be notified of the action, so it can sychronize to the same record. A big problem I see with this approach is if the user where to close that 2nd form, when you attempt to send the new values (when the dataset is scrolled) to a now non-existant form, you are going to generate an access violation. If you implement something like this, you'll have to ensure that the 2nd form isn't closed while the first form is available, and that the first form closes the 2nd form when it closes.

    Another approach is to create the 2nd form when the user signals he wants to edit the record (via a button press or some other approach), so the 2nd form is created specifically for the one record he wants to make changes to, and closed when the edits are done.

    Please reply with the approach you prefer, and I'll try to help...
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    Second form is already created and exists in project group , it is not being created dynamically after clicking on edit button , in this case how to achieve output.

    You are right I am getting access violation error and need to ensure that second form is not closed.

    I wrote something like ub UniQuery Scroll function but access violation error persists

    labelpub := Form1.FrmMain.DBAdvGrid1.DataSource.DataSet.FieldByName('label').AsString;

    if form2.editrec.Active then
    form2.editrec.Label1.Caption := labelpub;
    Last edited by ninadgac; January 23rd, 2014 at 01:00 PM.
  6. #4
  7. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    Well, you can simply not create the 2nd form, with your application loaded in Delphi's IDE, select Project | Options | and select Forms in the left panel. Select your 2nd form in the Auto Create Forms List and Move it to the Available Forms list. Now your application will no longer auto create this form.

    Then you can create the form as needed dynamically. I'd recommend to define a new constructor, passing in the information needed to initialize the 2nd form.

    UPDATE
    Code:
    if form2.editrec.Active then
    This too would generate an access violation. You are accessing Form2 (if form2.....) when form2 does not exist - thus the access violation.
    Last edited by majlumbo; January 23rd, 2014 at 01:17 PM.
  8. #5
  9. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    IS there any way to check whether form is not created before in order to avoid multiple creation ?

    I tried with create using
    Form2 := TFrom2.Create(nil);

    but it hangs the application
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    if not Assigned(Form2)
    Form2 := TFrom2.Create(nil);

    But it hangs application while loading

    When created form only in edit button click event it gives Access Violation error while when it created at UniQuery Scroll event it is hanging application while loading.
    Last edited by ninadgac; January 23rd, 2014 at 02:14 PM.
  12. #7
  13. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    Originally Posted by ninadgac
    if not Assigned(Form2)
    Form2 := TFrom2.Create(nil);

    But it hangs application while loading

    When created form only in edit button click event it gives Access Violation error while when it created at UniQuery Scroll event it is hanging application while loading.
    OK, I was really trying to steer you away from leaving the 2nd form open all the time, but if you prefer to have both forms open continuously, then here are a few steps to get you started.

    In Form1 (the form with the DBAdvGrid on it), you need to add Form2's unit to the uses clause.

    You can either auto create form 2, or dynamically create form2 in Form1's onCreate method (I'd prefer option 2 - so leave Form2 in the Available Forms list)

    In Form1's OnCreate method open Form2 (first declare a variable in your form's Private section (if you don't have a private section, add it)
    Code:
    uses ..., Form2Unit;
    
    ...
    
    TForm1 = class(TForm)
    ..
    Private
       ChildForm: TForm2;
    Public
      ..
    end;
    
    TForm1.FormCreate(Sender: TObject);
    begin
       ChildForm := TForm2.Create(Application);
       ChildForm.Show;
    end;
    That creates form2. Now in form2, you need to ensure that the form gets freed when it closes, so modify Form2's OnClose Method
    Code:
    TForm2.FormClose(Sender: TObject; Action: TCloseAction);
    begin
       Action := caFree;
    end;
    that takes care of freeing the memory when Form2 is closed.

    Now you want to add a new method to Form2, and this is important, it needs to be added to Form2's "Public" section
    Code:
    TForm2 = class(TForm)
      ...
      Public
        procedure NewRecordData(const LabelVal: String; IDVal: Integer);
    end;
    now you need to actually write the code for the new procedure
    Code:
    procedure Tform2.NewRecordData(const LabelVal: String; IDVal: Integer);
    begin
      labelpub := LabelVal;
      idpub := IDVal;
    end;
    Now you can call that method from Form1 from the afterscroll
    Code:
    procedure TForm1.UniQuery1AfterScroll(DataSet: TDataSet);
    begin
       if Assigned(ChildForm) then
       begin
          ChildForm.NewRecordData(DBAdvGrid1.DataSource.DataSet.FieldByName('label').AsString, DBAdvGrid1.DataSource.DataSet.FieldByName('id').AsInteger);
       end;
    end;
    you still have the issue of not allowing Form2 to close, but get this working first, then we can work on that part
    Last edited by majlumbo; January 24th, 2014 at 01:21 PM.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    Everything works it passes the value perfectly to the second form but there is still one issue is that whenever we closes second form it never actually unassigns/frees second form though we have code written there in 2nd form's close event as Action := caFree; is not effecting.

    As after closing 2nd form if I clicked again on edit button(which is supposed to open 2nd form) it gives Access Violation error message.
  16. #9
  17. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    Originally Posted by ninadgac
    Everything works it passes the value perfectly to the second form but there is still one issue is that whenever we closes second form it never actually unassigns/frees second form though we have code written there in 2nd form's close event as Action := caFree; is not effecting.

    As after closing 2nd form if I clicked again on edit button(which is supposed to open 2nd form) it gives Access Violation error message.
    I made a small change, not sure if you saw it. Specifically, I changed the creation of the 2nd form in the OnCreate of the first form to:
    Code:
    TForm1.FormCreate(Sender: TObject);
    begin
       ChildForm := TForm2.Create(Application);
       //was ChildForm := TForm2.Create(nil);
       ChildForm.Show;
    end;
    So, your 2nd form, I thought you didn't want to be able to close it while the first form is open.... But regardless, how are you closing it? The code "Action := caFree;" doesn't close the form, it simple releases the memory when the form is closed. If you put a button on the form, and code its OnClick handler like so:
    Code:
    procedure TForm2.BitBtn1Click(Sender: TObject)
    begin
       Close;
    end;
    That will close the form. I wouldn't worry too much about this last part just yet. Since you want to be able to keep the 2nd form open for the entire lifetime of the first form, we're going to add code to not allow the user to independently close the 2nd form, but to automatically close it when the first form closes.
    Last edited by majlumbo; January 25th, 2014 at 07:18 PM.
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    OK, here's the code to not allow the 2nd form to close
    Code:
    TForm2 = class(TForm)
      ..
      procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
      //add OnKeyDown procedure using the object inspector with form selected
      procdure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
      //add OnCloseQuery again from object inspector with form selected
    private
      AllowClose: Boolean;<--Add Boolean
      procedure DisableCloseButton;<--Add this new procedure to Private Section
    public
      procedure NewRecordData(const LabelVal: String; IDVal: Integer);
      procedure ParentClose;//<--Add this new procedure to Public Section
      ..
    end;
    
    procedure TForm2.FormCreate(Sender: TObject);
    begin
       AllowClose := False;
       KeyPreview := True;//you can also set this property in the object inspector with the form selected
       DisableCloseButton;//Call procedure to disable close button
    end;
    
    procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
       if ((ssAlt in Shift) and (Key = VK_F4)) then
          Key := 0;
    end;
    
    procedure TForm2.DisableCloseButton;
    var
       hSysMenu:  THandle;
    begin
       hSysMenu := GetSystemMenu(Handle, false);
       EnableMenuItem(hSysMenu, SC_CLOSE, MF_BYCOMMAND or MF_GRAYED)
    end;
    
    procedure TForm2.ParentClose;
    begin
       AllowClose := True;
       Close;
    end;
    
    procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
       //this procedure should be enough to ensure it doesn't close
       //but the first one (formKeyDown) disable Alt-F4 which is a
       //keyboard shortcut to close the form and
       // the 2nd (DisableCloseButton) disables the X in the upper
       // right corner of the form, so the user can't use it to close
       CanClose := AllowClose;
    end;
    and from Form1, you simply call Form2's Public ParentClose method from Form1's OnDestroy method.

    Code:
    procedure TForm1.FormDestroy(Sender: TObject);
    begin
       if Assigned(ChildForm) then
          ChildForm.ParentClose;
    end;

    Comments on this post

    • ninadgac agrees
  20. #11
  21. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    Actually Form 2 allow to close. Form 2 is there for Edit purpose only. After editing done user can close it.

    Below is Form1 DBAdvGrid1



    After selection of record and right clicked a popup menu will appear as shown in fig 1, When Edit Play clicked Form 2 Edit window will appear as shown in figure below



    Problem is that suppose at 1st time we selected Record No 6 from DBAdvGrid of Form1 , right clicked for Pop Up menus and clicked on Edit then 2nd Form - Edit window will appear. After editing record we generally closes form 2. Problem lies here when Form 2 is closed it is just hiding form 2, it is not completely destroying it or freeing memory (even though we have written code in Form2 close event). Due to which if we clicked 2nd times on Edit popup menu on Form1 it simply gives 'Access Violation' error. Because Form2 in actual open (not in visual sense).
  22. #12
  23. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    OK, changes course a bit, so you do want to close Form2 after each edit... That goes back to my first post to you asking which approach you prefer (leaving Form2 open all the time ready to receive information from Form1 -which can cause access violations if Form2 is closed, or to open a new Form2 for each edit - The method I was trying to steer you toward).

    So now the premise is that when you open Form2, you do so for the one record selected on Form1. You save or cancel those changes, close Form2, and then when you move to a new record on Form1, you can initiate edits opening a new Form2. The Form2 instance you have open can only work on that one record, (it does NOT receive information about the newly selected record on Form1 as you move from record to record on Form1).

    Let me know if that's correct...
  24. #13
  25. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    So now the premise is that when you open Form2, you do so for the one record selected on Form1. You save or cancel those changes, close Form2, and then when you move to a new record on Form1, you can initiate edits opening a new Form2. The Form2 instance you have open can only work on that one record, (it does NOT receive information about the newly selected record on Form1 as you move from record to record on Form1).

    When I open Form 2 by selecting record on Form 1 (with right click pop menu -> Edit) for the first time, it opens without any error. After edit or cancel when I goes to back to Form 1 and then again if I tried to edit new record for second time then I receives "Access Violation Error".
  26. #14
  27. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2008
    Posts
    354
    Rep Power
    7
    Originally Posted by ninadgac
    When I open Form 2 by selecting record on Form 1 (with right click pop menu -> Edit) for the first time, it opens without any error. After edit or cancel when I goes to back to Form 1 and then again if I tried to edit new record for second time then I receives "Access Violation Error".
    My last post was asking if the process I detail is what you are expecting... I wanted to make sure of this before going forward...

    as to why you may be getting the access violation error. More than likely you still have Form2 in the AutoCreate List and are "showing" the form the first time. Because it was Autocreated by your application, it is there to show, but when you close it (you've coded it to Free itself), the form no longer exists, so when you want to Show it again, it gives you the access violation.

    So if the process I detailed is in fact the behavior you expect, then the steps forward from here:

    1) Remove Form2 from the autocreate list (I've explained how to do that in an earlier post). That means your application will not autocreate the form, it'll be up to you to code the creation of the form every time you need it (see below).

    2) You'll need to clean out any of the code I've already given you since it no longer applies.

    3) You're going to define a new constructor for Form2, and in that constructor, you are going to accept the values you want to pass Form2.

    in Form2's declaration add the new constructor and add two variables to hold the data you want to pass it.
    Code:
    TForm2 = class(TForm)
     ...
      procedure FormClose(Sender: TObject; Action: TCloseAction);
      procedure FormCreate(Sender: TObject);
    private
      fLabelpub: String;
      fIDpub: Integer;
    public
      constructor CreateWithParameters(AOwner: TComponent; const LabelPub: String; idpub: Integer);
    end;
    
    .....
    
    constructor TForm2.CreateWithParameters(AOwner: TComponent; const LabelPub: String; idpub: Integer);
    begin
      inherited Create(AOwner);
      fLabelpub := Labelpub;
      fIDpub := IDpub;
    end;
    
    procedure TForm2.FormClose(Sender: TObject; Action: TCloseAction);
    begin
      Action := caFree;
    end;
    
    procedure TForm2.FormCreate(Sender: TObject);
    begin
      //do something here with fLabelPub and fIDPub.
    end;
    Now Form2 has the values in fLabelpub and fIDpub when it is created. And to create it from Form1, Add Form2's unit name to Form1's uses clause, and use the new constructor
    Code:
    TForm1.procedure EditPlay1Click(Sender: TObject);
    var
      EditForm: TForm2;
    begin
      //assuming the EditPlay menu item is where you want to open form2 if not just change to where you do want
      EditForm := TForm2.CreateWithParameters(<your LabelPub Value>, <Your IDPub Value>);
      EditForm.Show;
    end;

    Comments on this post

    • ninadgac agrees
  28. #15
  29. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Oct 2013
    Posts
    42
    Rep Power
    1
    Form 2 is not in the Auto Create list , it is in the list of available forms.


    Code:
    EditForm := TForm2.CreateWithParameters(<your LabelPub Value>, <Your IDPub Value>);
      EditForm.Show;
    At this segment what the value should be passed for TComponent parameter? As I am getting error 'Incompatible types TComponent and String'
    Last edited by ninadgac; January 31st, 2014 at 04:26 AM.
Page 1 of 2 12 Last
  • Jump to page:

IMN logo majestic logo threadwatch logo seochat tools logo