如何使用下拉菜单检测鼠标单击按钮

时间:2009-07-26 07:58:47

标签: delphi

我的问题从答案中得出 How to create a button with drop-down menu?

我正在尝试复制Mircosoft Office 2007 UI左上角的“Office按钮”的行为;特别是在用户点击按钮的情况下,弹出菜单出现,按钮被重新绘制为“向下”状态。按钮图像保持在Down状态,直到用户单击菜单上的鼠标或表单上的其他位置,甚至是应用程序外部。

我需要检测此鼠标点击,以便我可以重绘正常图像中的按钮,如果我使用自己的对话框作为弹出菜单,则隐藏菜单。

我正在使用D6 谢谢你的建议,
问候,
PhilW。

澄清:

我现在意识到,当使用TPopUpMenu时,答案是微不足道的,因为一旦弹出菜单被显示,它就被错误理解,它留给了主事件循环的命运。我过去很乐意编码。更聪明,有点尴尬(但朋友之间没关系)我的问题应该更具体,并说:

“当我使用对话框表单作为TPopUpMenu时,如何检测此鼠标单击?”

很抱歉这个混乱。

1 个答案:

答案 0 :(得分:1)

也许我错过了一些东西,但至少对于弹出菜单来说这很容易:

procedure TForm1.FormCreate(Sender: TObject);
begin
  SpeedButton1.AllowAllUp := TRUE;
  SpeedButton1.GroupIndex := 1;
end;

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  CurPos: TPoint;
begin
  CurPos := Mouse.CursorPos;
  PopupMenu1.Popup(CurPos.x, CurPos.y);
  SpeedButton1.Down := FALSE;
end;

这是有效的,因为弹出式菜单是使用辅助消息循环显示的,并且在其外部单击确实将其视为与单击菜单项相同。

如果要显示表单而不是弹出菜单,只需提供一个包装函数,该函数仅在表单关闭时返回,类似于上面代码中的Popup()。例如,您可以显示非模态的表单,并使用SetCaptureControl()方法处理所有鼠标事件,即使鼠标光标位于表单区域之外。

修改

一些代码可以帮助您入门 - 它演示了原理,但肯定不完整或最优。而不是弹出菜单显示一个表单:

procedure TForm1.SpeedButton1Click(Sender: TObject);
var
  PtLeftTop: TPoint;
begin
  PtLeftTop := ClientToScreen(Point(SpeedButton1.Left + SpeedButton1.Width,
    SpeedButton1.Top + SpeedButton1.Height));
  TForm2.ShowFormAsPopup(PtLeftTop);
  SpeedButton1.Down := FALSE;
end;

表单包含以下代码:

type
  TForm2 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormKeyDown(Sender: TObject; var Key: Word;
      Shift: TShiftState);
    procedure FormMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormDeactivate(Sender: TObject);
  public
    class procedure ShowFormAsPopup(ATopLeft: TPoint);
  end;

// boilerplate snipped

class procedure TForm2.ShowFormAsPopup(ATopLeft: TPoint);
var
  Form2: TForm2;
  OldDeactivate: TNotifyEvent;
begin
  Form2 := TForm2.Create(nil);
  try
    OldDeactivate := Application.OnDeactivate;
    try
      Application.OnDeactivate := Form2.FormDeactivate;

      Form2.Left := ATopLeft.x;
      Form2.Top := ATopLeft.y;
      Form2.Show;
      SetCaptureControl(Form2);
      while Form2.Visible do
        Application.ProcessMessages;
    finally
      Application.OnDeactivate := OldDeactivate;
    end;
  finally
    Form2.Release;
  end;
end;

procedure TForm2.FormCreate(Sender: TObject);
begin
  KeyPreview := TRUE;
end;

procedure TForm2.FormKeyDown(Sender: TObject; var Key: Word;
  Shift: TShiftState);
begin
  if Key = VK_ESCAPE then
    Visible := FALSE;
end;

procedure TForm2.FormMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
var
  ScreenPos: TPoint;
begin
  ScreenPos := ClientToScreen(Point(X, Y));
  if (ScreenPos.X < Left) or (ScreenPos.Y < Top)
    or (ScreenPos.X > Left + Width) or (ScreenPos.Y > Top + Height)
  then begin
    Visible := FALSE;
  end;
end;

procedure TForm2.FormDeactivate(Sender: TObject);
begin
  Visible := FALSE;
end;