Solved

How to communicate date from a Child Form to a Parent Form in Delphi 7

Posted on 2009-06-30
7
399 Views
Last Modified: 2013-12-04
Dear Experts,

When I was programming in Visual C++ I would sometimes use very bad techniques to move data from a child dialog box to the window that calls it.  Let's suppose I have a dialog box that shows a list of items in a single column grid.  When the user double clicks on an item, that item is selected and the dialog box closes, returning control to the parent window.

            In C++ I could get text from an edit field with a command like this:
      form_edit.GetWindowText(answer_string,sizeof(answer_string));

In this case the variable answer_string would be a global variable so the user's selection would be available, through the global variable, to the parent window that called the dialog box.

I realize it is considered bad programming to have too many global variables.  What is the proper way to transfer data in this situation?  After double-clicking my dialog box shuts down so the user's answer has to be stored somewhere before the dialog box's memory is freed.  

How do I cleanly shut down the dialog box?  In C++, I could use this command:

      CDialog::OnOK();

What is the proper way to do this in Delphi?
Sincerely,

Phil Truscott
0
Comment
Question by:PTRUSCOTT
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
7 Comments
 
LVL 14

Accepted Solution

by:
SteveBay earned 125 total points
ID: 24745329
In Delphi visual components are typically considered public to the form, Therefore it is considered normal and acceptable to do things like this:
procedure TForm1.Button1Click(Sender: TObject);
var StrVal : String;
begin
     StrVal := '';
     Form2 := TForm2.Create(nil);
     if Form2.ShowModal = mrOK then
          StrVal := Form2.Edit1.Text;
     FreeAndNil(Form2);
     ShowMessage(StrVal);
end;

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 24745357
depends what you want to get as return value
is it only 1 value ? -> use a function
is it more 1 value, with a check -> use a function with a out parameter
is it more than 1 value -> use a TStrings or Dataset

this is a sample of returning the selected email adresses in a string field
you could get the separate emails out again using the delimitedtext from TStrings
unit Unit2;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, StdCtrls, Buttons, ExtCtrls, Grids, DBGrids, DBClient;
 
type
  TfrmSelectEmails = class(TForm)
    cds: TClientDataSet;
    ds: TDataSource;
    grid: TDBGrid;
    pnl: TPanel;
    btnCancel: TBitBtn;
    btnSelectAll: TBitBtn;
    btnOk: TBitBtn;
    cdsName: TStringField;
    cdsemail: TStringField;
    procedure btnSelectAllClick(Sender: TObject);
  private
    function GetSelectedEmails: string;
    procedure SelectAll;
    procedure RandomData;
  public
    constructor Create(AOwner: TComponent); override;
    property SelectedEmails: string read GetSelectedEmails;
  end;
 
var
  frmSelectEmails: TfrmSelectEmails;
 
function SelectEmails(AOwner: TComponent): string;
 
implementation
 
{$R *.dfm}
 
function SelectEmails(AOwner: TComponent): string;
begin
  Result := '';
  frmSelectEmails := TfrmSelectEmails.Create(AOwner);
  try
    if frmSelectEmails.ShowModal = mrOk then
      Result := frmSelectEmails.SelectedEmails;
  finally
    FreeAndNil(frmSelectEmails);
  end;
end;
 
{ TfrmSelectEmails }
 
procedure TfrmSelectEmails.btnSelectAllClick(Sender: TObject);
begin
  SelectAll;
end;
 
constructor TfrmSelectEmails.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  cds.Active := True;
  RandomData;
end;
 
function TfrmSelectEmails.GetSelectedEmails: string;
const Delimiter = ';';
var b: TBookmark;
begin
  Result := '';
  with grid.DataSource.DataSet do
  begin
    DisableControls;
    try
      b := GetBookmark;
      try
        First;
        while not Eof do
        begin
          if grid.SelectedRows.CurrentRowSelected then
            Result := Result + FieldByName('email').AsString + Delimiter;
          Next;
        end;
      finally
        GotoBookmark(b);
        FreeBookmark(b);
      end;
    finally
      EnableControls;
    end;
  end;
  if Result <> '' then
    Delete(Result, Length(Result) - Length(Delimiter) + 1, Length(Delimiter));
end;
 
procedure TfrmSelectEmails.RandomData;
const MaxRandom = 30;
var I: Integer;
begin
  for I := 0 to Random(MaxRandom) do
    cds.InsertRecord([Format('name ', [i]), Format('email%d@abc.com', [i])]);
end;
 
procedure TfrmSelectEmails.SelectAll;
var b: TBookmark;
begin
  grid.SelectedRows.Clear;
  with grid.DataSource.DataSet do
  begin
    DisableControls;
    try
      b := GetBookmark;
      try
        First;
        while not Eof do
        begin
          grid.SelectedRows.CurrentRowSelected := True;
          Next;
        end;
      finally
        GotoBookmark(b);
        FreeBookmark(b);
      end;
    finally
      EnableControls;
    end;
  end;
end;
 
end.
 
--- dfm ---
object frmSelectEmails: TfrmSelectEmails
  Left = 0
  Top = 0
  Caption = 'Select emails'
  ClientHeight = 451
  ClientWidth = 692
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object grid: TDBGrid
    Left = 0
    Top = 0
    Width = 692
    Height = 392
    Align = alClient
    DataSource = ds
    Options = [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgMultiSelect]
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
  end
  object pnl: TPanel
    Left = 0
    Top = 392
    Width = 692
    Height = 59
    Align = alBottom
    TabOrder = 1
    object btnCancel: TBitBtn
      Left = 568
      Top = 16
      Width = 105
      Height = 25
      DoubleBuffered = True
      Kind = bkCancel
      ParentDoubleBuffered = False
      TabOrder = 0
    end
    object btnSelectAll: TBitBtn
      Left = 16
      Top = 16
      Width = 105
      Height = 25
      Caption = 'Select All'
      DoubleBuffered = True
      Glyph.Data = {
        F2010000424DF201000000000000760000002800000024000000130000000100
        0400000000007C01000000000000000000001000000000000000000000000000
        80000080000000808000800000008000800080800000C0C0C000808080000000
        FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333334433333
        3333333333388F3333333333000033334224333333333333338338F333333333
        0000333422224333333333333833338F33333333000033422222243333333333
        83333338F3333333000034222A22224333333338F33F33338F33333300003222
        A2A2224333333338F383F3338F33333300003A2A222A222433333338F8333F33
        38F33333000034A22222A22243333338833333F3338F333300004222A2222A22
        2433338F338F333F3338F3330000222A3A2224A22243338F3838F338F3338F33
        0000A2A333A2224A2224338F83338F338F3338F300003A33333A2224A2224338
        333338F338F3338F000033333333A2224A2243333333338F338F338F00003333
        33333A2224A2233333333338F338F83300003333333333A2224A333333333333
        8F338F33000033333333333A222433333333333338F338F30000333333333333
        A224333333333333338F38F300003333333333333A223333333333333338F8F3
        000033333333333333A3333333333333333383330000}
      NumGlyphs = 2
      ParentDoubleBuffered = False
      TabOrder = 1
      OnClick = btnSelectAllClick
    end
    object btnOk: TBitBtn
      Left = 440
      Top = 16
      Width = 105
      Height = 25
      DoubleBuffered = True
      Kind = bkOK
      ParentDoubleBuffered = False
      TabOrder = 2
    end
  end
  object cds: TClientDataSet
    Active = True
    Aggregates = <>
    Params = <>
    Left = 576
    Top = 40
    Data = {
      4D0000009619E0BD0100000018000000020000000000030000004D00044E616D
      65010049000000010005574944544802000200640005656D61696C0200490000
      000100055749445448020002002C010000}
    object cdsName: TStringField
      FieldName = 'Name'
      Size = 100
    end
    object cdsemail: TStringField
      FieldName = 'email'
      Size = 300
    end
  end
  object ds: TDataSource
    DataSet = cds
    Left = 512
    Top = 40
  end
end

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 24745384
use it like this from a other form:

procedure TFormX.btnSelectMailsClick(Sender: TObject);
begin
  Memo1.Lines.Delimiter := ';';
  Memo1.Lines.DelimitedText := SelectEmails(Self);
end;
0
Online Training Solution

Drastically shorten your training time with WalkMe's advanced online training solution that Guides your trainees to action. Forget about retraining and skyrocket knowledge retention rates.

 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 24745397
0
 
LVL 22

Expert Comment

by:8080_Diver
ID: 24746148
I have an approach that I learned from a Certified Delphi Instructor Instructor (i.e. he taught the guys who taught Delphi ;-).  
In the unit of forms (other than the mainform), I have a completely public function.  (For instance, I have a standard AboutBox form that I use and the function that it has for displaying the AboutBox is called TellAbout.)  This function (which, as in the case of my AboutBox, can be over loaded to allow various options), expects to receive certain paramaters which may be passed as constants and/or , as variables.  This function then creates the form, fills in any appropriate variables specific to the form, and shows the form (usually, I use ShowModal).  When the user closes the form, the function will extract any information from the form that should be returned to the calling form and then releases the form.  Also, I generally use a TModalResult for the return value from the function and that means I can use the result from the user closing the form, if aI want to.
By putting this function in the form's unit, you don't have to code the set up, show, and data extraction every place that you want to call the form . . . you just do another function call.  It also means that the form/unit is not tightly coupled to the other units in the application and, therefore, it contributes to code reusability (both within and between applications).  Finally, since you can over load the function, you can add new parameters for specific applications/calls and, by not requiring them in the old function call (which you leave in the unit), you don't break the contract with any existing applications/calls.
Effectively, you can pass the parameters to the function and receive results back in the parameters and easily solve your problem.
If you want, I can provide you with my AboutBox as an example of the process (it has 2 variations on the TellAbout function).
0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 24751603
8080_Diver,
i don't often consider the overloading but using my previous sample ...

this instructor ... looks like he does the same as i do
unit Unit2;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, DB, StdCtrls, Buttons, ExtCtrls, Grids, DBGrids, DBClient;
 
type
  TfrmSelectEmails = class(TForm)
    cds: TClientDataSet;
    ds: TDataSource;
    grid: TDBGrid;
    pnl: TPanel;
    btnCancel: TBitBtn;
    btnSelectAll: TBitBtn;
    btnOk: TBitBtn;
    cdsName: TStringField;
    cdsemail: TStringField;
    procedure btnSelectAllClick(Sender: TObject);
  private
    function GetSelectedEmails: string;
    procedure SelectAll;
    procedure RandomData;
  public
    constructor Create(AOwner: TComponent); override;
    property SelectedEmails: string read GetSelectedEmails;
  end;
 
var
  frmSelectEmails: TfrmSelectEmails;
 
function SelectEmails(AOwner: TComponent): string; overload;
procedure SelectEmails(AOwner: TComponent; var Emails: string); overload;
 
 
implementation
 
{$R *.dfm}
 
function SelectEmails(AOwner: TComponent): string;
begin
  Result := '';
  frmSelectEmails := TfrmSelectEmails.Create(AOwner);
  try
    if frmSelectEmails.ShowModal = mrOk then
      Result := frmSelectEmails.SelectedEmails;
  finally
    FreeAndNil(frmSelectEmails);
  end;
end;
 
procedure SelectEmails(AOwner: TComponent; var Emails: string); 
begin
  Emails := SelectEmails(AOwner);
end;
 
{ TfrmSelectEmails }
 
procedure TfrmSelectEmails.btnSelectAllClick(Sender: TObject);
begin
  SelectAll;
end;
 
constructor TfrmSelectEmails.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  cds.Active := True;
  RandomData;
end;
 
function TfrmSelectEmails.GetSelectedEmails: string;
const Delimiter = ';';
var b: TBookmark;
begin
  Result := '';
  with grid.DataSource.DataSet do
  begin
    DisableControls;
    try
      b := GetBookmark;
      try
        First;
        while not Eof do
        begin
          if grid.SelectedRows.CurrentRowSelected then
            Result := Result + FieldByName('email').AsString + Delimiter;
          Next;
        end;
      finally
        GotoBookmark(b);
        FreeBookmark(b);
      end;
    finally
      EnableControls;
    end;
  end;
  if Result <> '' then
    Delete(Result, Length(Result) - Length(Delimiter) + 1, Length(Delimiter));
end;
 
procedure TfrmSelectEmails.RandomData;
const MaxRandom = 30;
var I: Integer;
begin
  for I := 0 to Random(MaxRandom) do
    cds.InsertRecord([Format('name ', [i]), Format('email%d@abc.com', [i])]);
end;
 
procedure TfrmSelectEmails.SelectAll;
var b: TBookmark;
begin
  grid.SelectedRows.Clear;
  with grid.DataSource.DataSet do
  begin
    DisableControls;
    try
      b := GetBookmark;
      try
        First;
        while not Eof do
        begin
          grid.SelectedRows.CurrentRowSelected := True;
          Next;
        end;
      finally
        GotoBookmark(b);
        FreeBookmark(b);
      end;
    finally
      EnableControls;
    end;
  end;
end;
 
end.
 
--- dfm ---
object frmSelectEmails: TfrmSelectEmails
  Left = 0
  Top = 0
  Caption = 'Select emails'
  ClientHeight = 451
  ClientWidth = 692
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object grid: TDBGrid
    Left = 0
    Top = 0
    Width = 692
    Height = 392
    Align = alClient
    DataSource = ds
    Options = [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgMultiSelect]
    TabOrder = 0
    TitleFont.Charset = DEFAULT_CHARSET
    TitleFont.Color = clWindowText
    TitleFont.Height = -11
    TitleFont.Name = 'Tahoma'
    TitleFont.Style = []
  end
  object pnl: TPanel
    Left = 0
    Top = 392
    Width = 692
    Height = 59
    Align = alBottom
    TabOrder = 1
    object btnCancel: TBitBtn
      Left = 568
      Top = 16
      Width = 105
      Height = 25
      DoubleBuffered = True
      Kind = bkCancel
      ParentDoubleBuffered = False
      TabOrder = 0
    end
    object btnSelectAll: TBitBtn
      Left = 16
      Top = 16
      Width = 105
      Height = 25
      Caption = 'Select All'
      DoubleBuffered = True
      Glyph.Data = {
        F2010000424DF201000000000000760000002800000024000000130000000100
        0400000000007C01000000000000000000001000000000000000000000000000
        80000080000000808000800000008000800080800000C0C0C000808080000000
        FF0000FF000000FFFF00FF000000FF00FF00FFFF0000FFFFFF00333334433333
        3333333333388F3333333333000033334224333333333333338338F333333333
        0000333422224333333333333833338F33333333000033422222243333333333
        83333338F3333333000034222A22224333333338F33F33338F33333300003222
        A2A2224333333338F383F3338F33333300003A2A222A222433333338F8333F33
        38F33333000034A22222A22243333338833333F3338F333300004222A2222A22
        2433338F338F333F3338F3330000222A3A2224A22243338F3838F338F3338F33
        0000A2A333A2224A2224338F83338F338F3338F300003A33333A2224A2224338
        333338F338F3338F000033333333A2224A2243333333338F338F338F00003333
        33333A2224A2233333333338F338F83300003333333333A2224A333333333333
        8F338F33000033333333333A222433333333333338F338F30000333333333333
        A224333333333333338F38F300003333333333333A223333333333333338F8F3
        000033333333333333A3333333333333333383330000}
      NumGlyphs = 2
      ParentDoubleBuffered = False
      TabOrder = 1
      OnClick = btnSelectAllClick
    end
    object btnOk: TBitBtn
      Left = 440
      Top = 16
      Width = 105
      Height = 25
      DoubleBuffered = True
      Kind = bkOK
      ParentDoubleBuffered = False
      TabOrder = 2
    end
  end
  object cds: TClientDataSet
    Active = True
    Aggregates = <>
    Params = <>
    Left = 576
    Top = 40
    Data = {
      4D0000009619E0BD0100000018000000020000000000030000004D00044E616D
      65010049000000010005574944544802000200640005656D61696C0200490000
      000100055749445448020002002C010000}
    object cdsName: TStringField
      FieldName = 'Name'
      Size = 100
    end
    object cdsemail: TStringField
      FieldName = 'email'
      Size = 300
    end
  end
  object ds: TDataSource
    DataSet = cds
    Left = 512
    Top = 40
  end
end

Open in new window

0
 
LVL 38

Expert Comment

by:Geert Gruwez
ID: 24753640
ow i see you need a date ... i thought you meant data
you could do this with a boolean and a TDateTime type
and TDateTime


unit uSelectDate;
 
interface
 
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ComCtrls, StdCtrls, Buttons, ExtCtrls;
 
type
  TfrmDatePick = class(TForm)
    pnlButtons: TPanel;
    btnOk: TBitBtn;
    btnCancel: TBitBtn;
    mcPick: TMonthCalendar;
  end;
 
var
  frmDatePick: TfrmDatePick;
 
function SelectDate(AOwner: TComponent; var ADate: TDateTime): Boolean;
 
implementation
 
{$R *.dfm}
 
function SelectDate(AOwner: TComponent; var ADate: TDateTime): Boolean;
var frm: TfrmDatePick;
begin
  Result := False;
  frm := TfrmDatePick.Create(AOwner);
  try
    if frm.ShowModal = mrOk then
    begin
      Result := True;
      ADate := frm.mcPick.Date;
    end;
  finally
    FreeAndNil(frm);
  end;
end;
 
end.

Open in new window

0

Featured Post

Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

For most people, the WrapPanel seems like a magic when they switch from WinForms to WPF. Most of us will think that the code that is used to write a control like that would be difficult. However, most of the work is done by the WPF engine, and the W…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Michael from AdRem Software outlines event notifications and Automatic Corrective Actions in network monitoring. Automatic Corrective Actions are scripts, which can automatically run upon discovery of a certain undesirable condition in your network.…
Suggested Courses
Course of the Month10 days, 11 hours left to enroll

632 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question