1

我有一个动态代码,它在 StringGrid 单元格中创建了一个组合框,这个组合是在运行时创建的,我应该为它设置 onChange 事件。我在下面使用这段代码,但是这段代码引发了一个异常,有人可以帮我在 TNotifyEvent 中成为我的 comboBoxOnChange 方法吗?

procedure TForm1.gridSelectCell(Sender: TObject; ACol, ARow: Integer;
  var CanSelect: Boolean);
var
  R: TRect;
  combo : TComboBox;
   procedure comboBoxOnChange(Sender: TObject);
   begin
      combo.Visible := false;
      combo.Free;
   end;
begin
  combo          := TComboBox.Create(self);
  combo.Parent   := self;
  //[DCC Error] Unit1.pas(57): E2010 Incompatible types: 'TNotifyEvent' and 'procedure, untyped pointer or untyped parameter'
  combo.OnChange := comboBoxOnChange;

  combo.Items.Add('Item1');
  combo.Items.Add('Item2');
  combo.Items.Add('Item3');
  combo.Items.Add('Item4');
  combo.Items.Add('Item5');
  combo.Items.Add('Item6');
  combo.Items.Add('Item7');
  combo.Items.Add('Item8');
  combo.Items.Add('Item9');
  combo.Items.Add('Item10');

    R         := Grid.CellRect(ACol, ARow);
    R.Left    := R.Left   + grid.Left;
    R.Right   := R.Right  + grid.Left;
    R.Top     := R.Top    + grid.Top;
    R.Bottom  := R.Bottom + grid.Top;

    combo.Left := R.Left + 1;
    combo.Top := R.Top + 1;
    combo.Width := (R.Right + 1) - R.Left;
    combo.Height := (R.Bottom + 1) - R.Top;
    combo.Visible := True;
    combo.SetFocus;
    CanSelect := True;
end;
4

2 回答 2

3

如果您手动声明和填写TMethod记录,然后在将其分配给目标事件时进行类型转换,则可以使用任何非类方法过程作为事件处理程序。此外,不是类的成员意味着Self缺少隐藏参数,因此您必须显式声明它。

在嵌套过程的情况下,只要过程不尝试访问其包含过程中的任何内容,这种方法就可以正常工作,因为当事件实际触发时,这些变量将不再在范围内。

话虽如此,更大的问题是控件不能Free()从其自己的事件之一中自身,否则您将收到 AccessViolation 错误。这是因为在事件处理程序退出后 RTL 仍然需要访问对象。因此,您必须将调用延迟Free()到事件处理程序退出之后,例如通过发布自定义窗口消息,PostMessage()以便它通过消息队列。

尝试这个:

type
  TForm1 = class(TForm)
    //...
  protected
    procedure WndProc(var Message: TMessage); override;
    //...
  end;

const
  APPWM_FREE_OBJECT = WM_APP + 100;

procedure TForm1.WndProc(var Message: TMessage);
begin
  if Message.Msg = APPWM_FREE_OBJECT then
    TObject(Message.LParam).Free
  else
    inherited;
end;

procedure TForm1.gridSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);
var
  combo : TComboBox;
  M: TMethod;
  //...

  procedure comboBoxOnChange(Self: Pointer; Sender: TObject);
  begin
    TComboBox(Sender).Visible := false;
    //combo.Free;
    PostMessage(Form1.Handle, APPWM_FREE_OBJECT, 0, LPARAM(Sender));
  end;

begin
  combo          := TComboBox.Create(Self);
  combo.Parent   := Self;
  //...

  M.Code := Addr(comboBoxOnChange);
  M.Data := combo;
  combo.OnChange := TNotifyEvent(M);

  CanSelect := True;
end;
于 2013-05-22T17:08:57.050 回答
1

不能将嵌套过程用作事件处理程序,您必须将其设置为以下形式的方法:

type
  TForm1 = class(...)
    private
      procedure comboBoxOnChange(Sender: TObject);
      ...
  end

procedure TForm1.comboBoxOnChange(Sender: TObject);
var combo : TComboBox;
begin
  combo := Sender as TComboBox;
  combo.Visible := false;
  combo.Free;
end;
于 2013-05-22T13:25:26.770 回答