ClientDataSet records (move once +1 once -1) - delphi

In the Jvdbgrid1 table, I always have only two ClientDataSet records.
When I am on the first record, how to go on the second record and conversely.
When I am on the second record, how to go on the first record.
So (buttonClick) once the record is +1 once -1
How to save this in code?

When you are on the second record and want to get to the first one, just call
ClientDataSet1.MoveBy(-1)
When on the first record, to get to the second, call
ClientDataSet1.MoveBy(1)
But if you want your app to do this automatically, it's easier to use .Next and .Prior, as in
procedure TForm1.ToggleRecord;
begin
ClientDataSet1.Next;
if ClientDataSet1.Eof then
ClientDataset1.Prior;
end;
Update The cleanest/simplest equivalent to what you do in your answer seems to be
procedure TForm1.PlayFile;
begin
ShowMessage(IntToStr(ClientDataSet1.RecNo));
end;
procedure TForm1.ToggleRecord2;
var
Distance : Integer;
begin
if ClientDataSet1.RecNo = 2 then
Distance := -1
else
Distance := 1;
ClientDataSet1.MoveBy(Distance);
PlayFile;
Distance := - Distance;
ClientDataSet1.MoveBy(Distance);
end;
but it is pretty much a matter of taste. Ymmv ...

In the end I succeeded :)
That's exactly what I meant. Question to you.
You can write this code more sensibly (better)
procedure TForm1.btn1Click(Sender: TObject);
begin
if assigned(idictionary) then
begin
if ClientDataSet1.RecNo = 1 then
begin
ClientDataSet1.Next;
PlayFile;
ClientDataSet1.Prior;
end;
if ClientDataSet1.RecNo = 2 then
begin
ClientDataSet1.Prior;
PlayFile;
ClientDataSet1.Next;
end;
end;
end;

Related

Recursive procedure for getting child records in hierarchical dataset

I have a data table (MDTasks) that has records represented in a tree view. Each record has a unique field, 'ID', and a field 'Parent_ID', which refers to the ID of the parent. I am trying to make a list of all the children at any level of a record with a given ID. I have the following, which gets the first child at each level, but doesn't go back up to get the siblings at any level. I would be grateful for any help. Thank you.
procedure TfmList.GetChildren(TaskID: integer);
var
iChildID: integer;
begin
with MDTasks do
begin
first;
while not EOF do
begin
if FieldByName('Parent_ID').AsInteger = TaskID then
begin
iChildID := FieldByName('ID').AsInteger;
Memo1.Lines.Add(IntToStr(iChildID));
GetChildren(iChildID);
end;
next;
end;
end;
end;
The code below should do what you want, if I understand you correctly. It uses a ClientDataSet so that my answer is self contained and so that the test data can easily be set up.
It uses a call to CloneCursor to do the recursive search for the children of the specified parent node ID.
procedure TForm1.FormCreate(Sender: TObject);
begin
CDS1.CreateDataSet;
CDS1.InsertRecord([1, -1]);
CDS1.InsertRecord([2, -1]);
CDS1.InsertRecord([3, -1]);
CDS1.InsertRecord([4, 2]); // This and the following rows are all children of ID = 2
CDS1.InsertRecord([5, 2]);
CDS1.InsertRecord([6, 4]);
CDS1.InsertRecord([7, 4]);
CDS1.InsertRecord([8, 7]);
FindChildren(2);
end;
procedure TForm1.FindChildren(ParentID : Integer);
procedure FindChildrenInner(ParentID : Integer);
var
TempCDS : TClientDataSet;
ID : Integer;
begin
TempCDS := TClientDataSet.Create(Nil);
try
TempCDS.CloneCursor(CDS1, False, True);
TempCDS.First;
while not TempCDS.Eof do begin
if TempCDS.FieldByName('Parent_ID').AsInteger = ParentID then begin
ID := TempCDS.FieldByName('ID').AsInteger;
Memo1.Lines.Add(Format('ID: %d, Parent: %d', [ID, ParentID]));
FindChildrenInner(ID);
end;
TempCDS.Next;
end;
finally
TempCDS.Free;
end;
end;
begin
Memo1.Lines.BeginUpdate;
try
Memo1.Lines.Clear;
Assert(CDS1.Locate('ID', ParentID, []));
FindChildrenInner(ParentID);
finally
Memo1.Lines.EndUpdate;
end;
end;
Looking at the code, I would say that it gets all the childs at the last level (not only first one). The problem is that you "share" the dataset (MDTasks) between levels - so when the last level iterates to the end of the table and returns to the caller the while not EOF do evaluates to false (on the parent level now) and loop ends, thus only the first child is gotten on levels above the last one.
One solution would be to iterate each level fully, logging Parent_IDs into local array, then use that array to get the next level below it.
Another solution is probably to use bookmarks in the table MDTasks. Let your procedure set a bookmark at the beginning and return to this bookmark at the end so the position/cursor in MDTasks is not changed from GetChildren.
your problem is that you are calling recursive function against the same data. you can use filtering, for example:
procedure GoGoGo (Id: integer);
var
OldFilter: string;
begin
OldFilter := Table.Filter;
Table.Filter := 'ParentId = ' + IntToStr (Id);
try
Table.First;
while not Table.Eof do begin
Memo.Lines.Add (Format('ID: %d, Parent: %d',
[Table.FieldByName ('I'd).AsInteger,
Table.FieldByName ('ParentID').AsInteger]));
GoGoGo (Table.FieldByName ('Id').AsInteger);
if Table.Locate ('Id', Id, []) then
Table.Next;
end;
finally
Table.Filter := OldFilter;
end;
end;
<...>
Memo.Lines.Clear;
Table.Filtered := TRUE;
Table.First;
GoGoGo (Table.FieldByName ('Id').AsInteger);
haven't tested this code, it may contain errors, but hopefully, idea is quite clear. with the same idea you can use another approaches, like create new TQuery with dynamically generated where clause, etc. I'm not a fan of such things just because in a really big tree, creating new objects in every iteration of recursive function may result in a stack overflow.
gl there ;)

Insert column into string grid, delphi

I have a string grid, from which i can delete columns. I defined a CustomStringGrid type that allows me to use DeleteColumn method.
This is how it looks:
TCustomStringGrid = class(TStringGrid)
[...]
With tCustomStringGrid(mygrid) do
DeleteColumn(col)
end;
IS there something similar to add a column? I've tried InsertColumn but it doesn't seem to exist. I want to add a column at a particular position. In fact, if a user deletes a column i have an undo button which i want to reinsert the deleted column (i'm keeping the data in an array so i can recreate the column but i don't know how to insert one in a particular position).
Thank you!
It's not built in but easy to emulate, with ColCount = ColCount + 1 and MoveColumn from a HackClass.
type
THackGrid=Class(Grids.TCustomGrid)
End;
Procedure InsertColumn(G:TStringGrid;Position:Integer);
begin
if Position<G.ColCount then
begin
G.ColCount := G.ColCount + 1;
THackGrid(g).MoveColumn(G.ColCount - 1,Position);
end;
end;
procedure TMyForm.Button1Click(Sender: TObject);
begin
InsertColumn(StringGrid1,1);
end;
THack grid is not working, maybe it is ok when both cols are visible, but that works always :
Procedure MoveColumn(G:TStringGrid;OldPosition : integer;NewPosition:Integer);
var
i : integer;
temp : string;
begin
for i := 0 to g.rowcount - 1 do
begin
temp := g.cells[OldPosition,i];
g.cells[OldPosition,i] := g.cells[NewPosition,i];
g.cells[NewPosition,i] := temp;
end;
end;

How to delete selected records from TDBAdvGrid?

I want to delete multiple selected records which I have displayed at TDBAdvGrid. A number of records are being selected by checking checkbox in front of them. After clicking on Delete button it triggers procedure as follows. It is returning values of selected rows id successfully only problem with deletion of all records. It deletes only first selected record.
procedure TForm5.Button3Click(Sender: TObject);
var
i,j,idn: Integer;
State: Boolean;
begin
j := 0;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
idn := StrToInt(DBAdvGrid1.Cells[6,i]);
UniQuery1.SQL.Text := 'Delete from userplays where id = :id';
UniQuery1.ParamByName('id').AsInteger := idn;
UniQuery1.ExecSQL;
end;
end;
end;
end;
It is deleting only first record in lineup. After deleting first record it breaks for loop and control goes back to TDBAdvGrid with updated data after delete.
Final code based on suggestion is as follows
j := 0;
DBAdvGrid1.BeginUpdate;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
showmessage('inside rowcount loop');
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
DBAdvGrid1.DataSource.DataSet.First;
DBAdvGrid1.DataSource.DataSet.MoveBy(i - 1 - j);
DBAdvGrid1.DataSource.DataSet.Delete;
j := j+1;
continue;
end;
end;
end;
This code works perfectly only when PageMode := False
Based on the suggestion above, I would like to make another suggestion...
//DBAdvGrid1.BeginUpdate;
query.First;
for i := 1 to DBAdvGrid1.RowCount - 1 do
begin
if DBAdvGrid1.GetCheckBoxState(1,i,state) then
begin
if state then
begin
//you can do whatever you want with the current selected record
end;
end;
query.Next;
end;
I think this is easier then using the MoveBy...
I even never changed PageMode, it's still on true. No idea if it's coincidence or not.
You can use cyBookmarks in the OnCheck event , with Virtual Table.
It creates a list of all records selected, and you can list them with
cyBookmarks.bookmarklits.count, so my example is like this :
procedure TForm2.cyDBGrid1CheckBoxClick(Sender: TObject);
begin
if cyBookmarks1.AddCurrentRecord then
begin
cyBookmarks1.BookmarkList.InsertBookmark(cyDBGrid1.CheckedList.CurrentRecord);
cyDBGrid1.Invalidate ;
end
else
begin
cyBookmarks1.RemoveCurrentRecord;
cyDBGrid1.Invalidate;
end;
if cyBookmarks1.BookmarkList.Count>0 then
begin
VirtualTable1.GotoBookmark(cyBookmarks1.BookmarkList.Items[0]);
lbl1.Caption:=VirtualTable1.FieldByName('N_ENREGISTREMENT').AsString;
end;
end;

Delphi Timer issue

procedure TForm1.Timer1Timer(Sender: TObject);
var
i : integer;
begin
if i > StrToInt(Edit1.Text) then
Timer1.Enabled := False
else
i :=+ 1;
SendClick(645,302);
Sleep(2200);
SendClick(694,619);
Sleep(2200);
SendClick(967,638);
Sleep(2200);
SendKeys('{BKSP}{BKSP}{BKSP}{BKSP}1',False);
SendClick(917,688);
Sleep(2200);
SendClick(917,688);
Sleep(2200);
SendClick(917,688);
amount := StrToInt(Label3.Caption) + 1;
Label3.Caption := IntToStr(amount);
end;
for some reason it repeats only 1 time and stops... can anyone spot a problem? im pretty tired and ive went over and over it a few times and i can't seem to see one...
I is a uninitialized local variable (it contains garbage), so the result of the comparision if i > StrToInt(Edit1.Text) is random.
You may want to add a member variable to your form's class, initialize at the proper time and check it's value on the onTimer event, something like:
type
TForm1 = class(TForm)
..
private
FTimerCount: Integer;
FMaxTimerCount: Integer;
..
procedure TForm1.Button1Click(Sender: TObject);
begin
FTimerCount := 0;
FMaxTimerCount := 20; //the timer will fire 20 times.
Timer1.Enabled := True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Inc(FTimerCount);
Timer1.Enabled := FTimerCount < FMaxTimerCount;
DoOtherStuff();
end;
The line
i :=+ 1;
assigns the value +1 (also known as 1) to the variable named i. (That is, if i is equal to 55, and you do i :=+ 1, then i will be equal to 1.)
Perhaps you are seeking
i := i + 1;
or
inc(i);
?
You're not initializing i, it is a local variable. Hence the timer can be enabled or not depending on the arbitrary value it's memory location holds.
This is a well case that people just ignore the Warning message.
I wish that compiler should spit out Hint or Error and No Warning. Warning is just a case that short comming from compiler and it should be fixed at later version.
Cheers

to retrieve stringlist items in memo from table POS_CatBreakDownValue into tchecklistbox

i have a problem on how to retrieve the items in memo from table into tchecklistbox...before this i do the procedure to insert the items that have been checked into memo in tbl POS_CatBreakDownValue..but now i want to know how to retrieve items from table and automatic check in tchecklistbox...thanks..here my procedure to insert the checklist into memo in table..i hope anyone can help me..thanks
procedure TfrmSysConfig.saveCatBreakDownValue;
var
lstCat:TStringList;
i :integer;
begin
lstcat := TStringList.Create;
try
for i:=0 to clCat.Items.Count-1 do begin
if clCat.Checked[i] then begin
lstcat.Add(clcat.Items.Strings[i]);
end;
end;
tblMainPOS_CatBreakDownValue.Value := lstCat.Text;
finally
lstcat.Free;
end;
end;
procedure TfrmSysConfig.saveCatBreakDownValue;
var
lstCat: TStringList;
i:integer;
begin
lstcat := TStringList.Create;
try
for i:=0 to clCat.Items.Count-1 do begin
if clCat.Checked[i] then begin
lstcat.Add(clcat.Items.Strings[i]);
end;
end;
tblMainPOS_CatBreakDownValue.Value := lstCat.Text;
finally
lstcat.Free;
end;
end;
Reading your code I'm guessing you've got a MemoField in a database that you are reading and writing the checked values from/to. You also have a predefined list of checkable items.
So you'll need to create a new string list and read the field back into it (Revesing the writing code). for each item in the list get the Index and check it.
Something like..
procedure TfrmSysConfig.saveCatBreakDownValue;
var
lstCat: TStringList;
i, Index:integer;
begin
lstcat := TStringList.Create;
try
lstcat.Text = tblMainPOS_CatBreakDownValue.Value;
for i:=0 to lstcat.Count-1 do
begin
Index := clCat.Items.IndexOf(lstcat.Items[i])
if Index > -1 then
begin
clCat.Checked[Index] := True;
end;
end;
finally
lstcat.Free;
end;
end;
Not sure I understand your question 100%
TCheckListBox can check or uncheck items using the Checked Property.
CheckListBox.Checked[Index] := True/False;
Since you sound like your comparing strings you may need to determine the index in the TCheckListBox based on the string this can be done like this:
CheckListBox1.Items.IndexOf('StringToFind')
If the string is not found then the result is -1;
If you want to check lines in a TMemo Control and see if they exists as rows in a table you can do the following.
While not Table.EOF do
begin
if Memo1.lines.IndexOf(Table.FieldByName('MyField').AsString) = -1 then
begin
// What you want to do if not found
end
else
begin
// what you want to do if it is found.
end;
Table.Next;
end;

Resources