How to retrieve data from database and display in Ttreeview in delphi - delphi

Please help me to populate a tree view from SQL database dynamically. I am very new to delphi
and step by step processes are welcome. I have two table formats given in the picture below and i want to fill the tree view from database accordingly. I searched on other resource sites also but didn't find the solution what i am looking for.
I am stuck. Please help me guys....
Many many thanks in advance.
procedure TForm1.Button1Click(Sender: TObject);
var
// node : TTreeList;
i: Integer;
MyTreeNode1,MyTreeNode2 : TTreeNode;
begin
with TreeList1.Items do
begin
Clear;
MyTreeNode1 := Add(nil, 'Table');
ADOTable1.First;
while ADOTable1 do
begin
AddChild(MyTreeNode1,'B') ;
AddChild(MyTreeNode1,'c');
Next;
end;
end;
end;

Switch to TADOQuery and then try something like this:
procedure TForm1.Button1Click(Sender: TObject);
var
CurrentDeptID, RecordDeptID: Integer;
RootNode, DeptNode: TTreeNode;
begin
CurrentDeptID := 0;
TreeList1.Items.Clear;
RootNode := TreeList1.Items.Add(nil, 'Departments');
DeptNode := nil;
ADOQuery1.SQL.Text := 'SELECT sd.DeptID, sd.Name, d.Dept FROM SubDepartments sd INNER JOIN Departments d ON (sd.DeptID = d.DeptID) ORDER BY d.Dept, sd.Name';
ADOQuery1.Open;
try
ADOQuery1.First;
while not ADOQuery1.Eof do
begin
RecordDeptID := ADOQuery1.FieldByName('DeptID').AsInteger;
if (DeptNode = nil) or (RecordDeptID <> CurrentDeptID) then
begin
DeptNode := TreeList1.Items.AddChild(RootNode, ADOQuery1.FieldByName('Dept').AsString);
CurrentDeptID := RecordDeptID;
end;
TreeList1.Items.AddChild(DeptNode, ADOQuery1.FieldByName('Name').AsString);
ADOQuery1.Next;
end;
finally
ADOQuery1.Close;
end;
end;

Related

How can I load Field1 and Field2 from TADOQuery to TTreeView?

I want information from TADOQuery to be loaded into a TTreeView. For example, I want it to be loaded as Field1->Add in Table1 and as Field2->AddChild with buttonClick. But when I run the code, I am getting an error:
Access violation at adress 0043616B in module "TRV2.exe"
I'm making a mistake or something is missing. Can you guide me?
procedure TForm1.AddButtonClick(Sender: TObject);
var
t: Integer;
MyNode, Node : TTreeNode;
begin
MyNode := Node;
t := Node.AbsoluteIndex;
TreeView1.Items.Add(MyNode, ADOQuery1.FieldByName('CODE_NAME').AsString);
end;
procedure TForm1.AddChildButtonClick(Sender: TObject);
var
t: Integer;
MyNode, Node: TTreeNode;
begin
MyNode := Node;
t := Node.AbsoluteIndex;
TreeView1.Items.Add(MyNode, ADOQuery1.FieldByName('CODE_CHILD').AsString);
end;
procedure TForm1.FormCreate(Sender: TObject);
var
t: Integer;
MyNode, Node: TTreeNode;
begin
MyNode := Node;
t := Node.AbsoluteIndex;
ADOQuery1.Open;
end;
UPDATE: I want to get the whole table and update the TTreeView when I add new Add and Child to the database. With these codes (AddButtonClick and AddChildButtonClick) I can only import the first values into the TTreeView. I wonder if a loop is needed?
MyNode and Node are both local variables that you are not initializing to anything. Your AV is because you are trying to access an object that doesn't exist.
Try using a class member instead, where you initialize it with one button click, and then use it with the other button click, eg:
private
MyNode: TTreeNode;
...
procedure TForm1.AddButtonClick(Sender: TObject);
begin
MyNode := TreeView1.Items.Add(nil, ADOQuery1.FieldByName('CODE_NAME').AsString);
end;
procedure TForm1.AddChildButtonClick(Sender: TObject);
begin
if MyNode <> nil then
TreeView1.Items.AddChild(MyNode, ADOQuery1.FieldByName('CODE_CHILD').AsString);
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
ADOQuery1.Open;
end;
UPDATE: to iterate through multiple records in the query result, you need to call TADOQuery.Next() in a loop until TADOQuery.Eof is true.
The database was taken into treview with the following codes. There is something missing. Because Field1=Add and Field2=Child. Same Fields repeating.
procedure TForm1.AddButtonClick(Sender: TObject);
var
CurrentDeptID, RecordDeptID: Integer; RootNode, DeptNode: TTreeNode;
begin
CurrentDeptID := 0;
TreeView1.Items.Clear;
RootNode := TreeView1.Items.Add(DeptNode, 'CODE_NAME');
DeptNode := nil;
ADOQuery1.SQL.Text := 'Select * from Tablo1 where CODE_NAME= CODE_NAME';
ADOQuery1.Open;
try
ADOQuery1.First;
while not ADOQuery1.Eof do
begin
RecordDeptID := ADOQuery1.FieldByName('ID').AsInteger;
if ( DeptNode = nil) or (RecordDeptID <> CurrentDeptID) then
begin
DeptNode := TreeView1.Items.AddChild(RootNode,
ADOQuery1.FieldByName('CODE_NAME').AsString); //
CurrentDeptID := RecordDeptID;
end;
TreeView1.Items.AddChild(DeptNode,
ADOQuery1.FieldByName('CODE_CHILD').AsString);
ADOQuery1.Next;
end;
finally
ADOQuery1.close;
end;
end;
[https://i.stack.imgur.com/kNojV.jpg]
Blockquote

MDI Application, check if a child form with the same caption is open

I have a Delphi MDI application that has a customer search child form which can only be opened once (checking isAssigned), however the view / edit form can be opened multiple times so that the end user can open multiple customers at once (Tabbed), what I'd like to do is be able to stop them from opening the same customer record more than once, on the open of the customer form I set the caption to the customers account reference and if that form exists I would like to .BringToFront, if not I'll create it.
What would be the best way to achieve this please, as I'm scratching my head!
Thanks in advance.
procedure TfrmCustomerSearch.ViewCustomerExecute(Sender: TObject);
begin
screen.cursor := crappstart;
if not IsMDIChildOpen(frmMainMenu, 'frmCustomerView', pfrmCaption) then
frmCustomerView := TfrmCustomerView.createform(nil,dmCustomerSearchfrm.FDQCustSearchreference.Value,cxGrid1DBTableView1.DataController.FocusedRecordIndex)
else
frmCustomerView.BringToFront;
screen.cursor := crdefault;
end;
function TfrmCustomerSearch.IsMDIChildOpen(const AFormName: TForm; const AMDIChildName, AMDICaption : string): Boolean;
var
i: Integer;
begin
Result := False;
for i := Pred(AFormName.MDIChildCount) DownTo 0 do
if (AFormName.MDIChildren[i].name = AMDIChildName) then
begin
if (AFormName.MDIChildren[i].caption = AMDICaption) then
begin
Result := True;
Break;
end
end;
end;
Try something more like this instead:
procedure TfrmCustomerSearch.ViewCustomerExecute(Sender: TObject);
begin
Screen.Cursor := crAppStart;
try
frmCustomerView := TfrmCustomerView(FindMDIChildOpen(frmMainMenu, TfrmCustomerView, pfrmCaption));
if frmCustomerView = nil then
frmCustomerView := TfrmCustomerView.CreateForm(nil, dmCustomerSearchfrm.FDQCustSearchreference.Value, cxGrid1DBTableView1.DataController.FocusedRecordIndex);
frmCustomerView.BringToFront;
finally
Screen.Cursor := crDefault;
end;
end;
function TfrmCustomerSearch.FindMDIChildOpen(const AParentForm: TForm; const AMDIChildClass: TFormClass; const AMDICaption : string): TForm;
var
i: Integer;
Child: TForm;
begin
Result := nil;
for i := Pred(AParentForm.MDIChildCount) DownTo 0 do
begin
Child := AParentForm.MDIChildren[i];
if Child.InheritsFrom(AMDIChildClass) and
(Child.Caption = AMDICaption) then
begin
Result := Child;
Exit;
end;
end;
end;

how to bind data to edit controls in a from using TTreeview in delphi

How to bind data from TTreeview control to Edit control in Delphi..
When I click on submit button .Like I can edit that data and have to update it..
procedure TForm1.Button1Click(Sender: TObject);
var
CurrentDeptID, RecordDeptID: Integer;
RootNode, DeptNode: TTreeNode;
begin
CurrentDeptID := 0;
TreeList1.Items.Clear;
RootNode := TreeList1.Items.Add(nil, 'Departments');
DeptNode := nil;
ADOQuery1.SQL.Text := 'SELECT sd.DeptID, sd.Name, d.Dept FROM SubDepartments sd INNER JOIN Departments d ON (sd.DeptID = d.DeptID) ORDER BY d.Dept, sd.Name';
ADOQuery1.Open;
try
ADOQuery1.First;
while not ADOQuery1.Eof do
begin
RecordDeptID := ADOQuery1.FieldByName('DeptID').AsInteger;
if (DeptNode = nil) or (RecordDeptID <> CurrentDeptID) then
begin
DeptNode := TreeList1.Items.AddChild(RootNode, ADOQuery1.FieldByName('Dept').AsString);
CurrentDeptID := RecordDeptID;
end;
TreeList1.Items.AddChild(DeptNode, ADOQuery1.FieldByName('Name').AsString);
ADOQuery1.Next;
end;
finally
ADOQuery1.Close;
end;
Thank you..
There is no DB Treeview as standard in Delphi 7, and in any case the query you have isn't editable. If you want to use data-aware controls on your form, you will need to add an additional dataset to bind your edit controls to. You can store the key reference of the sub-department in the TTreeItem's Data property.
procedure TForm1.Button1Click(Sender: TObject);
var
CurrentDeptID, RecordDeptID: Integer;
RootNode, DeptNode, SubDeptNode : TTreeNode;
begin
CurrentDeptID := 0;
TreeList1.Items.Clear;
RootNode := TreeList1.Items.Add(nil, 'Departments');
DeptNode := nil;
ADOQuery1.SQL.Text := 'SELECT sd.DeptID, sd.Name, d.Dept FROM SubDepartments sd INNER JOIN Departments d ON (sd.DeptID = d.DeptID) ORDER BY d.Dept, sd.Name';
ADOQuery1.Open;
try
ADOQuery1.First;
while not ADOQuery1.Eof do
begin
RecordDeptID := ADOQuery1.FieldByName('DeptID').AsInteger;
if (DeptNode = nil) or (RecordDeptID <> CurrentDeptID) then
begin
DeptNode := TreeList1.Items.AddChild(RootNode, ADOQuery1.FieldByName('Dept').AsString);
CurrentDeptID := RecordDeptID;
end;
SubDeptNode := TreeList1.Items.AddChild(DeptNode, ADOQuery1.FieldByName('Name').AsString);
SubDeptNode.Data := ADOQuery1.FieldByName('DeptID').AsInteger;
ADOQuery1.Next;
end;
finally
ADOQuery1.Close;
end;
In the OnClick event of your Treeview you can recover the key of the Subdepartment and pass that value to your additional query :-
Procedure TForm1.TreeList1Click(Sender : TObject);
Var
lNode : TTreeNode;
lID : Integer;
Begin
lNode := TTreeList.Selected;
If Assigned(lNode) And (lNode.Level = 2) Then
Begin
lID := lNode.Data;
// Pass this lID to your additional query.
End;
End;

Save state of radiobutton to stringlist

In my application i save some edit value in a Tstringlist with code below:
procedure TForm1.Button3Click(Sender: TObject);
var
F: TStringList;
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
F := TStringList.Create;
with F do
begin
Add(label7.Caption);
Add(label21.Caption);
SaveToFile(Savedialog1.Filename);
Free;
end;
end;
end;
I want to save Tradiobutton state too in this Tstringlist.
Can you help me?
Regards
Making an answer just to show the code sample in properly formatted form
To read:
try/finally pattern - http://docwiki.embarcadero.com/RADStudio/XE2/en/Writing_a_Finally_Block_(Delphi)
TIniFile class and boolean values - http://docwiki.embarcadero.com/Libraries/XE2/en/System.IniFiles.TCustomIniFile.WriteBool - as a somewhat outdated with limited capabilities but a very simple text structured format.
So your code would become something like
const ini_def_sect = 'Default Section';
procedure TForm1.Button3Click(Sender: TObject);
var
F: TCustomIniFile;
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
F := TIniFile.Create(SaveDialog1.Filename);
try
F.WriteString(ini_def_sect, label7.Name, label7.Caption);
F.WriteString(ini_def_sect, label21.Name, label21.Caption);
F.WriteBool(ini_def_sect, radiobutton1.Name, radiobutton1.Checked);
F.UpdateFile;
finally
F.Destroy;
end;
end;
end;
Or in VCL with-based style (that many dislike as they dislike with statement in Pascal)
const ini_def_sect = 'Default Section';
procedure TForm1.Button3Click(Sender: TObject);
begin
SaveDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if SaveDialog1.Execute then
begin
with TIniFile.Create(Savedialog1.Filename) do
try
WriteString(ini_def_sect, label7.Name, label7.Caption);
WriteString(ini_def_sect, label21.Name, label21.Caption);
WriteBool(ini_def_sect, radiobutton1.Name, radiobutton1.Checked);
UpdateFile;
finally
Destroy;
end;
end;
end;
And you REALLY REALLY should give your variables (including labels, forms, radio buttons, etc) reasonable names while you still can remember a bit about what do each of those mean. Trust me - a month or two and you would forget.
PS: reading the structured file could be something like
procedure TMainForm.btnOpenClick(Sender: TObject);
begin
OpenDialog1.Filter := 'GPP files (*.GPP)|*.GPP';
if OpenDialog1.Execute then
begin
with TIniFile.Create(OpenDialog1.Filename) do
try
label7.Caption := ReadString(ini_def_sect, label7.Name, '');
label21.Caption := ReadString(ini_def_sect, label21.Name, '');
radiobutton1.Checked := ReadBool(ini_def_sect, radiobutton1.Name, False);
finally
Destroy;
end;
end;
end;

Reassigning a datasource at run-time

I did some searching and only found more unanswered questions. :)
Using D5pro.
I want to reassign the DataSource to a TDBGrid at run time. I have seven identical structured DataSets and depending on a button click I want the appropriate DataSet displayed in the grid.
I have tried everything and I cannot get it to show the next DataSet. It sticks with the first one assigned at start up. I am getting to overkill approaches and still nothing is working. Here's where I am at the moment.
procedure SetSource(var aSrc : TDataSource);
begin
aSrc.DataSet.Close;
dbgridShowData.DataSource:=aSrc;
aSrc.DataSet.Open;
aSrc.DataSet.First;
aSrc.DataSet.Refresh;
end;
Where am I going wrong?
Thanks
You can change the Dataset shown by a DBGrid quite easily at runtime quite easily. There two approaches:
1: use a single DataSource assigned to DBGrid.DataSource and change the DataSource.DataSet to the desired DataSet. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DataSource1.DataSet := DataSet3;
end;
2: use a DataSource for each DataSet and change DBGrid.DataSource to the desired DataSource. Here is a simple example with all assignments made at runtime.
procedure TForm1.FormCreate(Sender: TObject);
begin
DataSource1.DataSet := DataSet1;
DataSource2.DataSet := DataSet2;
DataSource3.DataSet := DataSet3;
DataSet1.Active := true;
DataSet2.Active := true;
DataSet3.Active := true;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource1;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource2;
end;
procedure TForm1.Button3Click(Sender: TObject);
begin
DBGrid1.DataSource := DataSource3;
end;
If you define the columns of the DBGrid, the structure of the DataSets will need to be the the same, or you will have to change the column definitions when you change the Dataset displayed.
I prefer using a DataSource per DataSet because it is more flexible.
You probably need to change the DataSource.DataSet instead:
procedure SetDataFromDataSet(const aDataSource: TDataSource;
const aNewDataSet: TDataSet);
begin
aDataSource.DataSet.Close;
aDataSource.DataSet := aNewDataSet;
if not aNewDataSet.Active then
aNewDataSet.Open;
end;
Sample use:
SetDataFromDataSet(DataSource1, CustomerQuery);
You may not want to close and open datasets globally like this, though. It's probably better to do that from the calling code. Of course, that would depend on what you need for your app.
Tested with Delphi5 pro.
procedure TForm1.setDataSourceDataSet(var newDataSource:TDataSource);
begin
if DBgrid1.DataSource = nil then begin
DBgrid1.DataSource:=newDataSource;
end else begin
if DBgrid1.DataSource.Name = newDataSource.Name then exit;
DBGrid1.DataSource.Enabled:=False;
DBgrid1.DataSource:=newDataSource;
end;
If DBgrid1.DataSource.DataSet.active=False then DBgrid1.DataSource.DataSet.active:=True;
DBGrid1.DataSource.Enabled:=True;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource1);
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
setDataSourceDataSet(DataSource2);
end;
The secret lies in:
DBGrid1.DataSource.Enabled:=False;
...making changes...
DBGrid1.DataSource.Enabled:=True;
Tested with D5Pro

Resources