Mirror

Combobox instead inplace editor in TStringGrid (Views: 713)


Problem/Question/Abstract:

How can I use a combobox as inplace editor in standard TStringGrid?

Answer:

I wrote a small app which demonstrates how you can use the some combobox instead standard inplace editor in TStringGrid component.

Also in this app you can view how change font and/or alignment for some cells.

The form contents as text:

object frmMain: TfrmMain
  Left = 200
    Top = 108
    Width = 510
    Height = 382
    Caption = 'Example: TStringGrid advanced using'
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'MS Sans Serif'
    Font.Style = []
    OnCreate = FormCreate
    PixelsPerInch = 96
    TextHeight = 13
    object StringGrid1: TStringGrid
    Left = 24
      Top = 152
      Width = 457
      Height = 161
      ColCount = 2
      DefaultColWidth = 200
      DefaultRowHeight = 21
      RowCount = 9
      TabOrder = 0
      OnDrawCell = StringGrid1DrawCell
      OnSelectCell = StringGrid1SelectCell
      ColWidths = (
      118
      296)
  end
  object cbInplaceComboBox: TComboBox
    Left = 32
      Top = 320
      Width = 145
      Height = 21
      Style = csDropDownList
      ItemHeight = 13
      Items.Strings = (
      '1 value'
      '2 value'
      '3 value'
      '4 value'
      '5 value'
      '6 value'
      '7 value'
      '8 value'
      '9 value')
      TabOrder = 1
      OnChange = cbInplaceComboBoxChange
  end
  object btnClose: TButton
    Left = 416
      Top = 320
      Width = 75
      Height = 25
      Cancel = True
      Caption = '&Close'
      default = True
      TabOrder = 2
      OnClick = btnCloseClick
  end
  object MemoDescription: TMemo
    Left = 24
      Top = 8
      Width = 457
      Height = 129
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clNavy
      Font.Height = -11
      Font.Name = 'MS Sans Serif'
      Font.Style = [fsBold]
      Lines.Strings = (
      'In this sample I shows how you can:'
      ' '
      '1. change the inplace editor for second column'
      '    from standard inplace editor to user TComboBox component'
      ' '
      '   view the next procedures:'
      '      - TfrmMain.FormCreate'
      '      - TfrmMain.CMDialogKey'
      '      - TfrmMain.cbInplaceComboBoxChange'
      '      - TfrmMain.StringGrid1SelectCell'
      '  '
      '2. draw the cell values with different fonts'
      ' '
      '   view the next procedure:'
      '      - TfrmMain.StringGrid1DrawCell'
      ' '
      '3. change alignment for cells'
      ' '
      '   view the next procedure:'
      '      - TfrmMain.StringGrid1DrawCell')
      ParentFont = False
      ScrollBars = ssVertical
      TabOrder = 3
  end
end

The pas - file for same form:

unit Main;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Grids;

type
  TfrmMain = class(TForm)
    StringGrid1: TStringGrid;
    cbInplaceComboBox: TComboBox;
    btnClose: TButton;
    MemoDescription: TMemo;
    procedure FormCreate(Sender: TObject);
    procedure cbInplaceComboBoxChange(Sender: TObject);
    procedure StringGrid1SelectCell(Sender: TObject; Col, Row: Integer;
      var CanSelect: Boolean);
    procedure StringGrid1DrawCell(Sender: TObject; Col, Row: Integer;
      Rect: TRect; State: TGridDrawState);
    procedure btnCloseClick(Sender: TObject);
  private
    { Private declarations }
    procedure CMDialogKey(var msg: TCMDialogKey); message CM_DIALOGKEY;
  public
    { Public declarations }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.DFM}

procedure TfrmMain.FormCreate(Sender: TObject);
var
  i: Integer;
begin
  StringGrid1.DefaultRowHeight := cbInplaceComboBox.Height;
  cbInplaceComboBox.Visible := False;

  StringGrid1.Cells[0, 0] := 'Row No';
  StringGrid1.Cells[1, 0] := 'Values (from Combobox)';
  for i := 1 to StringGrid1.RowCount - 1 do
    StringGrid1.Cells[0, i] := IntToStr(i);
end;

procedure TfrmMain.CMDialogKey(var msg: TCMDialogKey);
begin
  if (ActiveControl = cbInplaceComboBox) then
  begin
    if (msg.CharCode = VK_TAB) then
    begin
      //set focus back to the grid and pass the tab key to it
      cbInplaceComboBox.SetFocus;
      cbInplaceComboBox.Perform(WM_KEYDOWN, msg.CharCode, msg.KeyData);
      // swallow this message
      msg.result := 1;
      Exit;
    end;
  end;

  inherited;
end;

procedure TfrmMain.cbInplaceComboBoxChange(Sender: TObject);
var
  intRow: Integer;
begin
  inherited;

  {Get the ComboBox selection and place in the grid}
  with cbInplaceComboBox do
  begin
    intRow := StringGrid1.Row;
    if (StringGrid1.Col = 2) then
      StringGrid1.Cells[2, intRow] := Items[ItemIndex]
    else
      StringGrid1.Cells[StringGrid1.Col, intRow] := Items[ItemIndex];
    Visible := False;
  end;
  StringGrid1.SetFocus;
end;

procedure TfrmMain.StringGrid1SelectCell(Sender: TObject; Col, Row: Integer;
  var CanSelect: Boolean);
var
  R: TRect;
begin
  if ((Col = 1) and (Row <> 0)) then
  begin
    {Size and position the combo box to fit the cell}
    R := StringGrid1.CellRect(Col, Row);
    R.Left := R.Left + StringGrid1.Left;
    R.Right := R.Right + StringGrid1.Left;
    R.Top := R.Top + StringGrid1.Top;
    R.Bottom := R.Bottom + StringGrid1.Top;

    {Show the combobox}
    with cbInplaceComboBox do
    begin
      Left := R.Left + 1;
      Top := R.Top + 1;
      Width := (R.Right + 1) - R.Left;
      Height := (R.Bottom + 1) - R.Top;

      ItemIndex := Items.IndexOf(StringGrid1.Cells[Col, Row]);
      Visible := True;
      SetFocus;
    end;
  end;
  CanSelect := True;
end;

procedure TfrmMain.StringGrid1DrawCell(Sender: TObject; Col, Row: Integer;
  Rect: TRect; State: TGridDrawState);
const
  AlignFlags: array[TAlignment] of Integer =
  (DT_LEFT or DT_VCENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
    DT_RIGHT or DT_VCENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX,
    DT_CENTER or DT_VCENTER or DT_WORDBREAK or DT_EXPANDTABS or DT_NOPREFIX);
var
  s: string;
begin
  inherited;

  with Rect do
  begin
    Left := Left + 2;
    Top := Top + 2;
    Right := Right - 5
  end;

  s := StringGrid1.Cells[Col, Row];

  if (Row = 0) and (Col < StringGrid1.ColCount) then
  begin
    StringGrid1.Canvas.Font.Style := StringGrid1.Canvas.Font.Style + [fsBold];
    StringGrid1.Canvas.Brush.Color := StringGrid1.FixedColor;
    StringGrid1.Canvas.FillRect(Rect);

    DrawText(StringGrid1.Canvas.Handle,
      PChar(s), Length(s),
      Rect, AlignFlags[taCenter]);
  end
  else if (Col = 0) and (Row > 0) and (Row < StringGrid1.RowCount) then
  begin
    StringGrid1.Canvas.FillRect(Rect);
    DrawText(StringGrid1.Canvas.Handle,
      PChar(s), Length(s),
      Rect, AlignFlags[taRightJustify]);
  end;
end;

procedure TfrmMain.btnCloseClick(Sender: TObject);
begin
  Close
end;

end.


Component Download: http://www.geocities.com/mshkolnik/FAQ/strgrid.zip

<< Back to main page