Showing multiple checkbox, delphi - delphi

I have 6 checkbox with edittext at each of checkbox.
I want to show only the selected checkbox with its edittext value in memo.
Here is my code:
//jumCheck is total of selected checkbox
for I := 0 to jumCheck - 1 do
begin
if CheckBox1.Checked then
begin
Memo1.Lines.Append('Gejala: '+CheckBox1.Caption+', Penyakit: '+Edit1.Text);
end
else if CheckBox2.Checked then
begin
Memo1.Lines.Append('Gejala: '+CheckBox2.Caption+', Penyakit: '+Edit2.Text);
end;
end;
And the result is just the first checkbox that i was selected for looping.
Anyone, please help me.

Probably, you need TRadioButtons instead...
Here is the code for dynamically created TEdits and TCheckBoxes:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
const
ElementsCount = 6;
type
TForm1 = class(TForm)
Memo1: TMemo;
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
chba: array [1 .. ElementsCount] of TCheckBox;
eda: array [1 .. ElementsCount] of TEdit;
procedure CBClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i: byte;
begin
for i := 1 to ElementsCount do
begin
chba[i] := TCheckBox.Create(self);
chba[i].Tag := i; //you can change the code of CBClick
//and know out the sender easier by Tag property
chba[i].Top := (i - 1) * 30 + 1;
chba[i].Left := 1;
chba[i].Caption := 'Some caption ' + inttostr(i);
chba[i].Parent := self;
chba[i].OnClick:= CBClick;
eda[i] := TEdit.Create(self);
eda[i].Top := (i - 1) * 30 + 1;
eda[i].Left := 100;
eda[i].Text := '';
eda[i].Parent := self;
end;
end;
procedure TForm1.CBClick(Sender: TObject);
var
i: byte;
begin
Memo1.Text := '';
for i := 1 to ElementsCount do
begin
if chba[i].Checked then
begin
Memo1.Lines.Append(chba[i].Caption + ' ' + eda[i].Text);
exit;//??? In this case only the first checked will be processed
//Probably, you need TRadioButton's instead
end;
end;
end;
end.

Your code has a few problems:
Using else skips all checkboxes after the first selected checkbox
There is no point in combining for and a list of if-statements. If you have a if-statement for every checkbox, what do you want to iterate with the for over?
Your for starts with 0, but the first checkbox seems to be CheckBox1 (generally it would be better to use more descriptive names)
What you seem to be looking for is the method FindComponent to find a component of a certain name or index.
E.g. it becomes
for I := 1 to jumCheck do
begin
if (FindComponent('CheckBox' + IntToStr(i)) as TCheckBox).Checked then
begin
Memo1.Lines.Append('Gejala: '+(FindComponent('CheckBox' + IntToStr(i)) as TCheckBox).Caption+', Penyakit: '+(FindComponent('Edit' + IntToStr(i)) as TEdit).Text);
end
end;

Related

How to coding patient search app in Delphi?

I'm working on a patient search app. I have a problem with ADOQuery.Active which does not deactivate when I delete a word in the search bar.
This is my code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Mask, scControls,
scDBControls, scGrids, scDBGrids, scGPControls, Data.DB, Data.Win.ADODB;
type
TForm1 = class(TForm)
ADOConnection1: TADOConnection;
DataSource1: TDataSource;
Edit1: TEdit;
scDBGrid1: TscDBGrid;
ADOQuery1: TADOQuery;
ADOQuery1PATIENTId: TAutoIncField;
ADOQuery1NAME_PAT: TStringField;
ADOQuery1PRENOM_PAT: TStringField;
procedure Edit1Change(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Edit1.Text = '' then
ADOQuery1.Filtered := false
else
begin
ADOQuery1.Active := true;
ADOQuery1.Filtered := False;
ADOQuery1.Filter := 'NAME_PAT' + ' LIKE ' + QuotedStr(Edit1.Text + '%');
ADOQuery1.Filtered := True;
end;
end;
end.
After clean TEdit, I set ADOQuery1.Active := false
The problem here is you are not affecting the right properties according to your first description.
Generally in database applications, you don't need to deactivate the dataset, just write an event for disabling the filter 'Filtered := False' that will be triggered when the filter text input is cleared (by deleting the filter string manually or a "clear text" button).
But, if you need to deactivate the dataset, then you have to set that property in your code.
Like this:
procedure TForm1.Edit1Change(Sender: TObject);
begin
if Edit1.Text = '' then
begin
ADOQuery1.Filtered := False;
ADOQuery1.Active := False;
end
else
begin
ADOQuery1.Active := True;
ADOQuery1.Filtered := False;
ADOQuery1.Filter := 'NAME_PAT' + ' LIKE ' + QuotedStr(Edit1.Text + '%');
ADOQuery1.Filtered := True;
end;
end;
Here is some useful links from Delphi documentation about the "TDataSet.Active" property and how to set filters in datasets:
https://docwiki.embarcadero.com/Libraries/Alexandria/en/Data.DB.TDataSet.Active
https://docwiki.embarcadero.com/Libraries/Alexandria/en/Data.DB.TDataSet.Filter
https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Setting_the_Filter_Property

Clientdataset 'index not found' error in nested dataset

I am attempting to find a subset of records in a clientdataset by using a clone cursor to seek a records using an indexdef. In the example below I have created a button to implement the clone creation. The code works fine for a clientdataset named cdsData. However if I nest cdsData in another dataset (cdsMaster) then the button code fails to find the indexDef.
The Form: (including both clientdatasets showing both datasources and clientdatasets. Omit dsMaster & cdsMAster in first unit example below)
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 289
ClientWidth = 554
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
OnCreate = FormCreate
PixelsPerInch = 96
TextHeight = 13
object Button1: TButton
Left = 32
Top = 24
Width = 75
Height = 25
Caption = 'Clone'
TabOrder = 0
OnClick = Button1Click
end
object dsMaster: TDataSource
DataSet = cdsMaster
Left = 56
Top = 80
end
object cdsMaster: TClientDataSet
Aggregates = <>
Params = <>
Left = 56
Top = 144
end
object dsData: TDataSource
DataSet = cdsData
Left = 152
Top = 88
end
object cdsData: TClientDataSet
Aggregates = <>
Params = <>
Left = 152
Top = 144
end
end
The successful cdsData unit:
unit IndexFindTest;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Data.DB, Datasnap.DBClient;
type
TForm1 = class(TForm)
dsData: TDataSource;
cdsData: TClientDataSet;
Button1: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Disp, Lbl : string;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Clone: TClientDataset;
begin
Clone := TClientDataset.Create(nil);
try
Clone.CloneCursor(cdsData,false);
cdsData.IndexDefs.Update;
clone.IndexName := cdsData.IndexDefs.find ('Lbl').Name;
//..added code to select a range of records using the IndexDef
finally
clone.free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
disp := 'Item 1';
lbl := 'a';
with TStringField.Create(Self) do begin
Name := 'MstrDisplays';
FieldKind := fkData;
FieldName := 'Displays';
Size := 10;
DataSet := cdsData;
end;
with TStringField.Create(Self) do begin
Name := 'MstrLabel';
FieldKind := fkData;
FieldName := 'Label';
Size := 10;
DataSet := cdsData;
end;
with cdsData.IndexDefs.AddIndexDef do begin
Name := 'Lbl';
Fields := 'Displays;Label';
Options := [ixCaseInsensitive];
end;
cdsData.CreateDataSet;
end;
end.
The nested version that fails:
unit IndexFindTest2;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Data.DB, Datasnap.DBClient;
type
TForm1 = class(TForm)
dsMaster: TDataSource;
cdsMaster: TClientDataSet;
Button1: TButton;
dsData: TDataSource;
cdsData: TClientDataSet;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
Disp, Lbl : string;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
var
Clone: TClientDataset;
begin
Clone := TClientDataset.Create(nil);
try
Clone.CloneCursor(cdsData,false);
cdsData.IndexDefs.Update;
//Error generated in next line
clone.IndexName := cdsData.IndexDefs.find ('Lbl').Name;
//..added code to select a range of records using the IndexDef
finally
clone.free;
end;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
disp := 'Item 1';
lbl := 'a';
with TStringField.Create(Self) do begin
Name := 'MstrTitle';
FieldKind := fkData;
FieldName := 'Title';
Size := 10;
DataSet := cdsMaster;
end;
with TDataSetField.Create(Self) do
begin
Name := 'MstrDisplay';
FieldName := 'Displays';
DataSet := cdsMaster;
end;
cdsData.DataSetField := TDataSetField(cdsMaster.FieldByName('Displays'));
with TStringField.Create(Self) do begin
Name := 'ClientNested';
FieldKind := fkData;
FieldName := 'Notes';
Size := 10;
DataSet := cdsData;
end;
with TStringField.Create(Self) do begin
Name := 'kntLabel';
FieldKind := fkData;
FieldName := 'Label';
Size := 10;
DataSet := cdsData;
end;
cdsData.IndexDefs.Update;
with cdsData.IndexDefs.AddIndexDef do begin
Name := 'Lbl';
Fields := 'Notes;Label';
Options := [ixCaseInsensitive];
end;
cdsMaster.CreateDataSet;
end;
end.
When running the second program I receive the error
cdsData: index 'Lbl' not found.
The only difference I can identify between the two programs is the fact that cdsData is nested in the second version. I found a note in CaryJensen's Delphi in Depth:clientDatasets 2nd edition (pg128) stating that the erro may occur and can be fixed using update, but no matter where in the sequence I apply the update, it does not work in this situation.
Can anyone shed light on this problem? Are there additional steps with a nested dataset?

Add an empty gantt to a serie

I want to add an empty gantt serie to a TGanttSeries. How to do that ?
I want that serie draw on the chart even is empty.
I tried to put Serie.AddGanttColor(0, 0, i, SerieName[i], clBlue); but it print a bar on 30/12/1899...
Here a picture of what I made : TCHART
What I need to make is to also drawing the Series1 (Task #1) on the left axis of the TChart. (Here the Series Series1 don't contain any points to draw)
You can hide the "empty" series by setting its "Pointer.Visible" property to "false". This will still include that series in the legend. If you want the series to be blank on the chart (the label still drawn along the left-axis), you will need to add at least one value to it and you'll surely want to choose a value that helps preserve the chart's readability. In my example, I chose to use the smallest date from the non-empty series and if all the series are "empty" simply use the current DateTime ("Now").
Also, you want to connect the chart's "GetLegendText" event so you can provide only the name of each series instead of some combination of the series name and its data. There does not appear to be a useful setting in the legend's properties. You could extend this and return only the series' name when empty and some more meaningful name/data combination when not.
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, VclTee.TeeGDIPlus, VCLTee.TeEngine, Vcl.ExtCtrls, VCLTee.TeeProcs, VCLTee.Chart,
VCLTee.Series, VCLTee.GanttCh, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Chart1: TChart;
Series1: TGanttSeries;
Button1: TButton;
Series2: TGanttSeries;
Series3: TGanttSeries;
procedure FormCreate(Sender: TObject);
procedure Chart1GetLegendText(Sender: TCustomAxisPanel; LegendStyle: TLegendStyle; Index: Integer; var LegendText: string);
private
Series : array[0..2] of TGanttSeries;
SeriesName : array[0..2] of string;
SeriesStart : array[0..2] of TDateTime;
SeriesEnd : array[0..3] of TDateTime;
SeriesColor : array[0..2] of TColor;
procedure DrawChart;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
var
i : integer;
begin
Series[0] := Series1;
Series[1] := Series2;
Series[2] := Series3;
SeriesName[0] := 'Task #1';
SeriesName[1] := 'Task #2';
SeriesName[2] := 'Task #3';
SeriesStart[0] := 0; SeriesEnd[0] := 0;
SeriesStart[1] := Now; SeriesEnd[1] := Now+1;
SeriesStart[2] := Now+0.5; SeriesEnd[2] := Now+3;
SeriesColor[0] := clBlue;
SeriesColor[1] := clGreen;
SeriesColor[2] := clRed;
for i := 0 to 2 do
begin
Series[i].ColorEachPoint := false;
Series[i].SeriesColor := SeriesColor[i];
end;
DrawChart;
end;
procedure TForm1.DrawChart;
var
EmptyValue : TDateTime;
i : integer;
begin
EmptyValue := 0;
for i := 0 to 2 do
begin
if (SeriesStart[i] <> 0) and
( (EmptyValue = 0) or (EmptyValue > SeriesStart[i]) ) then
EmptyValue := SeriesStart[i];
end;
if EmptyValue = 0 then
EmptyValue := Now;
for i := 0 to 2 do
begin
Series[i].Clear;
if SeriesStart[i] = 0 then
begin
Series[i].Pointer.Visible := false;
Series[i].AddGanttColor(EmptyValue,EmptyValue, i, SeriesName[i], SeriesColor[i])
end
else
begin
Series[i].Pointer.Visible := true;
Series[i].AddGanttColor(SeriesStart[i],SeriesEnd[i],i,SeriesName[i], SeriesColor[i])
end;
end;
end;
procedure TForm1.Chart1GetLegendText(Sender: TCustomAxisPanel; LegendStyle: TLegendStyle; Index: Integer; var LegendText: string);
begin
LegendText := SeriesName[Index];
end;
end.

show information with Rolling / moving messages delphi xe7

Good day sir/ma
i want to create a status bar with a rolling information like
Os version
current User Name
Date and time
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, ComCtrls;
type
TForm1 = class(TForm)
tmr2: TTimer;
stsbr: TStatusBar;
procedure tmr2Timer(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.tmr2Timer(Sender: TObject);
begin
if tmr2.Interval = 3000 then begin
stsbr.Panels[1].Text:= FormatDateTime('dddd' + ', ' + 'dd/mm/yyyy',date) + ', ' + TimeToStr(Time);
tmr2.Interval := 3001;
end else if tmr2.Interval = 3001 then begin
tmr2.Interval := 3002;
stsbr.Panels[1].Text:= 'PC Owner: '+GetUsersName+ ' - '+ GetLocalPCName;
end else if tmr2.Interval = 3002 then begin
tmr2.Interval := 3003;
stsbr.Panels[1].Text:= GetOSVersion;
end else if tmr2.Interval = 3003 then begin
tmr2.Interval := 3000;
stsbr.Panels[1].Text:= GetCPUName;
end;
procedure Form.FormCreate(Sender: TObject);
begin
tmr2Timer(Sender);
end;
end
.
that my full code
what i wanted to Achieve was a moving Information on a status bar
Please Help if u can
thanks..
You should not use Timer.Interval as lookout value to determine which data you should show in status bar. Use separate variable to do that. It will make your code cleaner.
unit Unit1;
interface
uses
Winapi.Windows, System.SysUtils, System.Classes, System.Win.Registry,
Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.ComCtrls, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
tmr2: TTimer;
stsbr: TStatusBar;
procedure FormCreate(Sender: TObject);
procedure tmr2Timer(Sender: TObject);
private
status: integer;
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function GetUsersName: string;
var
Buf: array [0 .. MAX_PATH] of Char;
BufSize: longword;
begin
Buf[0] := #$00;
BufSize := MAX_PATH;
if Winapi.Windows.GetUserName(Buf, BufSize) then Result := Buf
else Result := '';
end;
function GetLocalPCName: string;
var
Buf: array [0 .. MAX_COMPUTERNAME_LENGTH] of Char;
BufSize: longword;
begin
Buf[0] := #$00;
BufSize := MAX_COMPUTERNAME_LENGTH;
if Winapi.Windows.GetComputerName(Buf, BufSize) then Result := Buf
else Result := '';
end;
function GetOSVersion: string;
begin
Result := TOSVersion.ToString;
end;
function GetCPUName: string;
var
Reg: TRegistry;
begin
Result := '';
Reg := TRegistry.Create;
try
Reg.RootKey := HKEY_LOCAL_MACHINE;
if Reg.OpenKeyReadOnly('\Hardware\Description\System\CentralProcessor\0') then
begin
Result := Reg.ReadString('ProcessorNameString');
Reg.CloseKey;
end;
finally
Reg.Free;
end;
end;
procedure TForm1.tmr2Timer(Sender: TObject);
begin
case status of
0 : stsbr.Panels[1].Text:= FormatDateTime('dddd' + ', ' + 'dd/mm/yyyy',date) + ', ' + TimeToStr(Time);
1 : stsbr.Panels[1].Text:= 'PC Owner: ' + GetUsersName + ' - ' + GetLocalPCName;
2 : stsbr.Panels[1].Text:= GetOSVersion;
else stsbr.Panels[1].Text:= GetCPUName;
end;
inc(status);
if status > 3 then status := 0;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
status := 0;
// this property can also be set through IDE form designer
tmr2.Enabled := true;
// show initial status data
tmr2Timer(Sender);
end;
end.

Displaying value by value in a threaded binary tree using a "Next" button with a recursive inorder traversal

As the title states, having a bit of trouble mostly with the algorithm. I have the algorithm down to parse through and print ALL the values, but I need to be able to stop on each value and display it in a label. I tried using a global variable 'count', thinking I may be able to stop it. Any ideas? This is what I have so far:
unit Unit4;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm4 = class(TForm)
Createtree: TButton;
Current: TLabel;
RecursiveNext: TButton;
Close: TButton;
IterativeNext: TButton;
Iterative: TLabel;
procedure CloseClick(Sender: TObject);
procedure CreatetreeClick(Sender: TObject);
procedure RecursiveNextClick(Sender: TObject);
procedure IterativeNextClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
type
nodeptr = ^nodetype;
nodetype = record
id : integer ;
left,right : nodeptr ;
threaded : Boolean;
end;
var
Form4: TForm4;
inf : textfile;
root,c : nodeptr;
count : integer;
implementation
{$R *.dfm}
function Emptytree(var root : nodeptr) : Boolean;
begin
Result := False;
if root^.id <> NULL then Result := True;
end;
procedure TForm4.CloseClick(Sender: TObject);
begin
application.Terminate;
end;
function recursiveinorder(c : nodeptr) : integer;
begin
if c^.left <> nil then recursiveinorder(c^.left);
Result := c^.id;
if (c^.right <> nil) and (count > 0) then recursiveinorder(c^.right);
count := count - 1;
end;
function iterativeinorder(c : nodeptr) : integer;
var done : boolean;
begin
c := root;
while c <> nil do c := c^.left;
begin
done := false;
while done = False do
begin
Result := c^.id;
if (c^.threaded = false) and (count > 0) then
begin
c := c^.right;
done := true;
end
else
begin
c := c^.right;
if c = nil then done := true;
end;
end;
end;
count := count - 1;
end;
procedure TForm4.CreatetreeClick(Sender: TObject);
var
parent, knew, c : nodeptr;
begin
count := 0;
new(parent);
new(c);
new(root);
assignfile(inf, 'treedata.txt');
reset(inf);
readln(inf,root^.id);
while not eof(inf) do
begin
new(knew);
readln(inf,knew^.id);
if not Emptytree(root) then
begin
c:= root;
while c <> nil do
begin
parent := c;
if knew^.id < c^.id then
c:=c^.left
else c:= c^.right;
end;
if knew^.id < parent^.id then
begin
parent^.left := knew;
knew^.threaded := True;
knew^.right := parent;
end
else begin
knew^.right := parent^.right;
knew^.threaded := parent^.threaded;
parent^.right := knew;
parent^.threaded := false;
end;
end;
if Emptytree(root) then root := knew;
end;
end;
procedure TForm4.IterativeNextClick(Sender: TObject);
begin
count := count + 1;
Iterative.Caption := inttostr(iterativeinorder(root));
end;
procedure TForm4.RecursiveNextClick(Sender: TObject);
begin
count := count + 1;
Current.Caption := inttostr(recursiveinorder(root));
end;
end.

Resources