【问题标题】:Uncheckable dynamically created TCheckBox in Delphi XE4Delphi XE4 中不可检查的动态创建的 TCheckBox
【发布时间】:2018-09-25 22:21:31
【问题描述】:

我想创建一个属性编辑器,因为TValueListEditor 不支持很多东西。因此,当用户输入单元格时,我使用了TStringGrid 和其他控件。当我为布尔值放置 TCheckBox 时,动态创建的 TCheckBox 是不可检查的。 onClick 事件处理程序不会被点击触发(网格触发),TCheckBox 的标题失去了不透明度。我设置它的父级并将它带到前面。此时我也使用了TEditTComboBox 控件,它们工作正常。有人可以帮助以预期的方式使用它吗?

这里有一个例子来重现这种情况。

过去:

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.

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

【问题讨论】:

  • 您究竟需要什么TValueListEditor 无法处理? TStringGrid 不是为托管子控件而设计的,除了它自己的就地单元格编辑器。您可能会更幸运,只需使用网格的 OnDrawCell 事件根据需要将 CheckBox 的 图像 所有者绘制到您的单元格上,然后使用网格的 OnMouseDown/Up 事件“切换”检查细胞的状态。您可以使用网格的Objects 属性来跟踪状态数据。
  • @RemyLebeau 很多东西。可折叠的复合值、活动的内联编辑器(TEdit、TComboBox、TCheckBox 和自定义组件)。我想内联使用很多组件种类。
  • 你最好找到一个处理所有这些东西的第三方属性编辑器,并且可以在运行时使用。仅使用默认的 VCL 组件将很难做到这一点。

标签: delphi


【解决方案1】:

这不适用于复选框,因为字符串网格会拦截WM_COMMAND 消息的处理。当您单击复选框时,WM_COMMAND 通知将发送到其父级 - 即字符串网格。位于“Vcl.Grids”的TCustomGrid.WMCommand 中的网格检查通知是否来自其就地编辑器,否则丢弃该消息。

您可以修改网格上消息的处理以改变行为。一种方法是派生新的控件。例如

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;

然后OnClick 将触发。你不需要BringToFront,它可以在兄弟控件之间工作。


关于不透明度,这是复选框的默认外观。您可以通过在表单本身上放置一个与标签重叠的复选框来验证这一点。

【讨论】:

  • FWIW 将复选框放在面板上会更简单,并且有助于点击和不透明度。
  • 事件处理问题解决了。非常感谢。但是透明标题并不是 TCheckBox 的默认行为。我在示例中放置了静态的以说服它。静态控件的标题先覆盖其背景,然后写入文本。应该有一个属性来影响控件的绘制。 (我在文档中没有找到)
  • 您的 TPanel 推荐也解决了我的其他问题。这是一个好主意。再次非常感谢! :)
  • @sertac,我只使用了在 OnDrawCell 事件中呈现的一对 12x12 PNG 图像,但我只是好奇 - 您将复选框放在面板上的建议如何工作?
猜你喜欢
  • 2014-05-12
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 2013-04-18
  • 2013-05-09
  • 2011-07-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多