如何在运行时使用另一个过程中的过程在comboBox上设置onChange事件?

时间:2013-05-22 13:15:29

标签: delphi combobox

我有一个动态代码,它在StringGrid单元格中创建一个comboBox,这个组合是在运行时创建的,我应该为它设置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;

2 个答案:

答案 0 :(得分: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;

答案 1 :(得分: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;