How To Increment Numbers in Calculated field of TQuery? - delphi

I Have TQuery With Calculated Field N.
How To Increment Numbers in the example (N starts with 5):
I tried this but Nothing:
procedure TForm1.Query1CalcFields(DataSet: TDataSet);
var i:integer;
begin
i := strtoint(edit2.Text);
Query1['N'] := inttostr(i+1);
end;
result:
N
2
2
2
2
.
.
Note: Foxpro database ,i use BDE to connect with ,It does not have to be a calculated field ,i want the Incremented value to use it in print of quickreport like a single reference for each Page (not pagenumber).

I Found This Solution With The Help Of #kobik
In Printing Of TQRLabel I Add This Code And No Needed To The Calculated Field Or Other Varible:
procedure TForm1.QRLabel1Print(sender: TObject; var Value: string);
begin
value:=inttostr(Query1.RecNo+strtoint(edit2.Text)-1);
end;
The Tedit To Costume The Start Number At Runtime.

This is a simple way that I test it:
1- declare a global variable for saving auto number
2- Set it in FormShow to 5
3- In OnCalcFields assign global variable to the new field
4- increment global variable
Notes: Do not use TEdit or any thing for show the result of calculate field, because it will just show the first result. but all the result will save in table or query correctly.
Codes
Global Variable:
var
Form1: TForm1;
i : Integer;
Form Show:
procedure TForm1.FormShow(Sender: TObject);
begin
i := 5;
end;
Calc Filed:
procedure TForm1.adoqry1CalcFields(DataSet: TDataSet);
begin
adoqry1['n'] := i;
//OR adoqry1N.AsInteger := i;
//OR adoqry1.FieldByName('n').AsInteger := i;
i := i + 1;
end;
At the end, I test it with ADOQuery.

Related

Update corresponding label depending on which combobox fired the event

I have a program with n ComboBoxes and n Labels and I want to update the corresponding Label depending on the selection from the adjacent ComboBox i.e ComboBox2 would update Label2.
I am using the same event handler for every ComboBox and currently checking if Combobox1 or Combobox2 has fired the event handler. Is there a way to use the ItemIndex of the ComboBox passed to the procedure, such as Sender.ItemIndex? This is not currently an option and gives the error 'TObject' does not contain a member named 'ItemIndex'.
procedure TForm2.ComboBoxChange(Sender: TObject);
begin
if Sender = ComboBox1 then
Label1.Caption := ComboBox1.Items.Strings[ComboBox1.ItemIndex]
else
Label2.Caption := ComboBox2.Items.Strings[ComboBox2.ItemIndex];
end;
This code has the desired behavior but is obviously not scale-able.
Every component has a Tag property inherited from TComponent, where the Tag is a pointer-sized integer. As such, you can store each TLabel pointer directly in the corresponding TComboBox.Tag, eg:
procedure TForm2.FormCreate(Sender: TObject);
begin
ComboBox1.Tag := NativeInt(Label1);
ComboBox2.Tag := NativeInt(Label2);
end;
This way, ComboBoxChange() can then directly access the TLabel of the changed TComboBox, eg:
procedure TForm2.ComboBoxChange(Sender: TObject);
var
CB: TComboBox;
begin
CB := TComboBox(Sender);
if CB.Tag <> 0 then
TLabel(CB.Tag).Caption := CB.Items.Strings[CB.ItemIndex];
end;
Option 1
This is the most robust one.
Let your form have private members
private
FControlPairs: TArray<TPair<TComboBox, TLabel>>;
procedure InitControlPairs;
and call InitControlPairs when the form is created (either in its constructor, or in its OnCreate handler):
procedure TForm1.InitControlPairs;
begin
FControlPairs :=
[
TPair<TComboBox, TLabel>.Create(ComboBox1, Label1),
TPair<TComboBox, TLabel>.Create(ComboBox2, Label2),
TPair<TComboBox, TLabel>.Create(ComboBox3, Label3)
]
end;
You need to add the controls to this array manually. That's the downside of this approach. But you only need to do this once, right here. Then everything else can be done automagically.
Now, this is where it gets really nice: Let all your comboboxes share this OnChange handler:
procedure TForm1.ComboBoxChanged(Sender: TObject);
var
i: Integer;
begin
for i := 0 to High(FControlPairs) do
if FControlPairs[i].Key = Sender then
FControlPairs[i].Value.Caption := FControlPairs[i].Key.Text;
end;
Option 2
Forget about any private fields. Now instead make sure that each pair has a unique Tag. So the first combo box and label both have Tag = 1, the second pair has Tag = 2, and so on. Then you can do simply
procedure TForm1.ComboBoxChanged(Sender: TObject);
var
TargetTag: Integer;
CB: TComboBox;
i: Integer;
begin
if Sender is TComboBox then
begin
CB := TComboBox(Sender);
TargetTag := CB.Tag;
for i := 0 to ControlCount - 1 do
if (Controls[i].Tag = TargetTag) and (Controls[i] is TLabel) then
begin
TLabel(Controls[i]).Caption := CB.Text;
Break;
end;
end;
end;
as the shared combo-box event handler. The downside here is that you must be sure that you control the Tag properties of all your controls on the form (at least with the same parent as your labels). Also, they must all have the same parent control.

cxGrid - Footer summary of checked records

In cxGrid,I have a column that is boolean (properties : checkbox).
How can I do a footer summary (SUM) of such a column i.e to sum how many records are checked.
Right now, if I set it to SUM, my footer summary displays negative numbers for the items checked.How can I avoid these negative numbers?
edit :
I have found a would be solution on their site with :
procedure TForm1.cxGrid1DBTableView1DataControllerSummaryFooterSummaryItemsSummary(
ASender: TcxDataSummaryItems; Arguments: TcxSummaryEventArguments;
var OutArguments: TcxSummaryEventOutArguments);
var
si: TcxGridDBTableSummaryItem;
begin
si := Arguments.SummaryItem as TcxGridDBTableSummaryItem;
if si.Column = cxGrid1DBTableView1Sonda then
OutArguments.Done := not OutArguments.Value;
end;
However I am getting the error :
Could not convert variant of type (Null) into type (Boolean).
Dont understand this. Field is boolean type (bit).
edit2:
The problem is that sql server by default sets boolean type to NULL.
That is why the conversion error.
You can also just set your grid to calculate that summary using a different field , for example a calculated field where you assign the exact value you want to add each time.
Add a calculated field to your dataset, with the desired value.
MyHiddenField.Value := -1 * YourCheckingField.AsInteger;
Go to the Summaries Tab on the CxGrid dialog, and add a new Summary:
Set the Column property to the Grid Column where you want it to appear
Set the FieldName to your calculated field
And finally set Kind to skSum
It is better to send such questions to DevExpress support team.
You can customize footer:
assign Kind=skNone to footer summary item
use OnGetText event to show what you want
Quick example (shows number of chars in all records as footer value):
procedure TForm54.cxGrid1DBTableView1TcxGridDBDataControllerTcxDataSummaryFooterSummaryItems0GetText(
Sender: TcxDataSummaryItem; const AValue: Variant; AIsFooter: Boolean;
var AText: string);
var i,j: integer;
begin
j := 0;
for i := 0 to cxGrid1DBTableView1.DataController.RecordCount-1 do
j := j + Length(String(cxGrid1DBTableView1.DataController.Values[i, cxGrid1DBTableView1c.Index]));
AText := IntToStr(j);
end;
I think that you can resolve that problem in SQL component. Use typecasting and your cxGrid will work with Integer values.
SELECT CAS(Bit_Column AS int) AS Int_Column
FROM YourTable
You can try this :
procedure TForm1.cxGrid1DBTableView1DataControllerSummaryAfterSummary(
ASender: TcxDataSummary);
var i, j, Imp:integer;
Item: TcxGridDBTableSummaryItem;
begin
DBTableView1.DataController.BeginLocate;
for j:=0 to ASender.FooterSummaryItems.Count-1 do ASender.FooterSummaryValues[j]:=0;
try
for i:=0 to DBTableView1.DataController.RowCount-1 do
begin
if (DBTableView1.DataController.Values[i,cxGrid1DBTableView1Sonda.Index]<>null) then
for j:=0 to ASender.FooterSummaryItems.Count-1 do
begin
Item:=TcxGridDBTableSummaryItem(ASender.FooterSummaryItems[j]);
Imp:= DBTableView1.DataController.Values[i, cxGrid1DBTableView1Sonda.Index];
if (Imp= 1) or ((Imp= 2)
then ASender.FooterSummaryValues[j]:= ASender.FooterSummaryValues[j]+1;
end;
end;
finally
DBTableView1.DataController.EndLocate;
end;
end;
procedure cxGrid1DBTableView1DataControllerSummaryFooterSummaryItemsSummary(
ASender: TcxDataSummaryItems; Arguments: TcxSummaryEventArguments;
var OutArguments: TcxSummaryEventOutArguments);
var
AValue: Variant;
AItem: TcxGridTableSummaryItem;
begin
AItem := TcxGridTableSummaryItem(Arguments.SummaryItem);
// считаем проверенные
if (AItem.Column = tvCompareisCorrect) and (AItem.Kind = skCount) and (AItem.Position = spFooter) then begin
AValue := tvCompare.DataController.Values[ Arguments.RecordIndex, tvCompareisCorrect.Index];
if not VarIsNull(AValue) then
if not VarAsType(AValue, varBoolean) then Dec(OutArguments.CountValue);
end;

getting the checked nodes from tcxtreelist

I have a tcxtreelist
Does anyone know how to get all the checkedNodes?
I need to go through my tcxtreelist
get a certain value from the tcxtreelist
and write it to a string with comma delimited
Anyone can help me with this?
Thanks
Kind Regards
Suppose you have a cxTreeList with 3 columns, colChecked, colYear and colMonth.
If you go to colChecked in the IDE, you can set its Properties property to
CheckBox and, at run-time, use it as a checkbox.
How to get at the Checked value in a given tree node is actually quite simple.
If you declare a variable Node : TcxTreeList node, you can assign it to any
node in the tree, as in
Node := cxTreeList1.Items[i];
Having done that, you can get at the values in the three columns of the node by
accessing the Values property of the node, which is a zero-based array of variants
which represent the values stored in the node and displayed in the tree.
So, you can write
var
Node : TcxTreeListNode;
Checked : Boolean;
Year : Integer;
Month : Integer;
begin
Node := cxTreeList1.Items[i];
Checked := Node.Values[0];
Year := Node.Values[1];
Month := Node.Values[2];
end;
and, of course, you can set the node's Values by assignments in the opposite
direction (but don't try that with the db-aware version, TcxDBTreeList, because the displayed values are determined by the contents of the fields
of the dataset connected to it).
There's no need to use the Node local variable, I've have only in the interests of clarity. You could just as easily (but not so clearly) write
Checked := cxTreeList1.Items[i].Values[0]
Here's some example code that sets up a cxTreeList with a checkbox column, populates it with rows, and generates a list of the rows which have the checkbox checked:
uses
[...]cxTLData, cxDBTL, cxInplaceContainer, cxTextEdit,
cxCheckBox, cxDropDownEdit;
type
TForm1 = class(TForm)
cxTreeList1: TcxTreeList;
Memo1: TMemo;
btnGetCheckedValues: TButton;
procedure btnGetCheckedValuesClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
protected
colChecked : TcxTreeListColumn;
colYear : TcxTreeListColumn;
colMonth : TcxTreeListColumn;
public
procedure GetCheckedValues;
end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
Year,
Month : Integer;
YearNode,
MonthNode : TcxTreeListNode;
begin
cxTreeList1.BeginUpdate;
try
// Set up the cxTreeList's columns
colChecked := cxTreeList1.CreateColumn(Nil);
colChecked.Caption.Text := 'Checked';
colChecked.PropertiesClassName := 'TcxCheckBoxProperties';
colYear := cxTreeList1.CreateColumn(Nil);
colYear.Caption.Text := 'Year';
colMonth := cxTreeList1.CreateColumn(Nil);
colMonth.Caption.Text := 'Month';
// Set up the top level (Year) and next level (Month) nodes
for Year := 2012 to 2016 do begin
YearNode := cxTreeList1.Root.AddChild;
YearNode.Values[0] := Odd(Year);
YearNode.Values[1] := Year;
for Month := 1 to 12 do begin
MonthNode := YearNode.AddChild;
MonthNode.Values[0] := False;
MonthNode.Values[1] := Year;
MonthNode.Values[2] := Month;
end;
end;
finally
cxTreeList1.FullExpand;
cxTreeList1.EndUpdate;
end;
end;
procedure TForm1.GetCheckedValues;
var
i : Integer;
Node : TcxTreeListNode;
S : String;
begin
for i := 0 to cxTreeList1.Count - 1 do begin
Node := cxTreeList1.Items[i];
if Node.Values[0] then begin
S := Format('Item: %d, col0: %s col1: %s col2: %s', [i, Node.Values[0], Node.Values[1], Node.Values[2]]);
Memo1.Lines.Add(S);
end;
end;
end;
procedure TForm1.btnGetCheckedValuesClick(Sender: TObject);
begin
GetCheckedValues;
end;

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;

Free Pascal use for loop to determine visibility of component based on status of Date Component

My form contains some components whose naming follows a simple convention...
date1, date2, date3, date4, date5
check1, check2, check3, check4, check5
I need to be able to determine the visibility of the checkboxes based on the contents of the date fields, i.e. if a date is returned then the checkbox should be visible.
I'm trying to do this with the following code and everything compiles, but I'm failing to target the components, presumably because its trying to alter the variable rather than the component. Am I going about this in completely the wrong way?
var
dateVar : variant;
checkVar : variant;
x : integer;
// Set visibility of checkboxes and docs
x := 0;
dateVar := 'area.Date' + IntToStr(x);
checkVar := 'area.Check' + IntToStr(x);
for x:=1 to 5 do
begin
if dateVar > '00:00:00' then // Does FPC support the != or not equal to context?
checkVar.Visibility := False
else
checkVar.Visibility := True;
end;
You can iterate over the components via FindComponent. In the example below Self as the Form is given as Owner.
Procedure SetChecks(AOwner:TComponent);
var
x:Integer;
begin
for x:=1 to 5 do
TCheckBox(AOwner.FindComponent('check' + IntToStr(x))).Visible :=
TDateEdit(AOwner.FindComponent('date' + IntToStr(x))).Date <>StrToDateTime('00:00:00');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetChecks(Self);
end;

Resources