Retrieve values from database to StringGrid - delphi

In connection with my previous question
I've successfully save string values in StringGrid to my database in one column.
Now I want to retrieved the values from database and put it back from StringGrid.
This is what I've tried :
procedure TForm1.BitBtn1Click(Sender: TObject);
var i, iRow, iCol: integer ;
s : string;
Grid2: TStringGrid;
strArray : Array of String;
charArray : Array[0..0] of Char;
begin
getRecords;
with SqlQuery4 do
begin
if RecordCount <> 0 then
begin
names := FieldByName('names').AsString;
s := names;
charArray[0] := '|';
strArray := s.Split(charArray);
Grid2 := Form7.StringGrid1;
i := 0;
iCol:= 0;
iRow:=0;
for iRow := 1 to 19 do // increment rows
begin
for iCol := 0 to 5 do // increment cols / max 5 cols
begin
if iCol = 5 then iCol := 0; // reset column so that it will go on next row
for i := 0 to Length(strArray)-1 do // get string one by one
begin
Grid2.RowCount := Grid2.RowCount + 1; // add row
Grid2.Cells[iCol, iRow] := strArray[i]; // this value always overwrite, how to save this previous data?
end;
end;
end;
end;
end;
end;
It adds row but doesn't get the values in database..

You are missing the First and Next methods for moving in a TDataSet of the query object SqlQuery4
This code could work:
procedure TForm1.BitBtn1Click(Sender: TObject);
var i, iRow, iCol: integer ;
s : string;
Grid2: TStringGrid;
strArray : Array of String;
charArray : Array[0..0] of Char;
begin
getRecords;
with SqlQuery4 do
begin
First; //SqlQuery4 goes to the first row returned by the SQL query
if RecordCount <> 0 then
begin
names := FieldByName('names').AsString;
s := names;
charArray[0] := '|';
strArray := s.Split(charArray);
Grid2 := Form7.StringGrid1;
i := 0;
iCol:= 0;
iRow:=0;
for iRow := 1 to 19 do // increment rows
begin
for iCol := 0 to 5 do // increment cols / max 5 cols
begin
if iCol = 5 then iCol := 0; // reset column so that it will go on next row
for i := 0 to Length(strArray)-1 do // get string one by one
begin
Grid2.RowCount := Grid2.RowCount + 1; // add row
Grid2.Cells[iCol, iRow] := strArray[i]; // this value always overwrite, how to save this previous data?
end;
end;
Next; //SQLQuery goes to the next row available of the data set reurned by the SQL query
end;
end;
end;
end;
The basic way when you open a set of rows (a data set in Delphi) using a SQL query is something like this:
Procedure TForm1.ProcessData;
begin
{
The SQL query may look like:
SELECT *
FROM TABLE
WHERE
COLUMN1 = :PARAMETER1 AND /*Column1 is a VARCHAR */
COLUMN2 = :PARAMETER2 /*Column2 is a Integer*/
}
//If already open, the close it
if Query1.Active then
Query1.Close;
//Load some parameters from some components
Query1.ParamByName('PARAMETER1').AsString := Edit1.Text;
Query1.ParamByName('PARAMETER2').AsInteger := ComboBox1.ItemIndex;
//Open the SQL query
Query1.Open;
Query1.First; //We assure that the we are on the first record
while Not Query1.Eof do //Get into a whiile loop, exit when gets the end of the rows list returned by the Query1 object
begin
{
Your processing code goes here
}
Query1.Next; //Now you advance to the next row to process it, if there is no more rows EOF become TRUE (EOF(stans for End Of File)
end
Query1.Close; //is a good idea to close the query if you not longer need it to save resources
end;

Related

Print in another row if subrpeort has many records

I have a fastreprot with a subreport.
When record count of subrpeort is greater than five, I want to print rest of the subreport records in another detaildata record (in main report).
The detail data band cannot stretch because it's a label and size is per-defined.
I'm trying something like this:
var
TwoRows: boolean;
procedure MasterDataSubOnBeforePrint(Sender: TfrxComponent); //Sub Report
begin
if not TwoRows then
exit;
if DetailData1.RowNo = 1 then
begin
end;
if DetailData1.RowNo = 2 then
begin
MasterDataSub.DataSet.next;
MasterDataSub.DataSet.next;
MasterDataSub.DataSet.next;
MasterDataSub.DataSet.next;
MasterDataSub.DataSet.next;
end;
end;
procedure DetailData1OnBeforePrint(Sender: TfrxComponent); //Main Report
begin
TwoRows := false;
if MasterDataSub.DataSet.RecordCount > 5 then
begin
DetailData1.RowCount := 2;
TwoRows := true;
end
else
DetailData1.RowCount := 1;
end;
But RowNo is not defined.
How to get RowNo?

Delphi: Adding Combobox Dropdown to TADVStringGrid

I have a form that has a TADVStringGrid. I am trying to add a combobox to some rows in a specific column (2); however, I can't get the data to show on the dropdown. I added the HasComboBox event, I set the DirectComboDrop, and it still did not show any data in the dropdown. They were just empty. I check the object that I am adding to the dropdown, and they had data. What am I missing here?
procedure UserForm.DisplayGrid(Sender: TObject);
var
J : Integer;
begin
... additional logic
...
if OutputList.Count > 2 then
begin
with UserGrid.Combobox do
begin
for J := 0 to OutputList.Count - 1 do
BEGIN
if not(OutputList[J] = '') then
begin
dValue := DropDownValue.Create;
dValue.ID := J + 1;
dvalue.Name := OutputList[J];
dvalue.TestValue := OutputList[J] + 'testvalue'; // where value will be a list to choose from
ListOfTest.Add(dValue); // this is a glabal variable where I for later reference
ItemIndex := dValue.ID;
end;
END;
end;
end;
//event
procedure UserForm.UserGridHasComboBox(Sender: TObject; ACol, ARow: Integer;
var HasComboBox: Boolean);
begin
HasComboBox := True;
end;
There is an event handle called EditorProp that needed to be added. Data that need to be added for a specific column have to be added when the EditorProp event is called. The piece of code below was moved into the editorprop event, and it's working fine since.
for J := 0 to OutputList.Count - 1 do
BEGIN
if not(OutputList[J] = '') then
begin
dValue := DropDownValue.Create;
dValue.ID := J + 1;
dvalue.Name := OutputList[J];
dvalue.TestValue := OutputList[J] + 'testvalue'; // where value will be a list to choose from
ListOfTest.Add(dValue); // this is a glabal variable where I for later reference
ItemIndex := dValue.ID;
end;

Wrong data moving from TListbox to TStringGrid

I am working on Delphi 7. I have one TListBox and one TStringGrid with two columns (with no fixed row or column). I have data in the TListBox as follows:
Available Elements - a123 (a123)
Available Elements - a1234 (a1234)
Available Elements - a12345 (a12345)
And the TStringGrid is having following data as follows:
Column1 Column2
a1 Available Elements - a1
a2 Available Elements - a12
If I select the first item in the TListbox i.e. a123 and execute following button click event procedure, then the last item data ie a12345 is getting moved into the grid.
Could anybody put the focus on what I am doing wrong in the following code. Following code moves the seleted item in the TListbox to TStringgird's two columns:
procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
sString : String;
i : Integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do
begin
{-- Is this status selected? --}
if ListBox1.Selected[i] then
begin
sString := Trim(ListBox1.Items[i]);
{-- Delete selected status. --}
ListBox1.Items.Delete (i);
if ((grdVFormDetails.RowCount >= 1) And (Trim(grdVFormDetails.Cells[0, 0]) <> EmptyStr)) then
grdVFormDetails.RowCount := grdVFormDetails.RowCount+1;
grdVFormDetails.Cols[1].Add(Copy(sString, 1, Pos('(', sString) - 1));
sString := Copy(sString, Pos('(', sString) + 1, Length(sString));
sString := Copy(sString, Pos('(', sString) + 1, Length(sString) - 1);
grdVFormDetails.Cols[0].Add(sString);
break;
end;
end;
end;
NEVER delete Items of TList in the FOR loop.
The issue in this line:
ListBox1.Items.Delete (i);
The loop goes from i:=0 to 2. Item - 0 is selected and you delete it. What we got on the next repeat? i=1 but here are only 2 items left instead of 3 (all following items shifted) and i points at the last item not the second. On the next repeat when i=3 we will get "Index out of bound" error. You should delete Item only after FOR loop to avoid this issue.
procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
sString : String;
i : Integer;
k: integer;
begin
k:=-1;
for i := 0 to ListBox1.Items.Count - 1 do
begin
{-- Is this status selected? --}
if ListBox1.Selected[i] then
begin
sString := Trim(ListBox1.Items[i]);
{-- Delete selected status. --}
k:=i;
if ((grdVFormDetails.RowCount >= 1) And (Trim(grdVFormDetails.Cells[0, 0]) <> EmptyStr)) then
grdVFormDetails.RowCount := grdVFormDetails.RowCount+1;
grdVFormDetails.Cols[1].Add(Copy(sString, 1, Pos('(', sString) - 1));
sString := Copy(sString, Pos('(', sString) + 1, Length(sString));
sString := Copy(sString, Pos('(', sString) + 1, Length(sString) - 1);
grdVFormDetails.Cols[0].Add(sString);
break;
end;
end;
if k>=0 then ListBox1.Items.Delete (k);
end;
Assuming, you want to parse the input string like this:
'Some text (comment) etc. (12345)'
into a part with a trimmed string from the beginning to the first opening parenthesis (first from the end) of the input string to get a value like this:
'Some text (comment) etc.'
and the string from inside the last parentheses of the input string:
'12345'
If so, you can use the code that follows. Note that is expected to have list box items terminated by closing parentheses. You may check the commented version of this code or download a sample project if you want.
Here is the part, which moves the focused item from the list box to the string grid:
procedure TForm1.MoveLeftButtonClick(Sender: TObject);
var
S: string;
I: Integer;
ItemID: string;
ItemText: string;
begin
if ListBox1.ItemIndex = -1 then
Exit;
S := ListBox1.Items[ListBox1.ItemIndex];
for I := Length(S) - 1 downto 1 do
begin
if S[I] = '(' then
begin
ItemID := Trim(Copy(S, I + 1, Length(S) - I - 1));
ItemText := Trim(Copy(S, 1, I - 1));
with StringGrid1 do
begin
if (Cells[0, RowCount - 1] <> '') and
(Cells[1, RowCount - 1] <> '')
then
RowCount := RowCount + 1;
Cells[0, RowCount - 1] := ItemID;
Cells[1, RowCount - 1] := ItemText;
end;
ListBox1.Items.Delete(ListBox1.ItemIndex);
Break;
end;
end;
end;
And here is the part which moves the selected row from the string grid to the list box:
procedure TForm1.MoveRightButtonClick(Sender: TObject);
var
I: Integer;
RowIndex: Integer;
begin
RowIndex := StringGrid1.Selection.Top;
if (StringGrid1.Cells[0, RowIndex] <> '') and
(StringGrid1.Cells[1, RowIndex] <> '') then
begin
ListBox1.Items.Add(
Trim(StringGrid1.Cells[1, RowIndex]) + ' (' +
Trim(StringGrid1.Cells[0, RowIndex]) + ')'
);
for I := RowIndex to StringGrid1.RowCount - 2 do
StringGrid1.Rows[I].Assign(StringGrid1.Rows[I + 1]);
if StringGrid1.RowCount > 1 then
StringGrid1.RowCount := StringGrid1.RowCount - 1
else
begin
StringGrid1.Cells[0, 0] := '';
StringGrid1.Cells[1, 0] := '';
end;
end;
end;
I do not have Delphi installed at the moment, though as far as I remember, if ListBox1.Selected[i] then will not give you correct result. You need to get the item firstly,
them check if the item is selected.
If you don't have multi-select in the ListBox, better use the ItemIndex property, which gives you the Index of the selected Item, thus you don't have to loop to check all the Items in the list.
Like this:
procedure TForm1.btnMoveLeftClick(Sender: TObject);
var
sString : String;
i : Integer;
begin
if ListBox1.ItemIndex <> -1 then
begin
sString := Trim(ListBox1.Items[ListBox1.ItemIndex]);
//do all your processing here
//and at the end:
ListBox1.Items.Delete(ListBox1.ItemIndex);
end
end;

how to get two different file with this procedure in deplhi

i want to get value from two file .txt, one file contain different dimension matrix with other
i have try this code:
procedure TfrmJST.ParseDelimited(const S1: TStrings; const Value: String; const Delimiter: String);
var
dx,cx: integer;
ns,ms: String;
txt: string;
delta,teta: integer;
procedure TfrmJST.ParseDelimited(const S1: TStrings; const Value: String; const Delimiter: String);
var
dx,cx: integer;
ns,ms: String;
txt: string;
delta,teta: integer;
begin
Col := 1;
Delta := Length(Delimiter);
Txt := Value+Delimiter;;
begin
while Length(Txt) > 1 do
begin
Dx := Pos(Delimiter, Txt);
Ns := Trim(Copy(Txt, 1, Dx-1));
// S1.Add('#'+Ns+'*'); //only needed for testing
if Ns <> '' then
begin
Matrix[Row,Col] := StrToFloat(Ns); //for first matrix
Inc(Col);
end;
Txt := Copy(Txt, Dx+Delta, MaxInt);
end;
end;
Col := 1;
teta := Length(delimiter);
txt := value+delimiter;
begin
while Length(txt) > 1 do
begin
cx := Pos(delimiter, txt);
ms := Copy(txt, 1, cx-1);
if ms <> '' then
begin
ref[Row,Col] := StrToFloat(ms); ///for 2nd matrix
Inc(Col);
end;
txt := Copy(txt, cx+teta, MaxInt);
end;
end;
end;
and this is initialize of matrix:
private
{ Private declarations }
Row, Col: integer;
Matrix: array[1..140,1..141] of double;
Ref: array[1..2,1..140] of double ;
this is the implementation:
begin
Temp := TStringList.Create;
MemoSL:= TStringList.Create ;
Temp.LoadFromFile('trainer.txt');
Row := 1;
for I := 0 to Temp.Count-1 do
begin
ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
Inc(Row); //stackoverflow error in this line
end;
Temp.Free;
//parsing second matrix
TempList := TStringList.Create;
Templist.LoadFromFile('refbaru.txt');
row := 1;
for J := 0 to Templist.Count-1 do
begin
T := Templist[J];
ParseDelimited(Memo1.Lines, T, ' ');
Inc(row);
end;
Templist.Free;
i tried that code but give me error,
the error was stackoverflow error in line 'inc(row)' that process first matrix.
and while i gave comment out at the second function that process 2nd matrix, Temp[i] only returns 2 rows of matrix[140x141]. does it mean the code can't process two different file? and why it only return two rows of the matrix?
anyone can help me?
while Length(Txt) > 1 do
begin
Dx := Pos(Delimiter, Txt);
Ns := Trim(Copy(Txt, 1, Dx-1));
// S1.Add('#'+Ns+'*'); //only needed for testing
if Ns <> '' then
begin
Matrix[Row,Col] := StrToFloat(Ns); //for first matrix
Inc(Col);
end;
Txt := Copy(Txt, Dx+Delta, MaxInt);
end;
Looking at this piece of code I see the posibility of an endless loop: what happens if there is no Delimiter found? It will keep running and forever increase your 'col' value. Make sure to have a condition to stop your while loop if no delimeter is found.
It is pointless to look for a specific stack overflow error when many ordinary errors already exist.
If your code is clean programmed and it is still stack overflow, then of course, is time to look deeper into the code.
But first ! As long as you can see obvious errors, you should remove them.
1.) "Row" used in the same procedure on a 140 dimension array and on a only 2 dimension array.
How can that work ?
Matrix: array[1..140,1..141] of double;
Ref: array[1..2,1..140] of double ;
File 'trainer.txt' 140 Lines
File 'refbaru.txt' 2 Lines.
for I := 0 to Temp.Count-1 do // 140 lines
// ParseDelimited() will only run properly if Row < 3
// remember -> Ref: array[1..2,1..140])
// if Row > 2 , with Ref[Row,Col] := , 137 times data is overwritten.
procedure ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
....
Matrix[Row,Col] := StrToFloat(Ns);
....
Ref[Row,Col] := StrToFloat(ms);
....
end;
Inc(Row);
end;
2.) If you run the second loop with refbaru.txt and the two arrays are present together in the procedure ParseDelimited(), then you overwrite 2 values of array Matrix
recommendation
make sure: Loop through trainer.txt, writes values only to the Matrix array.
make sure: Loop through refbaru.txt, writes values only to the Ref array.
Your code could look something like:
[...]
filetoload: String;
[...]
procedure TfrmJST.ParseDelimited(S1: TStrings; Value: String; const Delimiter: String);
var
f:double;
[...]
Col := 1;
txt := Value+Delimiter;
[...]
if filetoload='trainer.txt' then begin
Delta := Length(Delimiter);
while Length(txt) > 1 do
begin
Dx := Pos(Delimiter, txt);
Ns := Trim(Copy(txt, 1, Dx-1));
if Ns <> '' then
begin
if TryStrToFloat(Ns,f) then Matrix[Row,Col]:=f;
Inc(Col);
if Col > MatrixColMax then break;
txt := Copy(txt, Dx+Delta, MaxInt);
end else txt:='';
end;
end;
if filetoload='refbaru.txt' then begin
teta := Length(delimiter);
while Length(txt) > 1 do
begin
cx := Pos(delimiter, txt);
ms := Copy(txt, 1, cx-1);
if ms <> '' then
begin
if TryStrToFloat(ms,f) then Ref[Row,Col]:=f;
Inc(Col);
if Col > RefColMax then break;
txt := Copy(txt, cx+teta, MaxInt);
end else txt:='';
end;
end;
begin
[...]
filetoload:='trainer.txt';
Temp := TStringList.Create;
Temp.LoadFromFile(filetoload);
if Temp.Count > MatrixRowMax then LinesToLoad:=MatrixRowMax-1 else
LinesToLoad:=Temp.Count-1;
for I := 0 to LinesToLoad do
[...]
ParseDelimited(MemoSL, Trim(Temp.Strings[I]), ' ');
[...]
end;
filetoload:='refbaru.txt';
TempList := TStringList.Create;
TempList.LoadFromFile(filetoload);
if TempList.Count > RefRowMax then LinesToLoad:=RefRowMax-1 else
LinesToLoad:=TempList.Count-1;
for J := 0 to LinesToLoad do
[...]
ParseDelimited(Memo1.Lines, T, ' ');
[...]
end;
end;
You should also compare the linesize of the file with the size of the arrays
RefRowMax: integer;
RefColMax: integer;
MatrixRowMax: integer;
MatrixColMax: integer;
LinesToLoad: integer;
....
RefRowMax:=2;
RefColMax:=140;
MatrixRowMax:=140;
MatrixColMax:=141;
....
procedure ParseDelimited()
if filetoload='trainer.txt' then begin
[...]
Inc(Col)
if Col > MatrixColMax then break;
end;
if filetoload='refbaru.txt' then begin
[...]
Inc(Col)
if Col > RefColMax then break;
end;
You should also look for a valid value of Ns , StrToFloat(Ns) before you write to the arrays in ParseDelimited()
function TryStrToFloat(const S: string; out Value: Double): Boolean;
or
Val();
var
f:double;
....
begin
....
if TryStrToFloat(Ns,f) then Matrix[Row,Col]:=f;
....
The OP overwritting many of used data.
And when he has enough data overwritten, he gets a stack overflow error.

How to get selected cell text from TcxGrid?

I'm using Devexpress TcxGrid and I'm trying to get selected cell text. My TcxGrid is connected to some kind of DataSource - I think it is DataControler.
My goal is to get the text from cells in the entire row and place it in string divided with comas.
If you want values with multiselection and from a TcxGridDbTableView:
In my result i don't have a separation between rows.
function GetSelectedValuesFrmGrid: String;
var
intSelectLoop,
intRowLoop: Integer;
oTableView: TcxGridDbTableView;
strValue: Variant;
oList: TStringList;
begin
Result:= '';
// Kind Of TableView
if <TcxGrid>.ActiveView is TcxGridDbTableView then
begin
oTableView:= <TcxGrid>.ActiveView as TcxGridDbTableView;
oList:= TStringList.Create();
try
for intSelectLoop:= 0 to oTableView.Controller.SelectedRowCount-1 do
begin
for intRowLoop:= 0 to oTableView.Controller.SelectedRows[intSelectLoop].ValueCount-1 do
begin
strValue:= oTableView.Controller.SelectedRows[intSelectLoop].Values[intRowLoop];
// Value can be Null
if VarIsNull(strValue) then
begin
strValue:= '';
end;
oList.Add(strValue);
end;
end;
Result:= oList.CommaText;
finally
oList.Free;
end;
end;
end;
You need the text from all cells in selected rows?
for I := 0 to cxGridDBTableView.Controller.SelectedRowCount -1 do
for J := 0 to cxGridDBTableView.Controller.SelectedRows[I].ValueCount -1 do
SelectedRowStr := SelectedRowStr + VarToStr(cxGrid1DBTableView1.Controller.SelectedRows[I].Values[J]) + ',';
SelectedRowStr := Copy(SelectedRowStr,1,length(SelectedRowStr)-1);
The grid will have a DataControler descendant. You can cycle through the items in the DataController and, depending on how your grid is configured, the items in the DataController can correspond to individual 'columns' shown in your grid. That being said the items in a DataController stay in ther
This code will let you cycle through each column in the grid and build up the string based on the DataController values.
var
i: Integer;
DC: TcxCustomDataController;
s: string;
begin
s := '';
DC := <yourgrid>.DataController;
for i := 0 to <yourgrid>.ColumnCount -1 do begin
s := s + vartostr(DC.Values[DC.FocusedRecordIndex, <yourgrid>.Columns[i].Index]) + ',';
end;
if Length(s) > 0 then
s := Copy(s,1,Length(s)-1);
end;

Resources