Saving certain data into an array from a DBGrid - arrays

I would like to ask for help.
I have been tasked with saving FighterID into an array. This data will be used to make fighter 1 ,fight, fighter 2(the data has already been sorted in descending order according to wins they have).
I could only find ways to do this with 2D arrays, i would like tom use a 1 dimensional array.
I have no idea how to save a specific columns info into the array. I have tried the following and got the following error:
[dcc32 Error] Presets.pas(53): E2010 Incompatible types: 'string' and 'procedure, untyped pointer or untyped parameter'
Code:
procedure TPresetsForm.FormActivate(Sender: TObject);
var I:integer;
var s:string;
begin
qry1.Close;
qry1.sql.add('SELECT FighterName,Wins,Sponser FROM Preset_Fighters');
qry1.Active := true;
qry1.Open;
tbl111.Sort:= 'Wins DESC' ;
for I := 1 to 6 do
begin
Fightorder[I]:=(Presets.PresetsForm.dbgrd_info.Columns[0].FieldName:=('FighterID');
end;
end;
I have no idea if this is the correct way to obtain the FighterID example (MT54).
All data is from MS Access, I hope I have provided enough information
Thanks for the help XD

Please try the following code:
var
Fightorder: array[1..6] of string;
procedure TPresetsForm.FormActivate(Sender: TObject);
var
I: Integer;
begin
qry1.Close;
qry1.Sql.Add('SELECT FighterName, Wins, Sponser FROM Preset_Fighters');
qry1.Active := True;
qry1.Open;
for I := 1 to 6 do
begin
Fightorder[I] := qry1.Fields[0].AsString;
qry1.Next;
end;
end;
I think this will help you figure it out.

Related

TStringList in an array in Lazarus

I have a problem with TStringLists in Lazarus. I have an array called 'trans' of records called 'TTrans' which contain, among other things, TStringList called 'meebetalers'. So when I need to know for example the amount of lines in that StringList I would have to write this right?
trans[i].meebetalers.Count;
Anyways, I first create a stringlist and put the selected strings from a checklistbox in it, and that works (i.e. the program returns 3 when I ask for the Count, which is correct).
In this piece of code I add values to the StringList:
slmeebetalers := TStringList.Create;
for i:= 0 to Form6.CLBox.Count-1 do begin
if Form6.CLBox.Checked[i] then begin
slmeebetalers.Add(Form6.CLBox.Items[i]);
end;
end;
Then I put the stringlist a procedure, and in that procedure I assign my first created StringList to the stringlist I mentionned before (trans[i].meebetalers), see my piece of code next.
Unit6.VoegTransToe(Form6.TransNaam.Text,
Form6.TrComboBox.Text,
bedrag,
slmeebetalers,
Form6.CalendarDialog1.Date);
But when I then ask for the count, it returns 0.
procedure VoegTransToe(naam, betaalpers: string; bedrag: currency;
meebetalers: TStringList; datum: TDateTime);
begin
aantaltrans:= aantaltrans+1;
trans[aantaltrans].naam:=naam;
trans[aantaltrans].pers.naam:=betaalpers;
trans[aantaltrans].bedrag:=bedrag;
trans[aantaltrans].datum:=datum;
meebetalers:= TStringList.Create;
trans[aantaltrans].meebetalers:= TStringList.Create;
trans[aantaltrans].meebetalers.Assign(meebetalers);
meebetalers.Free;
//trans[aantaltrans].meebetalers.Free;
end;
note The difference in name of the variable is because they are in different units
With this code I don't get an error, but it returns 0. When I say //meebetalers.Free; the same happens.
But when I add //trans[aantaltrans].meebetalers.Free; I don't get an error while compiling, but when I call the procedure. Then I get this error:
Project project1 raised exception class 'External: SIGSEGV'.
I think there is something wrong with the Create and Free function, but I don't know what. When I implement the try...finally...end it returns the same error. Can anybody help me?
The problem is that your VoegTransToe() procedure is ignoring the populated TStringList object that is passed in via its meebetalers parameter. You are resetting meebetalers to point at a newly created empty TStringList object just before assigning meebetalers to trans[aantaltrans].meebetalers.
procedure VoegTransToe(naam, betaalpers: string; bedrag: currency;
meebetalers: TStringList; datum: TDateTime);
begin
aantaltrans:= aantaltrans+1;
trans[aantaltrans].naam:=naam;
trans[aantaltrans].pers.naam:=betaalpers;
trans[aantaltrans].bedrag:=bedrag;
trans[aantaltrans].datum:=datum;
// meebetalers:= TStringList.Create; // <-- GET RID OF THIS!
trans[aantaltrans].meebetalers:= TStringList.Create;
trans[aantaltrans].meebetalers.Assign(meebetalers);
//meebetalers.Free; // <-- AND THIS!
end;
Don't forget to Free() the input TStringList object when you are done using it:
slmeebetalers := TStringList.Create;
try
for i := 0 to Form6.CLBox.Count-1 do begin
if Form6.CLBox.Checked[i] then begin
slmeebetalers.Add(Form6.CLBox.Items[i]);
end;
end;
Unit6.VoegTransToe(..., slmeebetalers, ...);
finally
slmeebetalers.Free;
end;

How to get the count of elements in database using delphi XE8

I am trying to make an e-mail sender with Delphi. I have database with statuses and emails and I need to get the number of elements in my database so that I can make a for loop. This is part of my code:
procedure TForm1.bDataBaseClick(Sender: TObject);
var
i : integer;
begin
FDConnection1.StartTransaction;
FDConnection1.Open();
//FDQuery1.ExecSQL('UPDATE Vasko '
//+' SET BatchNumber = 112233 '
//+' WHERE StatusOfProd = 4');
//FDQuery1.ExecSQL('select * from Vasko');
for i := 0 to FDQuery1.ComponentCount - 1 do
showmessage('hello');
FDConnection1.Commit;
FDConnection1.Close();
end;
For now I just want to make the loop that shows message several times. I think that I have mistake in this line:
for i := 0 to FDQuery1.ComponentCount - 1 do
Thank you in advance!

How to output an array that has nested arrays in Pascal

I'm creating a basic concept of a music player using Pascal, but I'm struggling to display the albums inside it. The error I got says "(134, 29) Error: Can't read or write variables of this type". I'm assuming it's saying that because I'm using an array within an array, and it's having a hard time displaying both at the same time (although I only want it to display the albums, not the tracks as well).
Here's what my code looks like:
function ReadAllTrack(prompt: String): Tracks;
var
i: Integer;
trackArray: Array of Track;
trackCount: Integer;
begin
WriteLn(prompt);
trackCount := ReadIntegerGreaterThan1('Please enter the number of tracks you would like to add: ');
Setlength(trackArray, trackCount);
for i := 0 to trackCount - 1 do
begin
WriteLn('Enter the details for your track:');
trackArray[i] := ReadTrack();
end;
result := trackArray;
end;
function ReadAlbum(): Album;
begin
result.albumName := ReadString('Album name: ');
result.artistName := ReadString('Artist name: ');
result.albumGenre := ReadGenre('Genre:');
result.trackCollection := ReadAllTrack('Track Collection:');
end;
function ReadAllAlbums(): Albums;
var
i: Integer;
albumArray: Array of Album;
albumCount: Integer;
begin
albumCount := ReadIntegerGreaterThan1('Please enter the number of albums you would like to add: ');
Setlength(albumArray, albumCount);
for i := 0 to albumCount - 1 do
begin
WriteLn('Enter the details for your album:');
albumArray[i] := ReadAlbum();
end;
result := albumArray;
end;
procedure DisplayAlbumOptions(listOfAllAlbums: Albums);
var
userInput: Integer;
begin
WriteLn('1. Display all albums');
WriteLn('2. Display all albums for a genre');
userInput := ReadIntegerRange('Please enter a number (1, 2) to select: ', 1, 2);
case userInput of
1: WriteLn(listOfAllAlbums); //Error: Can't read or write variables of this type
end;
end;
Basically what this does is it will ask the user showing 5 options:
1. Add albums
2. Display albums
etc
If the user selects 1, the program will ask the user to input the number of albums they want to input. Then for each album it'll ask them to enter the details, and then the tracks.
Then if the user selects 2, the program will ask the user to choose either display every single album there is, or display all albums for a single genre (I'll be working on this one after solving this problem). At first I thought it would be just as simple as WriteLn(TheAlbumArray); but turns out it was more complicated than I thought because I don't think it's possible for the program to display it this way. I tried separating the albums and tracks so that it would only display the albums when I use WriteLn(TheAlbumArray); but it wasn't possible because the tracks still have to be "inside" the album so that when I display the albums and select one of them, it would then display the tracks....
Any help or suggestion for this and/or the second will be much appreciated ^^
Your original question contained a lot of superfluous detail. After the edit, you removed the type declarations, but kept much of the superfluous detail.
However, it is possible to discern the problem you are passing an array of record to Writeln. The Writeln function can accept only certain simple types as arguments, e.g. strings, numerical types, boolean. You certainly cannot pass an array to Writeln. You must iterate over the array and process each member individually.
So you might try
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i]);
But that does not work either, because listOfAllAlbums[i] is a record, and a record is a compound type which cannot be passed to Writeln. So you need to process the record separately. If you want to display just the title, then you write:
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
WriteLn(listOfAllAlbums[i].albumName);
If you want to print the track titles too then you need to iterate over the array contained in the record.
for i := low(listOfAllAlbums) to high(listOfAllAlbums) do
begin
WriteLn(listOfAllAlbums[i].albumName);
for j := low(trackCollection) to high(trackCollection) do
WriteLn(listOfAllAlbums[i].trackCollection[j]);
end;
It is impossible to use composite types (arrays, records, ...) in Read[ln] and Write[ln] procedures.
To make your code more transparent you could to create type helper for your array(s) and use well-known AsString property. Here is example for simple array of Integer:
program foo;
{$mode objfpc}{$H+}
{$modeswitch typehelpers}
uses
Classes, SysUtils;
type
TMyArray = array of Integer;
TMyArrayHelper = type helper for TMyArray
private
function GetAsString: string;
procedure SetAsString(const AValue: string);
public
property AsString: string read GetAsString write SetAsString;
end;
function TMyArrayHelper.GetAsString: string;
var
i: Integer;
begin
Result := '';
for i in Self do
begin
if Result <> '' then
Result := Result + ', ';
Result := Result + IntToStr(i);
end;
Result := '[' + Result + ']';
end;
// Relatively simple parser
// Fill free to implement ones for your array type
procedure TMyArrayHelper.SetAsString(const AValue: string);
var
tmp, s: string;
items: TStringArray;
i: Integer;
begin
tmp := Trim(AValue);
if not (tmp.StartsWith('[') and tmp.EndsWith(']')) then
raise Exception.CreateFmt('Invalid array literal format: "%s"', [tmp]);
tmp := tmp.Trim(['[', ']']);
items := tmp.Split([',']);
for s in items do
try
StrToInt(s);
except
on e: Exception do
raise Exception.CreateFmt('Invalid integer literal: "%s"', [s]);
end;
SetLength(Self, Length(items));
for i := 0 to Length(items) - 1 do
Self[i] := StrToInt(items[i]);
end;
var
a1, a2: TMyArray;
begin
a1.AsString := '[1,2,3,5]';
Writeln('a1 = ', a1.AsString);
a2.AsString := a1.AsString;
a2[1] := 999;
Writeln('a2 = ', a2.AsString);
end.
Helper types in FreePascal
TStringHelper in SysUtils unit

Adding Values to an Array in Pascal - iIllegal Qualifier"

I am trying to create a program that prints 11 buttons so I wanted to use an array. The only change with these buttons is the name.
When I try to compile, I get the error "illegal qualifier" at my first array assignment.
type
buttonName = array[0..11] of String;
procedure PopulateButton(const buttonName);
begin
buttonName[0] := 'Sequence';
buttonName[1] := 'Repetition';
buttonName[2]:= 'Modularisation';
buttonName[3]:= 'Function';
buttonName[4]:= 'Variable';
buttonName[5]:= 'Type';
buttonName[6]:= 'Program';
buttonName[7]:= 'If and case';
buttonName[8]:= 'Procedure';
buttonName[9]:= 'Constant';
buttonName[10]:= 'Array';
buttonName[11]:= 'For, while, repeat';
end;
and in main I am trying to use this for loop
for i:=0 to High(buttonName) do
begin
DrawButton(x, y, buttonName[i]);
y:= y+70;
end;
Please know, I am very new to this and am not too confident of my knowledge in arrays, parameters/calling by constant and such.
Thank you
The parameter definition of PopulateButton() is wrong.
Try this:
type
TButtonNames = array[0..11] of String;
procedure PopulateButtons(var AButtonNames: TButtonNames);
begin
AButtonNames[0] := 'Sequence';
...
end;
...
var lButtonNames: TButtonNames;
PopulateButtons(lButtonNames);
for i := Low(lButtonNames) to High(lButtonNames) do
begin
DrawButton(x, y, lButtonNames[i]);
y:= y+70;
end;
Also pay attention to the naming conventions. Types normally begin with a T and function parameters start with an A.

Cast static array to open array of different element type

(I already asked this at CodeReview where it got closed as off-topic. Hopefully it's on-topic here.)
I have a static arrays of a derived type (like LabelsA: array[0..3] of TLabel; in the following sample code) and a routine accepting an open array of the base type (like procedure DoSomethingWithControls(const AControls: array of TControl);), and I want to call DoSomethingWithControls with those static arrays. Please see my sample:
procedure DoSomethingWithControls(const AControls: array of TControl);
var
i: Integer;
begin
for i := Low(AControls) to High(AControls) do
Writeln(AControls[i].Name);
end;
procedure Test;
var
LabelsA: array[0..3] of TLabel;
LabelsB: array[0..1] of TLabel;
procedure Variant1;
type
TArray1 = array[Low(LabelsA)..High(LabelsA)] of TControl;
TArray2 = array[Low(LabelsB)..High(LabelsB)] of TControl;
begin
DoSomethingWithControls(TArray1(LabelsA));
DoSomethingWithControls(TArray2(LabelsB));
end;
procedure Variant2;
type
TControlArray = array[0..Pred(MaxInt div SizeOf(TControl))] of TControl;
PControlArray = ^TControlArray;
begin
DoSomethingWithControls(Slice(PControlArray(#LabelsA)^, Length(LabelsA)));
DoSomethingWithControls(Slice(PControlArray(#LabelsB)^, Length(LabelsB)));
end;
procedure Variant3;
var
ControlsA: array[Low(LabelsA)..High(LabelsA)] of TControl absolute LabelsA;
ControlsB: array[Low(LabelsB)..High(LabelsB)] of TControl absolute LabelsB;
begin
DoSomethingWithControls(ControlsA);
DoSomethingWithControls(ControlsB);
end;
begin
Variant1;
Variant2;
Variant3;
end;
There are some possible variants of calling DoSomethingWithControls:
Variant 1 is quite simple but needs an "adapter" types like TArray1
for every size of TLabel array. I would like it to be more flexible.
Variant 2 is more flexible and uniform but ugly and error prone.
Variant 3 (courtesy of
TOndrej) is similar to
Variant 1 - it doesn't need an explicit cast, but Variant 1 offers a
tiny bit more compiler security if you mess something up (e.g.
getting the array bounds wrong while copy-pasting).
Any ideas how i can formulate these calls without these disadvantages (without changing the element types of the arrays)? It should work with D2007 and XE6.
These casts are all rather ugly. They will all work, but using them makes you feel dirty. It's perfectly reasonable to use a helper function:
type
TControlArray = array of TControl;
function ControlArrayFromLabelArray(const Items: array of TLabel): TControlArray;
var
i: Integer;
begin
SetLength(Result, Length(Items));
for i := 0 to high(Items) do
Result[i] := Items[i];
end;
And then you call your function like this:
DoSomethingWithControls(ControlArrayFromLabelArray(...));
Of course, this would be so much cleaner if you could use generics.
Not extremely beautiful either but you could trick the compiler like this:
procedure Variant3;
var
ControlsA: array[Low(LabelsA)..High(LabelsA)] of TControl absolute LabelsA;
begin
DoSomethingWithControls(ControlsA);
end;
Declare an overloaded procedure:
procedure DoSomethingWithControls(const AControls: array of TControl); overload;
var
i: Integer;
begin
for i := 0 to High(AControls) do
if Assigned(AControls[i]) then
Writeln(AControls[i].Name)
else
WriteLn('Control item: ',i);
end;
procedure DoSomethingWithControls(const ALabels: array of TLabel); overload;
type
TControlArray = array[0..Pred(MaxInt div SizeOf(TControl))] of TControl;
PControlArray = ^TControlArray;
begin
DoSomethingWithControls(Slice(PControlArray(#ALabels)^, Length(ALabels)));
end;
This is a general solution to your variant2. One declaration for all cases, so less prone to errors.
Below example is based on how open array parameters are internally implemented. It won't work with "typed # operator" however.
procedure Variant4;
type
TCallProc = procedure (AControls: Pointer; HighBound: Integer);
var
CallProc: TCallProc;
begin
CallProc := #DoSomethingWithControls;
CallProc(#LabelsA, Length(LabelsA) - 1);
CallProc(#LabelsB, Length(LabelsB) - 1);
end;
Passing High(Labels) for HighBound is perhaps better as long as all static arrays are 0 based.
Since a dynamic array can be passed into method as an open array, and option would be to convert the static array to a dynamic array.
If you don't mind the overhead of copying the array, consider the following:
Write a function to convert an open array of labels into a dynamic TControlArray array.
type
TControlArray = array of TControl;
{$IFOPT R+} {$DEFINE R_ON} {$R-} {$ENDIF}
function MakeControlArray(const ALabels: array of TLabel): TControlArray;
begin
SetLength(Result, Length(ALabels));
Move(ALabels[0], Result[0], Length(ALabels) * SizeOf(TObject));
end;
{$IFDEF R_ON} {$R+} {$UNDEF R_ON} {$ENDIF}
Now Variant4 can be written as:
procedure Variant4;
begin
DoSomethingWithControls(MakeControlArray(LabelsA));
DoSomethingWithControls(MakeControlArray(LabelsB));
end;
Test cases:
procedure TAdHocTests.TestLabelsToControls;
const
LLabelsA: array[0..3] of TLabel = (Pointer(0),Pointer(1),Pointer(2),Pointer(3));
var
LLoopI: Integer;
LLabelsB: array[0..9] of TLabel;
LEmptyArray: TLabelArray;
begin
for LLoopI := Low(LLabelsB) to High(LLabelsB) do
begin
LLabelsB[LLoopI] := Pointer(LLoopI);
end;
DoSomethingWithControls(MakeControlArray(LLabelsA), Length(LLabelsA));
DoSomethingWithControls(MakeControlArray(LLabelsB), Length(LLabelsB));
DoSomethingWithControls(MakeControlArray([]), 0);
DoSomethingWithControls(MakeControlArray(LEmptyArray), 0);
end;
procedure TAdHocTests.DoSomethingWithControls(
const AControls: array of TControl;
AExpectedLength: Integer);
var
LLoopI: Integer;
begin
CheckEquals(AExpectedLength, Length(AControls), 'Length incorrect');
for LLoopI := Low(AControls) to High(AControls) do
begin
CheckEquals(LLoopI, Integer(AControls[LLoopI]));
end;
end;

Resources