Watch, Follow, &
Connect with Us

Please visit our new home
community.embarcadero.com.


Welcome, Guest
Guest Settings
Help

Thread: Passing Form as Pararamiter and it understand a function on that form


This question is not answered. Helpful answers available: 2. Correct answers available: 1.


Permlink Replies: 3 - Last Post: Apr 19, 2018 11:53 AM Last Post By: Remy Lebeau (Te... Threads: [ Previous | Next ]
Donald Bossen

Posts: 81
Registered: 2/3/02
Passing Form as Pararamiter and it understand a function on that form  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Apr 18, 2018 3:28 PM
Here is my code.
procedure TFrmSendOrder.BtnPrintClick(Sender: TObject);
var
Form : TForm;
begin
try
with FrmTb2 do
if computer_id = -1 then
Form := FrmPrint
else
Form := FrmPrintNw;
with FrmTb2 do
if CheckPrinter(ReadIniStr(IniHdwe,'Printer','Printer')) then
OrderPrint(chPrinter,ReadIniStr(IniHdwe,'Printer','Printer'), 'Order Sent (Print) Report',Form)
else
OrderPrint(chDisplay,ReadIniStr(IniHdwe,'Printer','Printer'), 'Order Sent (Print) Report',Form);
except
on E: Exception do
ShowMessage(E.Message);
end;
end;

procedure TFrmSendOrder.OrderPrint(channel : TOutputChannel; Prt, Typ : ShortString; Form : TForm);
var
ordNo : Word;
Page : Word;
Msg : ShortString;
PageLen : Double;
PrintWidth : Double;
sTop : Double;
begin
// SetConv;
with FrmTb2 do
begin
if SelectDataWhere(TblPrt,Msg,'Prints','') then
begin
Form := TForm.Create(self);
Form.Show; //chDisplay = on Screen chPrinter = Print
IniPdf;
sTop := 0.25;
PageLen := pBeginDocPdf(Channel,Prt,1,sTop,True,False,dpDriverSetting,PrintWidth); // True = Portrait False = LandScape
stop := Stop + 0.10;

Page := 1;
TblPrt.First;;
While not TblPrt.Eof do
begin
OrdNo := TblPrt.FieldByName('Order_No').AsInteger;
Page := Form.PrintOrder(sTop,PageLen,OrdNo);
TblPrt.Edit;
TblPrt.FieldByName('Pages').AsInteger := page;
TblPrt.Post;
TblPrt.Next;
if not TblPrt.Eof then
pNewPagePdf;
end;
pEndDocPdf;
FinPdf;
Form.Close;
end
else
ShowMessage(Msg);
end; {--- end With FrmTb2 ---}
end;
The Compile does not understand PrintOrder is a Public function on Form. How do you tell it PrintOrder has a function? Or how to tell the Uses that you want to condition compile based on some flag like Project Name?
Thanks in Advance
Donald S. Bossen
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Passing Form as Pararamiter and it understand a function on that form  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Apr 18, 2018 8:42 PM   in response to: Donald Bossen in response to: Donald Bossen
Donald Bossen wrote:

The Compile does not understand PrintOrder is a Public function on
Form.

Correct, because you are passing in a generic TForm pointer, and the
TForm class itself does not have a public member named PrintOrder().
It is a method of your derived Form classes instead.

How do you tell it PrintOrder has a function?

You don't. I would suggest a different approach - pass the desired
PrintOrder() itself to OrderPrint(), and then just call it like any
other method call, eg:

type
  PrintOrderProc: procedure(sTop: Double; PageLen: Double; OrdNo: Word)
of object;
 
...
 
procedure TFrmSendOrder.BtnPrintClick(Sender: TObject);
var
  Form : TForm;
  Proc : PrintOrderProc;
  Chan : TOutputChannel;
  Prt  : ShortString;
begin
  try
    with FrmTb2 do
    begin
      if computer_id = -1 then
      begin
        Form := FrmPrint
        Proc := FrmPrint.PrintOrder;
      end else
      begin
        Form := FrmPrintNw;
        Proc := FrmPrintNw.PrintOrder;
      end;
 
      with FrmTb2 do
      begin
        Prt := ReadIniStr(IniHdwe,'Printer','Printer');
 
        if CheckPrinter(Prt) then
          Chan := chPrinter
        else
          Chan := chDisplay;
 
        OrderPrint(Chan, Prt, 'Order Sent (Print) Report', Form, Proc);
      end;
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;
 
procedure TFrmSendOrder.OrderPrint(channel : TOutputChannel;
  Prt, Typ : ShortString; Form : TForm; PrintOrder : PrintOrderProc);
var
  ordNo      : Word;
  Page       : Word;
  Msg        : ShortString;
  PageLen    : Double;
  PrintWidth : Double;
  sTop       : Double;
begin
  //SetConv;
  with FrmTb2 do
  begin
    if SelectDataWhere(TblPrt, Msg, 'Prints', '') then
    begin
      Form.Show; //chDisplay = on Screen chPrinter = Print
      try
        IniPdf;
        try
          sTop := 0.25;
          PageLen := pBeginDocPdf(Channel, Prt, 1, sTop, True, False,
dpDriverSetting, PrintWidth); // True = Portrait False = LandScape
          try
            sTop := sTop + 0.10;
            Page := 1;
            TblPrt.First;
            while not TblPrt.Eof do
            begin
              OrdNo := TblPrt.FieldByName('Order_No').AsInteger;
              Page := PrintOrder(sTop, PageLen, OrdNo);
              TblPrt.Edit;
              try
                TblPrt.FieldByName('Pages').AsInteger := page;
                TblPrt.Post;
              except
                TblPrt.Cancel;
                raise;
              end;
              TblPrt.Next;
              if not TblPrt.Eof then
                pNewPagePdf;
            end;
          finally
            pEndDocPdf;
          end;
        finally
          FinPdf;
        end;
      finally
        Form.Close;
      end;
    end
    else
      ShowMessage(Msg);
  end;  {--- end With FrmTb2 ---}
end;


Or how to tell the Uses that you want to condition compile based on
some flag like Project Name?

You would have to wrap the 'uses' entries in {$IFDEF} statements and
then define precompiler conditionals as needed. But that doesn't
really solve the problem you are trying to solve.

--
Remy Lebeau (TeamB)
Donald Bossen

Posts: 81
Registered: 2/3/02
Re: Passing Form as Pararamiter and it understand a function on that form  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Apr 19, 2018 9:06 AM   in response to: Remy Lebeau (Te... in response to: Remy Lebeau (Te...
Thank you for responding to my post
I am having a problem with the syntax of
{code}
type
PrintOrderProc: procedure(sTop: Double; PageLen: Double; OrdNo: Word)
of object;
if I change it to
type
PrintOrderProc = procedure(sTop: Double; PageLen: Double; OrdNo: Word) of Object;
I think this is causing the compiler to require when I call

if computer_id = -1 then
begin
Form := FrmPrint
Proc := FrmPrint.PrintOrder;
end else
begin
Form := FrmPrintNw;
Proc := FrmPrintNw.PrintOrder;
end;
the PrintOrder to require pramaters of (sTop: Double; PageLen: Double; OrdNo: Word)
I am simply unfamiliar with doing this.

You would have to wrap the 'uses' entries in {$IFDEF} statements and
then define precompiler conditionals as needed. But that doesn't
really solve the problem you are trying to solve.

When I started the idea was than I had 2 programs that used similar code say project A and B the difference was one uses a print form different from each other. One project had in its user PrintOrder and the other used PrintOrderNw that is why I thought I could use a conditional compiler directive to solve the problem.
Donald S. Bossen
Remy Lebeau (Te...


Posts: 9,447
Registered: 12/23/01
Re: Passing Form as Pararamiter and it understand a function on that form  
Click to report abuse...   Click to reply to this thread Reply
  Posted: Apr 19, 2018 11:53 AM   in response to: Donald Bossen in response to: Donald Bossen
Donald Bossen wrote:

I am having a problem with the syntax of

type
PrintOrderProc: procedure(sTop: Double; PageLen: Double; OrdNo:
Word) of object;

if I change it to

type
PrintOrderProc = procedure(sTop: Double; PageLen: Double; OrdNo:
Word) of Object;

Yes, that was a typo on my part, sorry. Your fix is correct.

I think this is causing the compiler to require when I call

if computer_id = -1 then
begin
Form := FrmPrint
Proc := FrmPrint.PrintOrder;
end else
begin
Form := FrmPrintNw;
Proc := FrmPrintNw.PrintOrder;
end;

the PrintOrder to require pramaters of (sTop: Double; PageLen:
Double; OrdNo: Word)

No, it doesn't. This code is not trying to call PrintOrder(), it is
assiging the memory address of PrintOrder() to the 'Proc' variable.
That aaddress then gets passed to OrderPrint(), which then calls
PrintOrder().

This mechanism is the foundation of how VCL component event handlers
operate.

The code above works fine when I try it.

When I started the idea was than I had 2 programs that used similar
code say project A and B the difference was one uses a print form
different from each other. One project had in its user PrintOrder and
the other used PrintOrderNw that is why I thought I could use a
conditional compiler directive to solve the problem.

In that situation, it would look like this:

uses
  ...
  {$IFDEF PROJECT_A}
  , FrmPrintOrder
  {$ELSE}
    {$IFDEF PROJECT_B}
  , FrmPrintOrderNw
    {$ELSE}
  {$MESSAGE Error 'Project not defined!'}
    {$ENDIF}
  {$ENDIF}
  ;
 
procedure TFrmSendOrder.BtnPrintClick(Sender: TObject);
var
  Form : TForm;
  Proc : PrintOrderProc;
  Chan : TOutputChannel;
  Prt  : ShortString;
begin
  try
    with FrmTb2 do
    begin
      {$IFDEF PROJECT_A}
      Form := FrmPrint;
      Proc := FrmPrint.PrintOrder;
      {$ELSE}
      Form := FrmPrintNw;
      Proc := FrmPrintNw.PrintOrder;
      {$ENDIF}
 
      Prt := ReadIniStr(IniHdwe, 'Printer', 'Printer');
 
      if CheckPrinter(Prt) then
        Chan := chPrinter
      else
        Chan := chDisplay;
 
      OrderPrint(Chan, Prt, 'Order Sent (Print) Report', Form, Proc);
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;


Or, you could do this instead:

uses
  ...
  {$IFDEF PROJECT_A}
  , FrmPrintOrder
  {$ELSE}
    {$IFDEF PROJECT_B}
  , FrmPrintOrderNw
    {$ELSE}
  {$MESSAGE Error 'Project not defined!'}
    {$ENDIF}
  {$ENDIF}
  ;
 
procedure TFrmSendOrder.BtnPrintClick(Sender: TObject);
var
  Chan : TOutputChannel;
  Prt  : ShortString;
begin
  try
    with FrmTb2 do
    begin
      Prt := ReadIniStr(IniHdwe, 'Printer', 'Printer');
 
      if CheckPrinter(Prt) then
        Chan := chPrinter
      else
        Chan := chDisplay;
 
      OrderPrint(Chan, Prt, 'Order Sent (Print) Report');
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;
 
procedure TFrmSendOrder.OrderPrint(channel : TOutputChannel;
  Prt, Typ : ShortString);
var
  Form       : {$IFDEF PROJECT_A}TFrmPrint{$ELSE}TFrmPrintNw{$ENDIF};
  ordNo      : Word;
  Page       : Word;
  Msg        : ShortString;
  PageLen    : Double;
  PrintWidth : Double;
  sTop       : Double;
begin
  Form := {$IFDEF PROJECT_A}FrmPrint{$ENDIF}FrmPrintNw{$ENDIF};
  //SetConv;
  with FrmTb2 do
  begin
    if SelectDataWhere(TblPrt, Msg, 'Prints', '') then
    begin
      Form.Show; //chDisplay = on Screen chPrinter = Print
      try
        IniPdf;
        try
          sTop := 0.25;
          PageLen := pBeginDocPdf(Channel, Prt, 1, sTop, True, False,
dpDriverSetting, PrintWidth); // True = Portrait False = LandScape
          try
            sTop := sTop + 0.10;
            Page := 1;
            TblPrt.First;
            while not TblPrt.Eof do
            begin
              OrdNo := TblPrt.FieldByName('Order_No').AsInteger;
              Page := Form.PrintOrder(sTop, PageLen, OrdNo);
              TblPrt.Edit;
              try
                TblPrt.FieldByName('Pages').AsInteger := page;
                TblPrt.Post;
              except
                TblPrt.Cancel;
                raise;
              end;
              TblPrt.Next;
              if not TblPrt.Eof then
                pNewPagePdf;
            end;
          finally
            pEndDocPdf;
          end;
        finally
          FinPdf;
        end;
      finally
        Form.Close;
      end;
    end
    else
      ShowMessage(Msg);
  end;  {--- end With FrmTb2 ---}
end;


There is a third option - define an interface that both Forms implement
to call PrintOrder() with, then OrderPrint() can query for that
interface, eg:

type
  IPrintOrder = interface
    ['{39AC01A3-549E-458B-9D36-EA778467A93C}']
    procedure PrintOrder(sTop: Double; PageLen: Double; OrdNo: Word);
  end;
 
...
 
 
type
  TFrmPrintOrder = class(TForm, IPrintOrder)
    ...
  public
    ...
    procedure PrintOrder(sTop: Double; PageLen: Double; OrdNo: Word);
    ...
  end;
 
...
 
type
  TFrmPrintOrderNw = class(TForm, IPrintOrder)
    ...
  public
    ...
    procedure PrintOrder(sTop: Double; PageLen: Double; OrdNo: Word);
    ...
  end;
 
...
 
procedure TFrmSendOrder.BtnPrintClick(Sender: TObject);
var
  Chan : TOutputChannel;
  Prt  : ShortString;
begin
  try
    with FrmTb2 do
    begin
      with FrmTb2 do
      begin
        Prt := ReadIniStr(IniHdwe,'Printer','Printer');
 
        if CheckPrinter(Prt) then
          Chan := chPrinter
        else
          Chan := chDisplay;
 
        OrderPrint(Chan, Prt, 'Order Sent (Print) Report', {$IFDEF
PROJECT_A}FrmPrint{$ELSE}FrmPrintNw{$ENDIF});
      end;
    end;
  except
    on E: Exception do
      ShowMessage(E.Message);
  end;
end;
 
procedure TFrmSendOrder.OrderPrint(channel : TOutputChannel;
  Prt, Typ : ShortString; Form : TForm);
var
  IPO        : IPrintOrder;
  ordNo      : Word;
  Page       : Word;
  Msg        : ShortString;
  PageLen    : Double;
  PrintWidth : Double;
  sTop       : Double;
begin
  //SetConv;
  with FrmTb2 do
  begin
    if SelectDataWhere(TblPrt, Msg, 'Prints', '') then
    begin
      if Supports(Form, IPrintOrder, IPO) then
      begin
        Form.Show; //chDisplay = on Screen chPrinter = Print
        try
          IniPdf;
          try
            sTop := 0.25;
            PageLen := pBeginDocPdf(Channel, Prt, 1, sTop, True, False,
dpDriverSetting, PrintWidth); // True = Portrait False = LandScape
            try
              sTop := sTop + 0.10;
              Page := 1;
              TblPrt.First;
              while not TblPrt.Eof do
              begin
                OrdNo := TblPrt.FieldByName('Order_No').AsInteger;
                Page := IPO.PrintOrder(sTop, PageLen, OrdNo);
                TblPrt.Edit;
                try
                  TblPrt.FieldByName('Pages').AsInteger := page;
                  TblPrt.Post;
                except
                  TblPrt.Cancel;
                  raise;
                end;
                TblPrt.Next;
                if not TblPrt.Eof then
                  pNewPagePdf;
              end;
            finally
              pEndDocPdf;
            end;
          finally
            FinPdf;
          end;
        finally
          Form.Close;
        end;
      end;
    end
    else
      ShowMessage(Msg);
  end;  {--- end With FrmTb2 ---}
end;


--
Remy Lebeau (TeamB)
Legend
Helpful Answer (5 pts)
Correct Answer (10 pts)

Server Response from: ETNAJIVE02