Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chris Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Multiple instances of a form

Status
Not open for further replies.

lespaul

Programmer
Feb 4, 2002
7,083
US
Thanks to Punchinello's help, I have created an application that allows multiple instances of the same form (frmJurorInformation). In the OnShow event I have the following code:

Code:
With qryStatus do
begin
  SQL.Clear;
  SQL.Add('SELECT * FROM JMPSTATUS WHERE STCODE = ' + QuotedStr(qryJurorInformation.FieldByName('STATUSCD').AsString));
  Active := true;
  cbStatusCodes.Text := FieldByName('STDESC').AsString;
end;

(I can't get the DBLookupComboBox to work properly so I'm setting it my self in a regular combo box).

I would like to have this in it's own procedure:

Code:
procedure SetStatus(AStatusCode : string);
begin
  With qryStatus do
  begin
    SQL.Clear;
    SQL.Add('SELECT * FROM JMPSTATUS WHERE STCODE = ' + QuotedStr(AStatusCode);
    Active := true;
    cbStatusCodes.Text := FieldByName('STDESC').AsString;
end;
end;

except I can't figure out how to refer to this particular instance of the form! In the OnShow event I can use SELF and it works fine, but when I try to move this to it's own procedure (within the JurorInformation.pas) it doesn't work. I have tried putting the declaration in all kinds of places at the top (implementation, private, public) and always get a unsatisified forward or external declaration.

Anyone give me a clue on how I can implement this? There are a few other procedures that I would like to use, but I'm stuck!

Leslie
 
Leslie,

Pass the dataset to your general function, e.g:

Code:
procedure SetStatus(var ADataSet : TDataset; const AStatusCode : string);
begin
  With ADataset do
  begin
    if active then close;  // new line
    SQL.Clear;
    SQL.Add('SELECT * FROM JMPSTATUS WHERE STCODE = ' + QuotedStr(AStatusCode);
    Active := true;
    cbStatusCodes.Text := FieldByName('STDESC').AsString;
end;
end;

(You may need to pass the combo box as well, depending on where you want this routine to live.)

I frequently use this approach to collect commonly-used routines into a single unit that can be quickly copied to new applications.

You'll need to use the dataset appropriate for the tables you're using, e.g. tClientDataset, tDBISAMTable, tBDEDataset, or whatever. You'll also need to add the appropriate units to the appropriate USES clause.

Also, you may need to typecase your passed dataset to match the underlying dataset type.

To illustrate, consider the following routine that implements a general auto-increment algorithm that's more network aware than many:

Code:
procedure TdmSystemTables.getNextValue(const ADataset: TDataset);
// -------------------------------------------------------------
// Generates a unique ID for the current record in ADataset.
// Note that we assume the first field is the one that needs the 
// key.
-------------------------------------------------------------
var
   strTable,               // Target table.
   strField  : String;     // Target field.
   intValue  : Integer;    // Counter Value.
   siRetries : SmallInt;   // Retry counter.
const
   k_RETRIES = 3;
   k_NAPTIME = 250; // milliseconds
begin

   // Get table and field name from ADataset
   with ( ADataset as TDBISAMTable ) do
   begin
      strTable := Tablename;
      strField := Fields[ 0 ].FieldName;
   end;

   siRetries := k_RETRIES;

   // Retrieve and increment next ID value
   with tblCounters do
   begin

      while RecordIsLocked and ( siRetries > 0 ) do
      begin
         dec( siRetries );
         sleep( k_NAPTIME );
      end;

      if RecordIsLocked then
         raiseDataError( daCounters, 
                         [ k_CTRLOCKED,  
                           strTable,
                           strField ] );

      if findKey( [ strTable, strField ] ) then
         begin
            LockTable;
            edit;
            intValue := fields[ 2 ].AsInteger;
            fields[ 2 ].AsInteger := intValue + 1;
            post;
            unlockTable;
         end
      else
         raise Exception.create( 
         raiseDataError( daCounters, 
                         [ k_CTRMISSING,
                           strTable,
                           strField ] );
   end;
   
   // Save retrieved id; assumes key is
   // first field in table.
   with ( ADataset as TDBISAMTable ) do
   begin
      fields[ 0 ].AsInteger := intValue;
   end;
   
end;

Now, we might quibble about certain elements of the specific implementation, but I hope it shows the general idea, as well as some of the issues you need to keep in mind.

Hope this helps...

-- Lance
 
thanks Lance! I'm getting ready to take off for the rest of the week, but I will definitely look into this when I get back!

leslie
 
Ok, I actually figured this particular problem out in a different way, but now I'm really interested in passing the dataset to a procedure!

I need to generate a letter and have a dataset that contains all the name and address information. Instead of passing each variable, I'd like to try this technique of passing the dataset.

My question is, can I access the dataset just like I normally would? Will the 'FIELDBYNAME' method still work on the passed dataset or does it "lose" it's information?

Code:
procedure PrintPostponementLetter(JurorsData : TDataSet; ADate : TDateTime);
begin
  //Fill in letter with fields from dataset???

end;

Thanks for any information on using a dataset in this manner!

Leslie
 
In case anyone is wondering, the answer is yes, you can use the TDataSet properties and methods the same way. I'm passing a TQuery to the procedure:

Code:
procedure TfrmJurorInformation.PostponementLetter1Click(Sender: TObject);
begin
  PrintPostponementLetter(qryJurorInformation);
end;

procedure TfrmJurorInformation.PrintPostponementLetter(const JurorsData : TDataSet);
const
dblleftmargin : double = 1.25;
dblLineHeight : double = 0.1875;
var
strSalutation : string;
dblCurrentLine : double;
PixPerInX, PixPerInY, OffsetX, OffsetY : integer;
begin
  if JurorsData.FieldByName('SEX').AsString = 'M' then
    strSalutation := 'MR.'
  else if JurorsData.FieldByName('SEX').AsString = 'F' then
    strSalutation := 'MS.'
  else
    strSalutation := 'MR./MS.';
  dblCurrentLine := 2.5;
  Printer.BeginDoc;
  PixPerInX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
  PixPerInY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);
  OffsetX := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETX);
  OffsetY := GetDeviceCaps(Printer.Handle, PHYSICALOFFSETY);
  Printer.Canvas.Font.Name := 'Times New Roman';
  Printer.Canvas.Font.Size := 12;
  Printer.Canvas.Font.Style := [];
  Printer.Canvas.TextOut((trunc(dblleftmargin * PixPerInX) - OffsetX), trunc((dblCurrentLine * PixPerInY) - OffsetY) , strSalutation + ' ' + JurorsData.FieldByName('FIRSTNAME').AsString + ' ' + JurorsData.FieldByname('LASTNAME').ASString);  

dblCurrentLine := dblCurrentLine + dblLineHeight;

Printer.Canvas.TextOut((trunc(dblleftmargin * PixPerInX) - OffsetX), trunc((dblCurrentLine * PixPerInY) - OffsetY) , 'Thank you for your prompt response to the Juror Summons ' +
  'Questionnaire.  Per your request, your jury duty has been postponed ' +
  'until ' + convertdate(JurorsData.FieldByName('TERMDATE').AsString) + '.  Please mark this postponement date on your calendar.  Additional ' +
  'postponements will not be granted.');
  Printer.EndDoc;
end;

Leslie
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top