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!

multi-dimensional array as parameter 1

Status
Not open for further replies.

lespaul

Programmer
Feb 4, 2002
7,083
US
I have searched the Delphi help on using an array as a parameter, but can only find information on using a single dimension array, is there any way to use a multidimensional array as a parameter? (ps some of this may sound familiar, I posted a question the other day, and thought I found a way around it, but..... NOT!!)

What I have is an array that I have created and I transfer to Excel:

Code:
ProcessList := VarArrayCreate([0, (personcount - 1), 0, 8], varOleStr);

I now need to take this array (or a copy of it) and pass it to another procedure in order to create a text file from the information:

CreateTextFile(ARRAY AS PARAMETER)

I have tried passing in ProcessList, but I get an error that:

Incompatible types : array and variant

I have tried creating a new array called TextList, setting it equal to ProcessList and passing it:

SetLength(TextList, personcount, 8);
TextList := ProcessList;
CreateTextFile(TextList);

but I get an error:

Incompatible Types : array and dynamic array

The help I found was on:
'Array Parameters'
'Open Array Parameters'
'Variant Open Array Parameters'

but like I said, they only deal with one dimensional arrays.

I appreciate any help or guidance!

Thanks,
Leslie
 
Is your function-parameter of the same type as ProcessList, if not, it should be, I guess s-) If it already is, I'm gone...

HTH
TonHu
 
I'm not sure what you're asking? Here's my existing code:

Code:
unit VoucherProcessing;

interface

uses ComObj, Forms, Controls, IDGlobal, Dialogs, SysUtils, Variants,
  DateUtils, Classes;

procedure ProcessVouchers();

implementation

uses JMSData_Module, FormatFunctions, ProperCaseFunction, MainMenu,
HoursProcessing, RoundNumber;

var
Save_Cursor:TCursor;
tripsmade : integer;
booPubEmp : boolean;
booOrientPanel : boolean;
const payrate  = 5.15;
const milerate = 0.32;

procedure CreateTextFile(AList : array of const);
begin

 //do stuff
end;

//process to determine which hours the Public Employee gets paid for
//if regular working hours are 8 - 5 and the juror serves from 2 - 6
//then the juror will get paid for 1 hour since the hours from 2 - 5
//are on public time only the hour from 5 - 6 is on the person's time
function CalcPublicEmployee(StartTime, EndTime : TDateTime): double;
var
PEStartTime, PEEndTime : TDateTime;
begin
  JMSData.qryPEJurorHours.SQL.Clear;
  JMSData.qryPEJurorHours.SQL.Add('SELECT * FROM JMPPEMPLE WHERE JURNUM = ' +
   JMSData.qryHoursCalc.FieldByName('JURNUM').AsString);
  JMSData.qryPEJurorHours.Active := True;
  PEStartTime := IntToTime(JMSData.qryPEJurorHours.FieldByName('REGTIMEIN').AsInteger);
  PEEndTime := IntToTime(JMSData.qryPEJurorHours.FieldByName('REGTIMEOUT').AsInteger);
  if (JMSData.qryPEJurorHours.FieldByName('REGTIMEIN').AsInteger = 0) AND
   (JMSData.qryPEJurorHours.FieldByName('REGTIMEOUT').AsInteger = 0) then
    Result := 0
  else if EndTime < PEStartTime then
    Result := RoundN(HourSpan(StartTime, EndTime),1)
  else if (StartTime < PEStartTime) AND (EndTime < PEEndTime) then
    Result := RoundN(HourSpan(StartTime, PEStartTime),1)
  else if (StartTime > PEStartTime) AND (EndTime > PEEndTime) then
    Result := RoundN(HourSpan(PEEndTime, EndTime),1)
  else
    Result := 0;
  JMSData.qryPEJurorHours.Active := False;
end;
//calculate the number of trips and the number of hours the juror worked during term
function GetTotalHours(strJurorNumber : string) : double;
var
daysworked, k, j : integer;
TotalHours : double;
HoursWorked : array of array of TDateTime;
begin
  If JMSData.qryHoursCalc.FieldByName('DNPT').AsString = 'F' then
  begin
    with JMSData.qryTemp do
    begin
      SQL.Clear;
      SQL.Add('SELECT * FROM JMPHOURS WHERE JURNUM = ' + strJurorNumber +
      ' ORDER BY SERVDAT, TIMETYPE');
      Active := True;
      While not EOF do
      begin
        If not ((FieldByName('SERVDAT').AsString =
          convertdate(frmMainMenu.processDate)) AND
          ((FieldByName('TIMETYPE').AsString = 'TI')
            OR (FieldByName('TIMETYPE').AsString = 'TO'))) then
        begin
          inc(daysworked);
        end
        else if not booOrientPanel then
        begin
          inc(daysworked);
        end;
        Next;
      end;
      //verify even number of records
      If not odd(daysworked) then
      begin
        //tripsmade determines the mileage pay but the panel who served
        //on orientation day needs extra slot for extra time entry
        tripsmade := daysworked div 2;
        if booOrientPanel then
        begin
          SetLength(HoursWorked, tripsmade + 1, 3);
          daysworked := daysworked + 2;
        end
        else
          SetLength(HoursWorked, tripsmade, 3);
        First;
        k := -1;
        for j := 0 to (daysworked - 1) do
        begin
          If j mod 2 = 0 then
          begin
            inc(k);
            Hoursworked[k , 0] := StrToDate(DateFormat(FieldByName('SERVDAT').AsString));
          end;
          if ((FieldByName('TIMETYPE').AsString = 'TI') or (FieldByName('TIMETYPE').AsString = 'OI')) then
            Hoursworked[k, 1] := IntToTime(FieldByName('TIMEIO').AsInteger)
          else if ((FieldByName('TIMETYPE').AsString = 'TO') or (FieldByName('TIMETYPE').AsString = 'OO')) then
            Hoursworked[k, 2] := IntToTime(FieldByName('TIMEIO').AsInteger);
          JMSData.qryTemp.Next;
        end;
        for j := 0 to ((daysworked div 2) - 1) do
        begin
          if not booPubEmp then
            TotalHours := TotalHours + RoundN(HourSpan(HoursWorked[j, 1], HoursWorked[j, 2]),1)
          else
            TotalHours := TotalHours + CalcPublicEmployee(HoursWorked[j, 1], HoursWorked[j, 2]);
        end;
      end;
      Result := TotalHours;
    end;
  end
  else
  Result := 0;
end;
//calculate total number of miles (RTM * tripsmade)
function GetTotalMiles() : integer;
begin
  with JMSData.qryHoursCalc do
  begin
    If FieldByName('DNPM').AsString = 'F' then
    begin
      If booPubEmp then
      begin
        If FieldByName('RTM').AsInteger < 30 then
          Result := 0
        else
          Result := FieldByName('RTM').AsInteger * tripsmade;
      end
      else
        Result := FieldByName('RTM').AsInteger * tripsmade;
    end
    else
      Result := 0;
  end;
end;
//set boolean to determine if the panel the juror is on was called to serve
//on orientation day
function CheckOrientation(strPanelID : string) : boolean;
begin
  With JMSData.qry2Temp do
  begin
    SQL.Clear;
    SQL.Add('SELECT SESSION FROM JMPDLYPANL WHERE SERVDAT = ' + QuotedStr(convertdate(frmMainMenu.processDate)) + 'AND PANELID = ' +
      QuotedStr(strPanelID));
    Active := True;
    If JMSData.qry2Temp.FieldByName('SESSION').AsString = 'AM' then
      Result := True
    else
      Result := False;
  end;
end;
//set boolean to determine if juror is public employee
function CheckPubEmployee(strJurorNumber : string) : boolean;
begin
  If JMSData.qryHoursCalc.FieldByName('PUBEMP').AsString = 'T' then
  begin
    with JMSData.qryPEJurorHours do
    begin
      SQL.Clear;
      SQL.Add('SELECT * FROM JMPPEMPLE WHERE JURNUM = ' + strJurorNumber);
      Active := True;
      If (FieldByName('PARTTIME').AsString = 'F') AND (FieldByName('SUBSTITUTE').AsString = 'F') AND
         (FieldByName('OTHER').AsString = 'F') then
        result := True
      else
        result := False;
    end;
  end
  else
    result := False;
end;
//main processing function
procedure ProcessVouchers();
var
ProcessList : variant;
TextList : array of array of Variant; //Here's where I'm having problems
personcount, i : integer;
firstvoucher, lastvoucher : string;
excelapp, excelsht : Variant;
PaidJurorList : Tstrings;
begin
  Save_Cursor := Screen.Cursor;
  Screen.Cursor := crHourGlass;
  try
  //if query not empty then process
  With JMSData.qryHoursCalc do
  begin
    If not IsEmpty then
    begin
      While not EOF do
      begin
        inc(personcount);
        Next;
      end;
      ProcessList := VarArrayCreate([0, (personcount - 1), 0, 8], varOleStr);
      SetLength(TextList, personcount, 8);
      First;
      For i := 0 to (personcount - 1) do
      begin
        booPubEmp := CheckPubEmployee(FieldByName('JURNUM').AsString);
        booOrientPanel := CheckOrientation(copy(FieldByName('PANELID').AsString,1, 9));

        ProcessList[i , 0] := ProperCase(FieldByName('FIRSTNAME').AsString +
         ' ' + FieldByName('LASTNAME').AsString) + ' (' + FieldByName('PANELID').AsString + ')';

        ProcessList[i , 1] := ProperCase(FieldByName('STREET1').AsString);
        ProcessList[i , 2] := ProperCase(FieldByName('CITY').AsString) +
         ' ' + UpperCase(FieldByName('STATE').AsString) + ' ' + FieldByName('ZIPCODE').AsString;
        ProcessList[i, 3] := GetTotalHours(FieldByName('JURNUM').AsString);
        ProcessList[i, 4] := ProcessList[i, 3] * payrate;
        ProcessList[i, 5] := GetTotalMiles;
        ProcessList[i, 6] := ProcessList[i, 5] * milerate;
        ProcessList[i, 7] := FieldByName('JURNUM').AsString;
        JMSData.qryHoursCalc.Next;
        tripsmade := 0;
      end;
      firstvoucher := JMSData.daLastVoucher.Value;
      //start excel
      excelapp:= CreateOleObject('Excel.Application');
      excelapp.Visible := True;
      excelapp.Workbooks.Open('R:\Case Management\JMS\Forms\Vouchers.xls');
      excelsht :=  excelapp.WorkSheets.Item['Data'];
      excelsht.Activate;
      //set excel range to size of ProcessList array and transfer array in full
      excelsht.Range[excelsht.Cells.Item[2, 1], excelsht.Cells.Item[(personcount + 1), 8]].Value := ProcessList;
      excelsht.Cells[1,10] := firstvoucher;
      excelapp.Worksheets.Item['VoucherReport'].PageSetup.LeftFooter := 'Voucher Processing for term beginning: ' + frmMainMenu.ProcessDate;

      excelapp.Run('Generate_VoucherRpt');
      lastvoucher := excelsht.Cells[1, 10].Text;
      //JMSData.daLastVoucher.value := lastvoucher;
      PaidJurorList := TStringList.Create;
      PaidJurorList.CommaText := excelapp.Worksheets.Item['Criteria'].Range['jurorlist'];
      //create check records for paid jurors
    end;
  end;
  finally
    Screen.Cursor := Save_Cursor;
  end;
end;
 
lespaul,

I'm assuming that after sending the data to Excel, you will be writing the data to a textfile, using the CreateTextFile procedure, wich should be called like
Code:
CreateTextFile(ProcessList);
so either TextList isn't needed, or TextList (c/s)hould also be of type Variant,
and then
Code:
procedure CreateTextFile(AList : array of const);
should be
Code:
procedure CreateTextFile(AList : variant);

as I tried to say in : &quot;Is your function-parameter of the same type as ProcessList&quot;, so the function-parameter should be of type Variant.

HTH
TonHu
(Was this some kind of a test? ;-))
 
that seems to work great! I don't know why I was being so dense! So now I have my array in the CreateTextFile procedure, I'm going to take the information from the array and create formatted strings for each element in the array. What is the best way to get this information into a text file?

Thanks for any information!

Leslie
 
I'd go for a comma or tab separated structure, or maybe some kind of html/xml variant (table?), so anyone can view it with a browser.
Advantage of a html table is that column cells are automagically resized and 'formatted' if text doesn't fit exactly ;-)

Just use your imagination!

HTH
TonHu
 
Actually I ended up using a TStringList. It has a SaveToFile that I can use (I'm just FTPing the file to another entity for processing).

However, I've got another really WEIRD problem. Below is my code. In the bold section, I need to add the following line of code:

Code:
vouchertotal := 0;

I basically need to reset this variable for each person that I am processing. However, when I add the code, the compiler SKIPS it. You know when you add a line of code, the compiler adds the little blue dot to the side indicating that you can put a break there? Well, the little blue dot never shows up on this line of code. If I take an existing line of code that has the blue dot, and modify it to the above, the blue dot already on that line disappears.

I really is the weirdest thing, I haven't had a chance to really look into why it's happening, it didn't happen until the end of the day yesterday. But if anyone knows what's up, I appreciate the clue!

Code:
procedure CreateTextFile(AList : variant; AVoucher : string);
var
commonstring, headerstring, detailstring : string;
VoucherList : TStringList;
i : integer;
vouchertotal : double;
VoucherNumber : integer;
formattotal : string;
begin
  VoucherList := TStringList.Create;
  vouchertotal := 0;

//take numeric string ##-###-###### convert last 6 digits to integer.  the string is the last voucher used and needs to be incremented 

  VoucherNumber := strToINt(copy(Avoucher,8,6));
  Inc(VOucherNumber);

//create new voucher number with increment

  AVoucher := copy(AVoucher,1,2) + copy(AVoucher,4,3) + IntToStr(VoucherNumber);

//create header and detail beginning strings

  headerstring := Format('%-2s%-4s%-10s%-4s%-4s%-12s',['D', 'MP', '218', 'MP', '218', AVoucher]);
  commonstring := Format('%-2s%-4s%-10s%-4s%-4s%-12s',['L', 'MP', '218', 'MP', '218', AVoucher]);

//for all elements in the array, sum the juror pay and mileage pay for a total payment due to all jurors

  For i := 0 to personcount - 1 do
  begin
    vouchertotal := vouchertotal + AList[i, 4] + AList[i, 6];
  end;

//convert total $#.## to a non-decimal format (ie if total is 9415.23 convert to format 941523 and convert to string

  vouchertotal := vouchertotal * 100;
  formattotal := floatToStr(voucherTotal);

//pad total with '0'
 
  while length(formattotal) < 14 do formattotal := '0' + formattotal;

//create final header string 

  headerstring := headerstring +
  Format('%-2s%-3s%-11s%-2s%-2s%-2s%-2s%-2s%-2s%-4s%14s%-14s%-4s%-3s%-4s%-2s%-9s%-4s%-4s%-2s%-4s%-2s%-8s%-4s%-4s%-27s',
   ['MP','218', AVoucher, FormatDateTime('mm', Today), FormatDateTime('dd', Today), FormatDateTime('yy', Today), '', '', copy(AVoucher,1,2), '', formattotal, '', '012','218','P559','','400','','4791','','','','','','','Description']);

//Add header string to List

  VoucherList.Add(headerstring);

Code:
  //for each element in the array get juror and mileage pay for detail record

For i := 0 to personcount - 1 do
  begin
    vouchertotal := AList[i,4] + AList[i, 6];
    vouchertotal := vouchertotal * 100;
    formattotal := floatToStr(vouchertotal);
    while length(formattotal) < 14 do formattotal := '0' + formattotal;
    detailstring := commonstring + Format('%-10s%-1s%-12s%-11s%-2s%-1s%-1s%-2s%-1s%-2s%-30s%-29s%-30s%-18s%-2s%-10s%-14s%-3s',
    ['MP218', '', '', 'MP03#', '', '','','','','', UpperCase(AList[i,11]), UpperCase(AList[i, 1]), AList[i,8], '', AList[i,9], AList[i,10], formattotal, '']);
    VoucherList.Add(detailstring);
  end;
Code:
//save Tstringlist to file for FTP transfer

  VoucherList.SaveToFile('C:\vouchertest.txt');
  VoucherList.Free;
end;

Thanks for any assistance.

Leslie
 
hi

vouchertotal := 0; is skipped because vouchertotal is being assigned vouchertotal := AList[i,4] + AList[i, 6]; so the compiler makes the :=0 assignment redundant.

lou


 
OK, I found out that the compiler optimizes the code and you're right, since it's really not doing anything it leaves it out.

However, when I try running the above code when it gets to the second person in the array I get the error:

Invalide variant type conversion

Any ideas on why this is happening? This is why I originally was putting the vouchertotal := 0 because I thought it would help this error.

The first time through the two values are 15.45 and 0 the second time through they are 12.8 and 12.6 (don't know if that will make any difference).

Thanks,

Leslie
 
I found a solution!!! I added two variables to the procedure jurorpay and milespay, I assigned the array elements to the variables and then add the variables. Works like a charm!
Code:
For i := 0 to personcount - 1 do
  begin
    jurorpay := AList[i, 4];
    milespay := AList[i, 6];
    vouchertotal := jurorpay + milespay;
    vouchertotal := vouchertotal * 100;
    formattotal := floatToStr(vouchertotal);
    while length(formattotal) < 14 do formattotal := '0' + formattotal;
    detailstring := commonstring + Format('%-10s%-1s%-12s%-11s%-2s%-1s%-1s%-2s%-1s%-2s%-30s%-29s%-30s%-18s%-2s%-10s%-14s%-3s',
    ['MP218', '', '', 'MP' + copy(AVoucher,1,2) + '#', '', '','','','','', UpperCase(AList[i,11]), UpperCase(AList[i, 1]), AList[i,8], '', AList[i,9], AList[i,10], formattotal, '']);
    VoucherList.Add(detailstring);
  end;
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top