I’m trying to sort the records (in descending order ) and display the data in grid which is connected through datasource to the dataset Vw_EmpVacations
Here is the code, please tell me what I did wrong
By the way, the view is sorted descending according to start_date when I execute it in the database
Vw_EmpVacations.Active:=false;
Vw_EmpVacations.SQL.Text:='select * from Vw_EmpVacations where Branch_ID=:x and emp_id=:y and vac_id=:z order by Start_Date Desc ';
Vw_EmpVacations.Parameters[0].Value:=branch_ID;
Vw_EmpVacations.Parameters[1].Value:=emp_Id;
Vw_EmpVacations.Parameters[2].Value:=Vac_ID;
Vw_EmpVacations.Active:=true;
thank you
I will try to help you despite the fact that you are very sparse in details about your problem;-)
Please create a new VCL Forms Application - Delphi For Win32 project.
Then, replace the source of project with this code:
program SortTest;
uses
Forms, ADODB, DB, DBGrids;
var
qrySortTest: TADOQuery;
conSQL2005: TADOConnection;
dsSortTest: TDataSource;
grdTest: TDBGrid;
MainForm: TForm;
begin
Application.Initialize;
conSQL2005 := TADOConnection.Create(Application);
with conSQL2005 do
begin
Name := 'conSQL2005';
//Do not forget to change the connection string
ConnectionString :=
'Provider=SQLOLEDB.1;Integrated Security=SSPI;Persist Security In' +
'fo=False;Data Source=WODZU-LAPTOP\SQL2005S';
LoginPrompt := False;
Provider := 'SQLOLEDB.1';
Connected := True;
end;
qrySortTest := TADOQuery.Create(Application);
with qrySortTest do
begin
Name := 'qrySortTest';
Connection := conSQL2005;
CursorType := ctStatic;
SQL.Clear;
SQL.Add('SELECT '#39'Kowalsky'#39' as Surname, 25 as Age');
SQL.Add('UNION');
SQL.Add('SELECT '#39'Smith'#39', 38');
SQL.Add('UNION');
SQL.Add('SELECT '#39'Jensen'#39', 11');
SQL.Add('UNION');
SQL.Add('SELECT '#39'Doe'#39', 26');
SQL.Add('UNION');
SQL.Add('SELECT '#39'Clarke'#39', 45');
SQL.Add('ORDER BY AGE DESC');
Active := True;
end;
dsSortTest := TDataSource.Create(Application);
with dsSortTest do
begin
Name := 'dsSortTest';
DataSet := qrySortTest;
end;
MainForm := TForm.Create(Application);
MainForm.Position := poScreenCenter;
grdTest := TDBGrid.Create(Application);
with grdTest do
begin
Name := 'grdTest';
Parent := MainForm;
Left := 8;
Top := 8;
Width := 320;
Height := 120;
DataSource := dsSortTest;
TabOrder := 0;
end;
MainForm.ShowModal;
Application.Run;
end.
Remember to put correct connection string to your SQL Server, otherwise it will not work.
Run the test, does it show you rows sorted by Age column in descending order? If yes, then this is the place for you to start.
Replace the qrySortTest.SQL with your parameterless query and check if it works. If not, then the problem lies in your query not in the component setup.
Hope this helps.
Related
I am trying to create a query that will be able to load into a tcxtreelist in delphi
I have a structure like this
-Season
Month
week
All I have is the structure. I still need to know how to constructed my query, so I can load this onto my treelist
if anyone knows how to do this, that really appreciate your help
I'm not sure the cxDBTreeList, which was my first thought,
is really suited to your purpose because it only works for a self-referencing dataset (See the
Devex online help for what this means). On the other hand, it is quite straightforward,
if a little long-winded to set up a cxTreeList to display your data.
In the following example, for simplicity I've left out the "week" level of your structure
and replaced the "Season" level by a "Quarter" (three-month period) one.
To try the example below:
Create a new project, and on its form, drop a TClientDataSet named CDS1 and a TcxTreelist.
Also, drop a TDataSource and TDBGrid onto the form and connect them up to the CDS in the usual way so that you can see the data you're working with.
Edit the code of the main form as shown below. It's probably easiest if you create a new
OnCalcFields event for CDS1 ond then cut'n paste the calcfields code into it.
As you'll see from the code, the calculated fields are actually of type fkInternalCalc.
The reason for this is so that the CDS can be indexed on them (unlike fxCalculated fields
which don't permit this).
The project is intended to be as self-contained as possible: that's why the CDS's
fields and the cxTreeList columns are all created in code, and why the project
uses a CDS as the dataset, so that all the data can be created in code and doesn't require
an external database or server.
You'll see that once the Quarter and Month nodes are set up, it's pretty trivial to
"hang" the individual data rows off them (in the while not CDS1.eof loop).
The Description calculated column is there so as to be able to display some information
specific to an individual data row in the cxTreeList. Obviously, you could have columns which get their values from individual dataset fields instead if you wanted.
Code:
type
TForm1 = class(TForm)
cxTreeList1: TcxTreeList;
CDS1: TClientDataSet;
DataSource1: TDataSource;
DBGrid1: TDBGrid;
procedure FormCreate(Sender: TObject);
procedure CDS1CalcFields(DataSet: TDataSet);
private
CDS1ID: TIntegerField;
CDS1ADate: TDateTimeField;
CDS1Name: TStringField;
CDS1Month: TIntegerField;
CDS1Description: TStringField;
CDS1Quarter: TIntegerField;
colQuarter : TcxTreeListColumn;
colMonth: TcxTreeListColumn;
colDataRow: TcxTreeListColumn;
protected
public
QuarterNodes : array[1..4] of TcxTreeListNode;
MonthNodes : array[1..12] of TcxTreeListNode;
end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
var
i : Integer;
Quarter,
Month : Integer;
NewNode : TcxTreeListNode;
begin
// First, create the dataset's fields
CDS1ID := TIntegerField.Create(Self);
CDS1ID.FieldName := 'ID';
CDS1ID.DataSet := CDS1;
CDS1Name := TStringField.Create(Self);
CDS1Name.Size := 20;
CDS1Name.FieldName := 'Name';
CDS1Name.DataSet := CDS1;
CDS1ADate := TDateTimeField.Create(Self);
CDS1ADate.FieldName := 'Date';
CDS1ADate.DataSet := CDS1;
CDS1Quarter := TIntegerField.Create(Self);
CDS1Quarter.FieldName := 'Quarter';
CDS1Quarter.FieldKind := fkInternalCalc;
CDS1Quarter.DataSet := CDS1;
CDS1Month := TIntegerField.Create(Self);
CDS1Month.FieldName := 'Month';
CDS1Month.FieldKind := fkInternalCalc;
CDS1Month.DataSet := CDS1;
CDS1Description := TStringField.Create(Self);
CDS1Description.Size := 80;
CDS1Description.FieldName := 'Description';
CDS1Description.FieldKind := fkInternalCalc;
CDS1Description.DataSet := CDS1;
// Next create the dataset's index and data rows
CDS1.CreateDataSet;
CDS1.IndexFieldNames := 'Quarter;Month;ID';
for i := 1 to 20 do begin
CDS1.Insert;
CDS1ID.AsInteger := i;
CDS1Name.AsString := 'Row' + IntToStr(i);
CDS1ADate.AsDateTime := Now - 365 + random(366); // This sets the ADate field
// to a date in the past year
CDS1.Post;
end;
try
// Next set up the cxTreeList's columns
cxTreeList1.BeginUpdate;
colQuarter := cxTreeList1.CreateColumn(Nil);
colQuarter.Caption.Text := 'Quarter';
colMonth := cxTreeList1.CreateColumn(Nil);
colMonth.Caption.Text := 'Month';
colDataRow := cxTreeList1.CreateColumn(Nil);
colDataRow.Caption.Text := 'DataRow';
colDataRow.Width := 300;
// Set up the top level (Quarter) and next level (Month) nodes
for Quarter := 1 to 4 do begin
QuarterNodes[Quarter] := cxTreeList1.Root.AddChild;
QuarterNodes[Quarter].Values[0] := Quarter;
for Month := 1 to 3 do begin
MonthNodes[(Quarter - 1) * 3 + Month] := QuarterNodes[Quarter].AddChild;
MonthNodes[(Quarter - 1) * 3 + Month].Values[0] := QuarterNodes[Quarter].Values[0];
MonthNodes[(Quarter - 1) * 3 + Month].Values[1] := (Quarter - 1) * 3 + Month;
end;
end;
// Next, create individual nodes for the Data rows and add them as children
// of the relevant month
CDS1.DisableControls;
try
CDS1.First;
while not CDS1.Eof do begin
Month := CDS1Month.AsInteger;
NewNode := MonthNodes[Month].AddChild;
NewNode.Values[0] := MonthNodes[Month].Values[0];
NewNode.Values[1] := MonthNodes[Month].Values[1];
NewNode.Values[2] := CDS1Description.AsString;
CDS1.Next;
end;
finally
CDS1.First;
CDS1.EnableControls;
end;
finally
cxTreeList1.FullExpand;
cxTreeList1.EndUpdate;
end;
end;
procedure TForm1.CDS1CalcFields(DataSet: TDataSet);
var
AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word;
ADayNumber,
AWeekNumber : Word;
ADate : TDateTime;
S : String;
begin
ADate := CDS1ADate.AsDateTime;
DecodeDateTime(ADate, AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond);
CDS1Quarter.AsInteger := 1 + AMonth div 4;
CDS1Month.AsInteger := AMonth;
CDS1Description.AsString := Format('ID: %d, Name: %s, Date: %s', [CDS1ID.AsInteger, CDS1Name.AsString, CDS1ADate.AsString]);
end;
Using Delphi XE8 I'm currently testing functionality with Firemonkey TListViews.
One thing I'm trying to do is to load a field of all records from a TFDMemtable component into a Listview Item, specifically into the DetailObject of the ListView Item.
For example, I have 3 records in a table (db field is called 'Name'):
Record 1 = Name 1
Record 2 = Name 2
Record 3 = Name 3
There is only 1 DetailObject property per ListView Item so my question is, would I be able to add all of the fields (Name 1, Name 2, Name 3) into that one DetailObject?
Below is what I've attempted so far but no luck. Not 100% sure what I need to do.
procedure MainForm.BuildList;
var LItem : TListViewItem;
begin
ListView1.BeginUpdate;
try
ListView1.CLearItems;
LItem := ListView1.Items.Add;
LItem.Objects.DetailObject.Visible := True;
with memtable do
begin
while not eof do
begin
LItem.Detail := FieldByName('Name').AsString;
end;
end;
finally
ListView1.EndUpdate;
end;
end;
I'm sorry if this isn't clear enough, please let me know.
Any help would be great.
I think I should warn you that before seeing your q, I'd never done anything with FMX ListViews and Master/Detail datasets. The Following is a little rough around the edges, and the layout isn't ideal, but it shows one way to populate a ListView from Master + Detail datasets. I have no idea whether there are better ways. Personally, I would see if I could use Live Bindings to do the job.
procedure TMasterDetailForm.BuildList;
var
LItem : TListViewItem;
DetailItem : TListViewItem;
ListItemText : TListItemText;
DetailIndex : Integer;
begin
ListView1.BeginUpdate;
ListView1.ItemAppearanceObjects.ItemEditObjects.Text.TextVertAlign := TTextAlign.Leading; // The default
// seems to be `Center`, whereas we want the Master field name to be at the top of the item
try
ListView1.Items.Clear; //Items;
Master.First;
while not Master.eof do begin
LItem := ListView1.Items.Add;
LItem.Text := Master.FieldByName('Name').AsString;
LItem.Height := 25;
Detail.First;
DetailIndex := 0;
while not Detail.Eof do begin
Inc(DetailIndex);
ListItemText := TListItemText.Create(LItem);
ListItemText.PlaceOffset.X := 100;
ListItemText.PlaceOffset.Y := 25 * (DetailIndex - 1);
ListItemText.TextAlign := TTextAlign.Leading;
ListItemText.Name := 'Name' + IntToStr(DetailIndex); //Detail.FieldByName('Name').AsString;
LItem.Data['Name' + IntToStr(DetailIndex)] := Detail.FieldByName('Name').AsString;
Detail.Next;
end;
LItem.Height := LItem.Height * (1 + DetailIndex);
Master.Next;
end;
finally
ListView1.EndUpdate;
end;
end;
TListItemText is one of a number of "drawable" FMX objects that can be added to do the TListViewItem. They seem to need unique names so that they can be accessed via the Names property.
FWIW, I used 2 TClientDataSets as the Master and Detail in my code.
Also FWIW, for FMX newbies like me, populating an FMX TreeView is a lot more like what you'd do in a VCL project:
procedure TMasterDetailForm.BuildTree;
var
PNode,
ChildNode : TTreeViewItem;
begin
TreeView1.BeginUpdate;
try
TreeView1.Clear;
Master.First;
while not Master.eof do begin
PNode := TTreeViewItem.Create(TreeView1);
TreeView1.AddObject(PNode);
PNode.Text := Master.FieldByName('Name').AsString;
Detail.First;
while not Detail.Eof do begin
ChildNode := TTreeViewItem.Create(TreeView1);
ChildNode.Text := Detail.FieldByName('Name').AsString;
PNode.AddObject(ChildNode);
Detail.Next;
end;
Master.Next;
end;
finally
TreeView1.EndUpdate;
end;
end;
Btw, in your code you should have been calling
memtable.Next;
in your while not eof loop, and memtable.First immediately before the loop.
i have a DBGrid and it is linked to client dataset when i assign a SQLQuery at run time
the DBGrid automatically assigns no of column. What i need is when DBGrid automatically assign columns i need to set one of those columns to assign a picklist.
can anyone help me?
the following procedure calls in the forms on show event. the form contains DataSource, ClientDataSet, SQLViewQuery (TSQLQuery), DatasetProvider and DBGridDetails (TDBGrid).
procedure TViewDetailsForm.ViewPendingAndReturnCheques;
var I : Integer;
slPickList:TStringList;
begin
slPickList := TStringList.Create;
slPickList.Add('Pending');
slPickList.Add('Returned');
slPickList.Add('Passed');
SQL := 'SELECT a.CHEQUE_NO, a.BANK, a.CHEQUE_DATE, a.AMOUNT,a.STATUS FROM CHEQUES a';
//refreshisng the DBGrid
SQLViewQuery.SQL.Clear;
SQLViewQuery.SQL.Add(SQL);
ClientDataSet.Active := false;
ClientDataSet.Active := true;
DBGridDetails.Columns[0].Width := _Block;
DBGridDetails.Columns[1].Width := _Block;
DBGridDetails.Columns[2].Width := _Block;
DBGridDetails.Columns[3].Width := _Block;
DBGridDetails.Columns[4].Width := _Block;
for I := 0 to DBGridDetails.Columns.Count - 1 do
begin
if DBGridDetails.Columns[I].FieldName = 'STATUS' then
begin
DBGridDetails.Columns[i].ButtonStyle := cbsAuto;
DBGridDetails.Columns[I].PickList := slPickList;
end;
end;
Show;
end;
Here's a sample app I just created in Delphi 2007 that demonstrates how to accomplish this. Here's all I did to set it up:
Click File->New-VCL Forms Application from the IDE's main menu.
Drop a TClientDataSet, a TDataSource, and a TDBGrid on the form.
Click on the form, and then use the Object Inspector to create a new OnCreate event handler. Add the following code:
procedure TForm1.FormCreate(Sender: TObject);
var
SL: TStringList;
begin
with ClientDataSet1 do
begin
FieldDefs.Clear;
FieldDefs.Add('OrderNo', ftInteger);
FieldDefs.Add('Status', ftString, 10);
CreateDataSet;
end;
ClientDataSet1.Active := True;
// Connect a datasource to the CDS
DataSource1.DataSet := ClientDataSet1;
// Connect the grid to that datasource to create the columns.
DBGrid1.DataSource := DataSource1;
// Create the picklist for the second column (Status)
SL := TStringList.Create;
try
SL.Add('Pending');
SL.Add('Returned');
SL.Add('Passed');
DBGrid1.Columns[1].ButtonStyle := cbsAuto;
DBGrid1.Columns[1].PickList := SL;
finally
SL.Free;
end;
end;
Run the application, click in the Status column in the grid, and you'll see the three choices added to the PickList above.
You can assign values to the dbgrid column picklist during the run time.
Below is the code:
procedure Tfrm1.FormShow(Sender: TObject);
var
slPickList:TStringList;
I: Integer;
begin
slPickList := TStringList.Create;
slPickList.Add('Pending');
slPickList.Add('Returned');
slPickList.Add('Passed');
for I := 0 to 2 do
begin
dbgViewAxiomClaims.Columns1.PickList.add(slPickList[i]);//assigning
end;
end;
Below is the result:
I'm trying to add a column between existing columns in a TListView. Therefor I add the new column at the end and move it by setting it`s index to the designated value. This works, until adding another new column.
What I did:
Add the column at last position (Columns.Add) and add the subitem at the last position (Subitems.Add) too. Afterwards I move the column by setting it's index to the correct position.
This works fine as long as it's just one column that gets added. When adding a second new column, the subitems get screwed up. The new subitem of the first column is moved to the last position, e.g. like this:
0 | 1 | new A | new B | 3
Caption | old sub 1 | old sub 3 | new Sub B | new sub A
I would be very happy if someone could help!
For example, is there maybe a command or message I can send to the ListView so it refreshes or saves it's Column --> Subitem mapping that I could use after adding the first new column and it's subitems so I can handle the second new column the same way as the first.
Or is this just a bug of TListViews column-->subitem handling or TListColumns...?
example code for a vcl forms application (assign the Form1.OnCreate event):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ComCtrls;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
listview: TListView;
initButton: TButton;
addColumn: TButton;
editColumn: TEdit;
subItemCount: Integer;
procedure OnInitClick(Sender: TObject);
procedure OnAddClick(Sender: TObject);
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
listview := TListView.Create(self);
with listview do
begin
Left := 8;
Top := 8;
Width := self.Width - 30;
Height := self.Height - 100;
Anchors := [akLeft, akTop, akRight, akBottom];
TabOrder := 0;
ViewStyle := vsReport;
Parent := self;
end;
initButton := TButton.Create(self);
with initButton do
begin
left := 8;
top := listview.Top + listview.Height + 20;
Width := 75;
Height := 25;
TabOrder := 1;
Caption := 'init';
OnClick := OnInitClick;
Parent := self;
end;
editColumn := TEdit.Create(self);
with editColumn do
begin
left := initButton.Left + initButton.Width + 30;
top := listview.Top + listview.Height + 20;
Width := 120;
Height := 25;
TabOrder := 2;
Parent := self;
Caption := '';
end;
addColumn := TButton.Create(self);
with addColumn do
begin
left := editColumn.Left + editColumn.Width + 10;
top := listview.Top + listview.Height + 20;
Width := 75;
Height := 25;
TabOrder := 1;
Enabled := true;
Caption := 'add';
OnClick := OnAddClick;
Parent := self;
end;
end;
procedure TForm1.OnInitClick(Sender: TObject);
var col: TListColumn;
i, j: integer;
item: TListItem;
begin
listview.Items.Clear;
listview.Columns.Clear;
// add items
for I := 0 to 2 do
begin
col := ListView.Columns.Add;
col.Caption := 'column ' + IntToStr(i);
col.Width := 80;
end;
// add columns
for I := 0 to 3 do
begin
item := ListView.Items.Add;
item.Caption := 'ItemCaption';
// add subitems for each column
for j := 0 to 1 do
begin
item.SubItems.Add('subitem ' + IntToStr(j+1));
end;
end;
subItemCount := 5;
end;
procedure TForm1.OnAddClick(Sender: TObject);
var number: integer;
col: TListColumn;
i: Integer;
ascii: char;
begin
listview.Columns.BeginUpdate;
number := StrToInt(editColumn.Text);
ascii := Chr(65 + number);
// create the new column
col := TListColumn(ListView.Columns.add());
col.Width := 80;
col.Caption := ascii;
// add the new subitems
for I := 0 to ListView.Items.Count-1 do
begin
ListView.Items[i].SubItems.Add('subitem ' + ascii);
end;
// move it to the designated position
col.Index := number;
listview.Columns.EndUpdate;
Inc(subItemCount);
end;
end.
Thank you!
Edit: The suggested fix from Sertac Akyuz works fine, though I can't use it because changing the Delphi sourcecode is no solution for my project. Bug is reported.
Edit: Removed the second question that was unintended included in the first post and opened new question (See linked question and Question-revision).
Update: The reported bug is now closed as fixed as of Delphi XE2 Update 4.
Call the UpdateItems method after you've arranged the columns. E.g.:
..
col.Index := number;
listview.UpdateItems(0, MAXINT);
..
Update:
In my tests, I still seem to need the above call in some occasion. But the real problem is that "there is a bug in the Delphi list view control".
Duplicating the problem with a simple project:
Place a TListView control on a VCL form, set its ViewStyle to 'vsReport' and set FullDrag to 'true'.
Put the below code to the OnCreate handler of the form:
ListView1.Columns.Add.Caption := 'col 1';
ListView1.Columns.Add.Caption := 'col 2';
ListView1.Columns.Add.Caption := 'col 3';
ListView1.AddItem('cell 1', nil);
ListView1.Items[0].SubItems.Add('cell 2');
ListView1.Items[0].SubItems.Add('cell 3');
Place a TButton on the form, and put the below code to its OnClick handler:
ListView1.Columns.Add.Caption := 'col 4';
Run the project and drag the column header of 'col 3' to in-between 'col 1' and 'col 2'. The below picture is what you'll see at this moment (everything is fine):
Click the button to add a new column, now the list view becomes:
Notice that 'cell 2' has reclaimed its original position.
Bug:
The columns of a TListView (TListColumn) holds its ordering information in its FOrderTag field. Whenever you change the order of a column (either by setting the Index property or by dragging the header), this FOrderTag gets updated accordingly.
Now, when you add a column to the TListColumns collection, the collection first adds the new TListColumn and then calls the UpdateCols method. The below is the code of the UpdateCols method of TListColumns in D2007 VCL:
procedure TListColumns.UpdateCols;
var
I: Integer;
LVColumn: TLVColumn;
begin
if not Owner.HandleAllocated then Exit;
BeginUpdate;
try
for I := Count - 1 downto 0 do
ListView_DeleteColumn(Owner.Handle, I);
for I := 0 to Count - 1 do
begin
with LVColumn do
begin
mask := LVCF_FMT or LVCF_WIDTH;
fmt := LVCFMT_LEFT;
cx := Items[I].FWidth;
end;
ListView_InsertColumn(Owner.Handle, I, LVColumn);
Items[I].FOrderTag := I;
end;
Owner.UpdateColumns;
finally
EndUpdate;
end;
end;
The above code removes all columns from the underlying API list-view control and then inserts them anew. Notice how the code assigns each inserted column's FOrderTag the index counter:
Items[I].FOrderTag := I;
This is the order of the columns from left to right at that point in time. If the method is called whenever the columns are ordered any different than at creation time, then that ordering is lost. And since items do not change their positions accordingly, it all gets mixed up.
Fix:
The below modification on the method seemed to work for as little as I tested, you need to carry out more tests (evidently this fix does not cover all possible cases, see 'torno's comments below for details):
procedure TListColumns.UpdateCols;
var
I: Integer;
LVColumn: TLVColumn;
ColumnOrder: array of Integer;
begin
if not Owner.HandleAllocated then Exit;
BeginUpdate;
try
SetLength(ColumnOrder, Count);
for I := Count - 1 downto 0 do begin
ColumnOrder[I] := Items[I].FOrderTag;
ListView_DeleteColumn(Owner.Handle, I);
end;
for I := 0 to Count - 1 do
begin
with LVColumn do
begin
mask := LVCF_FMT or LVCF_WIDTH;
fmt := LVCFMT_LEFT;
cx := Items[I].FWidth;
end;
ListView_InsertColumn(Owner.Handle, I, LVColumn);
end;
ListView_SetColumnOrderArray(Owner.Handle, Count, PInteger(ColumnOrder));
Owner.UpdateColumns;
finally
EndUpdate;
end;
end;
If you are not using packages you can put a modified copy of 'comctrls.pas' to your project folder. Otherwise you might pursue run-time code patching, or file a bug report and wait for a fix.
I'm a newbie into Delphi and i need an advice.
I'm using a TMS TDBAdvGrid and i need to sort the data when the user is clicking the header of a column. I setup the sort settings of the grid and i write code for the onclicksort event, but it is not working.
The sort settings of the grid:
SortSettings.Show = True;
SortSettings.IgnoreBlanks = True;
SortSettings.BlankPos = blLast;
the onclicksort event:
try
try
if FSortISWorking then
Exit;
FSortISWorking := true;
if ACol < 0 then
begin
grid.BeginUpdate;
grid.SortSettings.Column := ACol;
Application.ProcessMessages;
grid.QSort;
grid.EndUpdate;
end;
except on e: Exception do
begin
// log the error
end;
end;
finally
FSortISWorking := false;
end;
The grid is not linked directly to the database. The data is loaded into memory (TClientDataSet) and i need to sort the data only in memory, without another query to the database.
Thank you
I tried your example and this solved the issue for me:
Grid.PageMode := False;
In order to resolve this problem you must order the dataset behind your grid. here you have how to do this in general:http://delphi.about.com/od/usedbvcl/l/aa042203a.htm.
bellow you have an example:
procedure TForm1.DBAdvGrid1CanSort(Sender:TObject; ACol: Integer; var DoSort: Boolean);
var fldname:string;
begin
DoSort := False; // disable internal sort
// toggle sort order if
dbadvgrid1.SortSettings.Direction = sdAscending then
dbadvgrid1.SortSettings.Direction := sdDescending else
dbadvgrid1.SortSettings.Direction := sdAscending;
// get field name of the column
clicked fldname :=query1.FieldList.Fields[ACol -1].FieldName;
if pos(' ',fldname) 0 then fldname:= 'biolife.db."'+fldname+'"';
// add ORDER BY clause to the query
query1.SQL.Text := 'select * from
biolife.db ORDER BY '+fldname;
if dbadvgrid1.SortSettings.Direction =
sdDescending then query1.SQL.Text :=
query1.SQL.Text + ' DESC';
query1.Active := true;
DBAdvGrid1.SortSettings.Column := ACol;
end;
if you want to order your clientdataset here you have how to do it:
http://edn.embarcadero.com/article/29056
best regards,
Radu