SOLID Developper
SOLID Developper

Reputation: 816

Uncheckable dynamically created TCheckBox in Delphi XE4

I want to create a property editor because a lot of things does not supported by TValueListEditor. So I use a TStringGrid and other controls placed on it when the user enter the cells. When I place a TCheckBox for boolean values, the dynamically created TCheckBox is uncheckable. The onClick event handler does not fiered by the clicks (the grid fiered) and the caption of the TCheckBox lost its opacity. I set its parent and bring it to the front. By this time I used TEdit and TComboBox controls as well and they work fine. Somebody can help to use it in the expected way?

Here is an example to recreate the situation.

pas:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.Grids,
  StdCtrls;

type
  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    CheckBox1: TCheckBox;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    procedure onCheckBoxClicked( sender_ : TObject );
  public
    { Public declarations }
    fCheckBox : TCheckBox;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.onCheckBoxClicked( sender_ : TObject );
begin
  if ( TCheckBox( sender_ ).checked ) then
    TCheckBox( sender_ ).caption := 'true'
  else
    TCheckBox( sender_ ).caption := 'false';
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  fCheckBox := TCheckBox.create( NIL );
  fCheckBox.Parent := stringGrid1;
  fCheckBox.caption := 'Dynamic checkbox';
  fCheckBox.left := 70;
  fCheckBox.top := 30;
  fCheckBox.onClick := onCheckBoxClicked;
  fCheckBox.BringToFront;
  stringgrid1.cells[1,1] := 'fgfgfgfgfgf';
  stringgrid1.cells[1,2] := 'fgfgfgfgfgf';
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  fCheckBox.Free;
end;

end.

The dfm:

object Form1: TForm1
  Left = 358
  Top = 183
  Caption = 'Form1'
  ClientHeight = 601
  ClientWidth = 854
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'Tahoma'
  Font.Style = []
  OldCreateOrder = False
  OnCreate = FormCreate
  OnDestroy = FormDestroy
  PixelsPerInch = 96
  TextHeight = 13
  object StringGrid1: TStringGrid
    Left = 120
    Top = 72
    Width = 320
    Height = 120
    TabOrder = 0
  end
  object CheckBox1: TCheckBox
    Left = 192
    Top = 128
    Width = 97
    Height = 17
    Caption = 'Static checkbox'
    TabOrder = 1
  end
end

Upvotes: 3

Views: 369

Answers (1)

Sertac Akyuz
Sertac Akyuz

Reputation: 54802

This does not work with a checkbox because the string grid intercepts processing of the WM_COMMAND message. When you click the checkbox, a WM_COMMAND notification is sent to its parent - which is the string grid. The grid, in TCustomGrid.WMCommand of 'Vcl.Grids', checks if the notification is from its inplace editor and discards the message otherwise.

You can modify the processing of the message on the grid to change the behavior. One way is to derive a new control. E.g.

type
  TStringGrid = class(vcl.grids.TStringGrid)
  protected
    procedure WMCommand(var Message: TWMCommand); message WM_COMMAND;
  end;

  TForm1 = class(TForm)
    StringGrid1: TStringGrid;
    ....

...

procedure TStringGrid.WMCommand(var Message: TWMCommand);
var
  Control: TWinControl;
begin
  inherited;
  Control := FindControl(Message.Ctl);
  if Assigned(Control) and (Control <> InplaceEditor) then
    Control.Perform(Message.Msg, MakeWParam(Message.ItemID, Message.NotifyCode),
        Message.Ctl);
end;

Then the OnClick will fire. You don't need BringToFront, it works among sibling controls.


Regarding opacity, it's the checkbox's default appearance. You can verify this by placing a checkbox overlapping a label on the form itself.

Upvotes: 4

Related Questions