IT SOLUTIONS
Your full service technology partner! 
-Collapse +Expand
Delphi
Search Delphi Group:

Advanced
-Collapse +Expand Delphi To/From
To/FromCODEGuides
-Collapse +Expand Delphi Store
PRESTWOODSTORE

Prestwood eMagazine

June Edition
Subscribe now! It's Free!
Enter your email:

   ► KBProgrammingDelphi for W...Using Controls   Print This     
Next Random Article Next Random Tidbit || Change Topic Random From All
  From the September 2015 Issue of Prestwood eMag
 
Delphi Using Controls:
TDBGrid: Rerarranging Columns at Will
 
Posted 46 months ago on 8/19/2013
Take Away:

Delphi's TDBGrid is an incredibly useful component; one you'd expect to find in any professional development tool.

One of it's handy behaviors is that users can click in column headers and drag to rearrange column ordering to their liking.

Unfortunately, TDBGrid doesn't offer the developer any really easy way to rearrange grid columns from code. This is inconvenient because you might offer the user a choice of various columns upon which they can search, and it would be nice to make their chosen column the leftmost - at least. Often it makes sense to rearrange other columns as well.

This little class allows you to do that.

It has no exposed methods, and only two properties, so it's incredibly easy to use.

Read on to learn how it works and to get the code.

KB102495



Using TDBGridColumnManager:

1: Set up your TDBGrid. It must already be populated with the desired column specifications before using this little grid manager. Let's say it's named DBGrid1.

2: Instantiate an instance of TDBGridColumnManager:

  MyGridManager := TDBGridColumnManager.Create;

3: Specify the grid that TDBGridColumnManager jis intended to manage.

MyGridManager.Grid := DBGrid1;

4: From then on, you can rearrange the grids columns any time by simply setting the other property, ColumnOrderList, a string. When you do, the columns are reordered instantly.

ColumnOrderList should be a string of data column names separated by commas. Note that I said data column names, not header title captions; In a TDBGrid, these are the names assigned to the FieldName property of each column.

How it works:

The TDBGridColumnManager maintains two private lists. The first, FSpecList, is populated with one instance of the simple TDBGridColumnSpec class for each existing column when you assign your grid to the manager's Grid property. This is why your grid should be all set up and ready to go before you assign it to the object.

The second list FColumnOrderList, gets cleared and populated whenever you assign a list of fields to the ColumnOrderList.

An interesting aside is the simple code in the private setter method, SetColumnOrder. Note that we assign the simple string to the TStringList, FColumnOrderList by using it's CommaText property. This is a nifty feature of the TStringList class. We can get a comma-delimited string from a populated TStringList, or populate a TStringList - both with the CommaText property.

The setter method for the ColumnOrderList property then invokes the private ArrangeColumns method. This method clears the grid's columns, then rebuilds them, in the order specified.

Not bad for about 100 lines of code.

Can this code be further simplified or improved? Oh, absolutely, but I'll leave that to you, the reader. Have fun with it!

unit uDbGridManager;

interface

uses Classes, RzDbGrid, System.Generics.Collections, System.SysUtils,
  Vcl.DBGrids;

type
  TDBGridColumnSpec = class(TObject)
    FieldName: String;
    DataAlignment: TAlignment;
    Title: String;
    TitleAlignment: TAlignment;
    ColumnWidth: integer;
  end;

type
  TDBGridColumnManager = class
  private
    FGrid: TDBGrid;
    FSpecList : TStringList;
    FColumnOrderList : TStringList;
    procedure SetGrid(_value: TDBGrid);
    procedure LoadGridColumns;
    procedure ArrangeColumns;
    procedure SetColumnOrder(_value : string);
  protected
  public
    constructor Create;
    destructor Destroy; override;
    property DbGrid: TDBGrid read FGrid write SetGrid;
    property ColumnOrderList : String write SetColumnOrder;
  end;

implementation

constructor TDBGridColumnManager.Create;
begin
  FSpecList := TStringList.Create;
  FColumnOrderList := TStringList.Create;
  FGrid := nil;
end;

destructor TDBGridColumnManager.Destroy;
begin
  FSpecList.Free;
  FColumnOrderList.Free;
  inherited;
end;


procedure TDBGridColumnManager.LoadGridColumns;
var i : integer;
  thisCol : TColumn;
  newColSpec :  TDBGridColumnSpec;
  fieldName : String;
begin
  FSpecList.Clear;
  for i  := 0 to Pred(FGrid.Columns.Count) do
    begin
      thisCol := FGrid.Columns[i];
      newColSpec :=  TDBGridColumnSpec.Create;
      fieldName := thisCol.FieldName;
      newColSpec.FieldName := fieldName;
      newColSpec.DataAlignment := thisCol.Alignment;
      newColSpec.Title := thisCol.Title.Caption;
      newColSpec.TitleAlignment := thisCol.Title.Alignment;
      newColSpec.ColumnWidth := thisCol.Width;
      FSpecList.AddObject(fieldName, newColSpec);
    end;
end;



procedure TDBGridColumnManager.SetGrid(_value: TDBGrid);
begin
  FGrid := _value;
  LoadGridColumns;
end;


procedure TDBGridColumnManager.ArrangeColumns;
var i, idx : integer;
  fldName : String;
  p : pointer;
  colSpec : TDBGridColumnSpec;
  col : TColumn;
begin
  if not Assigned(FGrid) then
    raise Exception.Create('Grid not assigned.');
  if not Assigned(FSpecList) then
    raise Exception.Create('Column specification list not assigned.');
  FGrid.Columns.Clear;
  for i := 0 to Pred(FColumnOrderList.Count) do
  begin
    fldName := FColumnOrderList.Strings[i];
    idx := FSpecList.IndexOf(fldName);
    if idx > -1 then
    begin
      p := FSpecList.Objects[idx];
      colSpec :=  TDBGridColumnSpec(p);
      col := FGrid.Columns.Add;
      col.FieldName := fldName;
      col.Alignment := colSpec.DataAlignment;
      col.Title.Caption := colSpec.Title;
      col.Title.Alignment := colSpec.TitleAlignment;
      col.Width := colSpec.ColumnWidth;
    end;
  end;
end;

procedure TDBGridColumnManager.SetColumnOrder(_value : string);
begin
  FColumnOrderList.Clear;
  FColumnOrderList.CommaText := _value;
  ArrangeColumns;
end;

end.

Conclusion:

Delphi remains one of the premier systems for developing desktop and portable device applications. One of the reasons for its early - and continued - success is its VCL library of controls, and the ease with which developers can improve them, make them do new things, even create entirely new components.

This little bit of code is an example of how easy it can be to teach the old dog a new trick.


Comments

0 Comments.
Share a thought or comment...
 
Write a Comment...
...
Sign in...

If you are a member, Sign In. Or, you can Create a Free account now.


Anonymous Post (text-only, no HTML):

Enter your name and security key.

Your Name:
Security key = P1225A1
Enter key:
Article Contributed By Wes Peterson:

Wes Peterson is a Senior Programmer Analyst with Prestwood IT Solutions where he develops custom Windows software and custom websites using .Net and Delphi. When Wes is not coding for clients, he participates in this online community. Prior to his 10-year love-affair with Delphi, he worked with several other tools and databases. Currently he specializes in VS.Net using C# and VB.Net. To Wes, the .NET revolution is as exciting as the birth of Delphi.

Visit Profile

 KB Article #102495 Counter
6537
Since 8/19/2013
-
   Contact Us!
 
Have a question? Need our services? Contact us now.
--Mike Prestwood

Call: 916-726-5675

email: info@prestwood.com


Go ahead!   Use Us! Call: 916-726-5675 


©1995-2017 Prestwood IT Solutions.   [Security & Privacy]