I have e DevExpress grid where I would like to expand some groups that contain a certain value.
I have a grouping on year and week and I would like to have only the current year and the current week expanded as default.
I have been searching for some hints, but havn't found any yet.
The question is a "bit" old but since you are still active I'll answer it.
For the simplicity I've used only two columns: "Year" and "Population", so the grouping is only by "Year".
Here is the screenshot of an example application:
You see an initial data.
I am grouping rows using a "Year" column.
I am expanding group with "Year" = 1, I've assumed that current year = 1.
procedure TfrmMain.btnExpandClick(Sender: TObject);
const
CurrentYear = 1;
var
i: Integer;
begin
for i := 0 to tbvMain.ViewData.RowCount - 1 do
begin
// Check if a row is a grouping row.
if not tbvMain.ViewData.Rows[i].IsData then
begin
// Check if a grouping value is the one that you want expanded.
if tbvMain.ViewData.Rows[i].Values[clmYear.Index] = CurrentYear then
tbvMain.ViewData.Rows[i].Expand(False);
end;
end;
end;
procedure TfrmMain.FormCreate(Sender: TObject);
var
i: Integer;
begin
// Prepare some random data.
Randomize;
tbvMain.DataController.RecordCount := 10;
for i := 0 to tbvMain.DataController.RecordCount - 1 do
begin
tbvMain.DataController.Values[i, clmYear.Index] := Random(3) + 1;
tbvMain.DataController.Values[i, clmPopulation.Index] := Random(100);
end;
end;
The key here is to check if the given row is data or not. If it is not data then it is a grouping row, for this you need to use tbvMain.ViewData.Rows[i].IsData
You can find full source code here. Please note that I've used Delphi 2009 and Dev Express build 56.
Have you try with something like this?
TableView1.ViewData.Records[0].Expand(true)
If the current year is the first, otherwise replace 0 with the correct record number
Related
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;
I have some difficulties in entering some data into TGrid Cells, can someone give me some code example with commentary on how to insert data into a TGrid cell? To be more precise in C++ Builder when I'm using a StringGrid I can use
StringGrid1->Cells[1][0] = "Hello world";
which will insert in the cell of the second column of the first row the "hello world" message. How can I do the same with TGrid? And how can I use TCheckColumn? I have many diffulties because I cannot find any good documentation.
I'm looking but there is no guide on this anywhere.
TL;DR:
You need to store the data in your own data structure, and pass it to the displayed grid via the OnGetValue event.
I found the answer in the link to MonkeyStyler provided by #nolaspeaker in the comments.
TGrid does not store any data internally.
You need to store the data yourself. When a cell in your grid is displayed, the OnGetValue(Sender: TObject; const Col, Row: Integer; var Value: TValue) event is fired.
It is up to you to implement an event handler for this, and return the data for the given cell.
For example, suppose you have a very simple grid that only shows "hello" in every cell of the first column and "world" in every cell of the second column.
Your OnGetValue event would look like this:
procedure MyOnGetValueHandler(Sender: TObject; const Col, Row: Integer; var Value: TValue);
begin
if Col = 0 then
Value := 'hello'
else
if Col = 1 then
Value := 'world';
end;
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;
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
I'm using the TcheckListBox control and would like to use a second column on this, but besides the Columns and Header properties, I could not find any source on inserting the multicolumn contents...
It can look like a noobie question, but Delphi's help doesn't have any content on this, and my searches (on Google and SO) brought much garbage...
I just need an example.
This is not possible using a TCheckListBox.
But you could use a TListView.
Set the ViewStyle property to vsReport and Checkboxes to True.
To create the columns and add the items:
procedure TFormMain.Button1Click(Sender: TObject);
var
Item1, Item2: TListItem;
begin
ListView1.Columns.Add.Caption := 'aa';
ListView1.Columns.Add.Caption := 'bb';
Item1 := ListView1.Items.Add;
Item1.Caption := 'item1';
Item1.SubItems.Add('subitem1');
Item2 := ListView1.Items.Add;
Item2.Caption := 'item2';
Item2.SubItems.Add('subitem2');
Item2.Checked := True;
end;
Looks like:
list view with checkboxes http://img638.imageshack.us/img638/4681/clipboard01y.png
I could be wrong but I thought the columns were for wrapping rather than for formatting purposes.
eg,
Set the number of columns to 2
Add 3 or 4 items
Resize the box vertically and you'll see the items flow to fill the columns