【问题标题】:Getting column index of a clicked control in TGridPanel在 TGridPanel 中获取单击控件的列索引
【发布时间】:2016-08-16 14:09:45
【问题描述】:

我正在使用TGridPanel 来保存一些面板。在设计时,我将网格面板设置为 1 行 5 列。

我可以使用这段代码在网格中添加一个面板,效果很好:

procedure TForm6.AddPanelToGrid(const ACaption: string);
var
  pnl: TPanel;
begin
  pnl := TPanel.Create(gpOne);
  pnl.Caption := ACaption;
  pnl.Parent := gpOne;
  pnl.Name := 'pnlName' + ACaption;
  pnl.OnClick := gpOne.OnClick;
  pnl.ParentBackground := false;
  pnl.ParentColor := false;
  pnl.Color := clLime;
  pnl.Font.Size := 14;
  gpOne.ControlCollection.AddControl(pnl);
  pnl.Height := pnl.Width;
end;

我想要做的是当我点击它时从网格中删除一个TPanel(这就是为什么我在上面的代码中将点击处理程序设置为网格面板的处理程序)。

在那个点击处理程序中我这样做了,这几乎可以工作:

procedure TForm6.gpOneClick(Sender: TObject);
begin
  if not (sender is TPanel) then exit;

  gpOne.ControlCollection.RemoveControl(Sender as TPanel);
  (Sender as TPanel).Free;

  gpOne.UpdateControlsColumn( 0 );  <<<-------
  gpOne.UpdateControlsRow(0);

  gpOne.Refresh();
end;

使用UpdateControlColumn() 的参数会导致网格中面板的顺序发生变化 - 第一个和第二个交换位置。

我可以通过将列 idex 添加到面板的标记属性中来解决此问题,然后将其传递给 UpdateControlColumn()。这样就可以了,但是一旦面板被删除,更高的标签号就不再有效 - 面板已经移动了列。

那么,如何从OnClick 处理程序中获取面板所在的列?

我正在使用 Delphi 10.1 Berlin - 如果这有什么不同的话。

为了测试这一点,我开始了一个新项目,添加了一个TGridPanel,将其设置为 1 行和 5 个等宽的列。我添加了 6 个 TButton 控件并为每个控件创建了一个 OnClick 处理程序,代码如下:

AddPanelToGrid('One');  // changing the string for each button.

单击几个按钮添加一些面板,然后单击面板将其删除。

【问题讨论】:

  • 当您仍在事件处理程序中时,在事件的Sender 上调用Free()永远安全的。在事件处理程序退出后,RTL 仍然需要访问对象。如果您需要释放Sender,您必须延迟释放直到处理程序退出之后。通常,我通过使用PostMessage() 向自己发布一条自定义窗口消息,其中包含LParam 中的对象指针,然后在安全的情况下让消息处理程序释放对象。这类似于TForm 在其OnClose 事件处理程序返回Action=caFree 时使用CM_RELEASE 释放自身。
  • 谢谢@RemyLebeau,如果我继续使用这种方法,我会采纳你的建议。亲切的问候,

标签: delphi vcl delphi-10.1-berlin tgridpanel


【解决方案1】:

TCustomGridPanel 有一对有用的函数,CellIndexToCell()CellToCellIndex,但它们不是公共的,因此不能从 TGridPanel 直接访问。

为了使它们可用,请重新声明TGridPanel,如下所示:

type
  TGridPanel = class(Vcl.ExtCtrls.TGridPanel)  // add this
  end;                                         // -"-
  TForm27 = class(TForm)
    Button1: TButton;
    gpOne: TGridPanel;
    ...
  end;

然后为row和col添加rc变量,添加对CellIndexToCell()的调用并使用c作为UpdateControlsColumn的参数:

procedure TForm27.gpOneClick(Sender: TObject);
var
  r, c: integer;
begin
  if not (sender is TPanel) then exit;

  gpOne.CellIndexToCell(gpOne.ControlCollection.IndexOf(Sender as TPanel), c, r); // add this

  gpOne.ControlCollection.RemoveControl(Sender as TPanel);
  (Sender as TPanel).Free;

  gpOne.UpdateControlsColumn( c );  // <<<-------
  gpOne.UpdateControlsRow(0);

  gpOne.Refresh();
end;

并遵循 Remy Lebeau 的建议,以释放面板。 (我刚刚注意到他的评论)。


如果您还没有,您可能还想看看TFlowPanel 及其FlowStyle 属性。 TflowPanel 如果您使用多行,则删除后重新排序更容易预测,但当然取决于您的需要。

【讨论】:

  • 谢谢你,@TomBrunberg - 非常感谢。我只需要一排最多 5 个面板 - 不需要流动或调整大小,所以 TFlowPanel 会过度杀戮。亲切的问候,
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-27
  • 1970-01-01
  • 2011-02-24
  • 1970-01-01
相关资源
最近更新 更多