也许我遗漏了一些东西,但至少对于弹出菜单来说这很容易:
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;