How to create button to addition every lines in DBGrid Delphi 7 - delphi

how to make button on delphi 7 to execute addition with all data in dbgrid delphi.
for example
i have database table with 3 coloumns show in dbgrid,
[CODE_NUMBER][ITEMS NAME][STOCK][NEW_STOCK]
001 Rackets 1 5
002 Sports Shoes 2 5
003 Golf Hat 3 5
... etc
How to create button when i click it, then dbgrid start addition
[STOCK] = [STOCK]+[NEW_STOCK]
after count in the first line, move to second line do the same addition
and so on until the end of the record in dbgrid and delete data in [NEW_STOCK] coloumn.
i've try with
if dbgrid1.fieldbyname('Code').value <> 0 then
begin
dbgrid1.fieldbyname('Stock').value := dbgrid1.fieldbyname('Stock').value + dbgrid1.fieldbyname('NEW_STOCK').value;
dbgrid1.next;
but only affect in the first line, nothing happen with the next lines in dbgrid

To change data in dbgrid, you should use it's corresponding dataset, i.e.:
with dbgrid1.DataSource.DataSet do begin
Edit;
Fields.fieldbyname('Stock').value := Fields.fieldbyname('Stock').value + Fields.fieldbyname('NEW_STOCK').value;
Post;
Next;
end;

More efficient would be to do this at the database
The update statement to send to the database is very simple :
update yourtable set Stock = Stock + newStockValue where Code <> 0
and then just refresh your query or table component.

Related

FastCube 2 in Delphi, hide total for a measure

I am using FastCube 2.0 with Delphi.
I have cube and a slice... I need to hide TOTAL for one column (measure). How do I access it in code?
Thank you
Solution:
fcxSliceSLICENAME.MeasuresContainer.Measures[0].UseDifferentAggForTotals := True;
fcxSliceSLICENAME.MeasuresContainer.Measures[0].AgrFuncForTotals := af_Formula;
(0 indicates index of the column whose total you want to hide)

How to compare 4 column values of TAdvStringGrid with one another and label them?

If i have colA, ColB, Colc, ColD and there are 1000 rows in each column in TAdvStringGrid . I would like check the number of double measurements of values in the 1000 rows in colA, ColB, Colc, ColD of TAdvStringGrid.
I am doing some thing like At first reading ColA, ColB, ColC, ColD values into multidimensional array and looping each element in multi dimensional array and comparing with each row element TAdvStringGrid and when found same using OnDrawcell function, I am labelling and displaying the row with a colour.
However it takes a lot of time. Is there a shorter way to do it. As the rows keep on increasing. Thanks for the answer in advance.
Every row is one measurement and one measurement consist of 4 values in ColA,B, C,D.
List : array of array of double;
SetLength (List,AdvStringGrid.RowCount,4);
for i := 0 to AdvStringGrid.RowCount -1 do begin
j:=0;
List[i,j] := strtofloat(AdvStringGrid.Cells[4,i+1]);
List[i,j+1] := strtofloat(AdvStringGrid.Cells[5,i+1]);
List[i,j+2] := strtofloat(AdvStringGrid.Cells[8,i+1]);
List[i,j+3] := strtofloat(AdvStringGrid.Cells[9,i+1]);
end;{for i}
How do i compare each element with neighbour and mark the duplicate??
Am I correct that every row is one meassurement? So one meassurement consist out of 4 values?
First thing is you shouldn't modify the visual StringGrid in in a loop. In the worst case the StringGrid invalidates and draws again after each action.
So it's good to read all data in an multidimention array.
To eliminate doubles i would sort everything and then compare neigbors. This is a pretty common pattern.
Define any order like ColA accending, then ColB accending, ColC accending and ColD accending and implenent a sort algorithm (like quicksort or mergesort).
After everything is sortet you can traverse the array from highes element to 0 and check if two neighbours are the same.
If you want to mark the double values instead of deleting them consider adding a 5th colum for a value when it is a duplicate.
After all the calcilation i would search for any Function like BeginUpdate() and Endupdate() to make sure that the StringGrid will only draw once.
Do all changes to StringGrid between the call of BeginUpdate() and Endupdate()
Update: your code could look something like this:
var
i:integer;
sortedList: array of array of double;
begin
setlength(List, 1000, 5); // use a fifth row for marking doublicates, set this value to 0
// Fill List like you mentioned here
sortedList = YourSortAlgorithm(List); // sort your List here
for i := high(sortedList) downto 0 do
begin
// compare if entries are duplicates
if sortedList[i,1] = sortedList[i-1,1] and sortedList[i,2] = sortedList[i-1,2] and sortedList[i,3] = sortedList[i-1,3] and sortedList[i,4] = sortedList[i-1,4] then
begin
sortedList[i-1,5] = 1; // 1 means duplicate, 0 means not duplicate
end;
end;
AdvStringGrid1.BeginUpdate;
// update your Stringgrid here
AdvStringGrid1.EndUpdate();
end;
Bye the way, instead of using a two dimentionaly array i would recoment to use a array of record.
Saying for example, that your ColA is a height, ColB is a length, ColC is a Temperature and ColD is a age you could define a record like this
type
TMeasurement = record
height: double;
length: double;
temperature: double;
age: double;
isBoolean: boolean;
end;
var
list: array of TMeasurement;
begin
//...
end;

Change integer field in db table to display as string on cxgrid

I have a delphi form with a cxgrid on it, the grid is connected to a query/datasource.
If a field in the database table is an Integer, is there anyway of me displaying the integer as a string on the cxgrid column?
e.g. 1 = January
2 = February
3 = March
and so on.
Thanks,
Yes, there is such possibility.
Put TcxEditRepository component next go your grid. Double click on it, you should see the empty window with "Add..." button. Click it and from the list of available components select ImageComboBox.
Now, you need to edit Items property of this combo.
After filling up all rows go to your view (TcxGridDBTableView or TcxGridTableView) and pick the column which contains integer values. This column has a property called RepositoryItem. If you did everything correctly you should be able to select the repository item which you've created earlier (the ImageComboBox). After selecting it, your column should immediately display month names instead of numbers.
Other approach is to override cxGrid column OnGetDisplayText event. You could do something like that:
procedure TSomeForm.GetDisplayText(Sender: TcxCustomGridTableItem;
ARecord: TcxCustomGridRecord; var AText: string);
var
nVal : Integer;
begin
nVal := ARecord.Values[Sender.Index];
case nVal of
1: AText := "January";
//and so on
end;
end;

calculated field-running total

I'm used to calculate the balance of the calculated field., But when I connect the dbgrid. Calculated by moving the scroll is wrong.
Please get help
var
Form1: TForm1;
i : Integer;
procedure TForm1.FormShow(Sender: TObject);
begin
i := 0;
DataSource1.DataSet := ADOTable1;
DBGrid1.DataSource := DataSource1;
end;
procedure TForm1.ADOTable1CalcFields(DataSet: TDataSet);
begin
i := (ADOTable1Debtor.AsInteger - ADOTable1creditor.AsInteger) + i;
ADOTable1Total.AsInteger := i;
end;
Now run the application and move the scroll in dbgrid column numbers (total) will change.
I'd like to know how to stop the change.
The calculated fields is designed to show value calculations at the row level and is not designed to make aggregations (calculations based on a set of rows).
For example, the database layer will fire the OnCalc event in no particular order and every time is needed to obtain the value of the field (for display pruposes, for example), since that value is not stored and may (and usually do) depend on the values of other fields.
In a set of 10 rows, you can get it called for rows 1, 2, 3, 4, 5 and then in 1 again...
You can use it, for example, in a line_total column which is the product of quantity and unit_price, but you can't use it to show e.g. the sum(line_total) of all the lines, as I infer you're trying to do in the shown code.
How to perform aggregations then?
You may want to link your DataSet to a ClientDataSet, which have AggregateFields, in which you can perform calculations like SUM(Quantity * Price) on the entire row-set or sub-sets based on a Index.
To learn more about AggregateFields read ClientDataSet Aggregates and GroupState by Cary Jensen in EDN.
What you are trying can't work, since any scroll will change the result.
Take a AdoDataset instead with following Commandtext
select ID, creditor, Debtor,(Select sum (Debtor-Creditor) from Table1 t where t.ID<=Table1.ID) as Total
from Table1 order by ID

Zeoslib - loop over calculated fields

I have a Delphi 7 project using Zeoslib 6.6.6 and Sqlite3.
On the form I have a Zquery selecting everything out of a sample database table along with a bunch of calcuated fields (TFloatField; TCurrencyField). The OnCalcFields event of the query runs fine and all field values are set.
However, when i try to loop over the dataset, I consistently get a 'List index out of bounds (62893)' exception, though i am well within the field count limit (the first calculated field of about 14).
Snippet:
gd is a TStringGrid, ZQuery4 is a TZQuery
while not ZQuery4.Eof do
begin
row := row + 1;
gd.Cells[0, row] := IntToStr(gd.Row);
gd.Cells[1, row] := ZQuery4pid.Value; //Known column
gd.Cells[2, row] := FormatFloat('0.00', ZQuery4area.Value); //known column
for i := 3 to ZQuery4.FieldCount - 1 do
begin
field := Zquery4.Fields[i]; //crashes here when accessing the first calculated field.
if field.IsNull
then gd.Cells[i, row] := ''
else gd.Cells[i, row] := field.AsString;
end;
end;
The bizarre thing is that if i connect a DBGrid to the query it works fine. Any ideas?
What happens when gd.cells[x,row] exceeds the number of rows you have set in the string grid? Probably that's your error. If you set your stringgrid to have 62000 rows, great, that's your error. Otherwise, I suspect that you're hitting a limit.
I always used to have my string grid row count grow like this, with logic after row=row+1:
if gd.RowCount<=row then gd.RowCount := row+1;
If however you really are getting this error at 60k+ stringgrid rows, it is possible that instead what is happening is you are hitting a string grid row length limit.
Since you haven't obviously posted ALL your code, it's hard to know what sets the row count in the string grid where, and how it grows.
In the case that you've hit a limit beyond which a StringGrid no longer operates, I suggest you drop StringGrid and use ExgridView or some other virtual gridview that can handle a very very large amount of data.
I seem to have stumbled across at least a workaround:
changing
gd.Cells[i, row] := field.AsString;
to
gd.Cells[i, row] := field.DisplayText;
seems to have solved the problem.

Resources