在 OnMouseEnter 中创建和销毁表单; Delphi 中的 OnMouseLeave 事件

发布于 2024-09-30 09:53:58 字数 2723 浏览 4 评论 0原文

抱歉,如果之前已经提出过这样的问题,但我现在没有时间挖掘 stackoverflow db ...

所以,我有这段代码:

procedure TForm1.GraphPrevBtnMouseEnter(Sender: TObject);
var frm_PrevBtn : TForm;
begin
  GraphPrevBtn.Width := 75;
  if z = 0 then begin
    frm_PrevBtn := TForm.Create(nil);
    with frm_PrevBtn do begin
      Name := 'frm_PrevBtn';
      BorderStyle := bsNone;
      Position := poDesigned;
      Top := Form1.Top + GraphprevBtn.Top + (form1.Height - Form1.ClientHeight) - 3;
      Left := Form1.Left + GraphprevBtn.Left + 3;
      Width := GraphprevBtn.Width; Height := GraphprevBtn.Height; transparentColor := True; TransparentColorValue := clbtnFace;
      Show;
    end;
    GraphPrevBtn.Parent := frm_PrevBtn;
    if GetLastError = 0 then z := frm_prevBtn.GetHashCode;
  end;
end;

procedure TForm1.GraphPrevBtnMouseLeave(Sender: TObject);
    var frm_PrevBtn_H : THandle;
    begin
    // if form is created then- if mouse is under button then- if z = formshashcode ( form is on creatin stage )
      if not (FindVCLWindow(Mouse.CursorPos) = GraphPrevBtn) and ((FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm).Visible = True) and (GraphPrevBtn.Parent = FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm) then begin // if mouse is not under graphprevBtn
        ShowMessage(FindVCLWindow(Mouse.CursorPos).Name); // 
        if z = 112                                                       // then if form is created
        then begin
            GraphPrevBtn.Parent := Form1;
            GraphPrevBtn.bringtoFront;
            GraphPrevBtn.Top := 29; GraphPrevBtn.Left := 226;
            (FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm).Free;
            if GetLastError = 0 then z := 0;
          end;
      end;
   end;

所以,我的愿望如下: 当我用鼠标输入这个 GraphPrevBtn 时,就会创建表单。至于创建,焦点从控制转向新的形式。由于焦点位于新表单,因此会触发 OnMouseLeave 事件。当事件被触发时,它应该破坏表单,但是仅当用户(NOT主动控制/焦点)实际上通过鼠标离开控制权。

现在发生的情况是,要么新表单根本没有被销毁,要么两个事件都进入无限循环(*frm_PrevBtn* 一次又一次地创建和销毁......) 。

最好的解决方案是什么?

我的想法是获取新的表单矩形并在鼠标位于该矩形内时进行检查。如果是,则执行允许 OnMouseLeave 事件,否则断开它......它会起作用吗?

我尝试了这些示例:

  1. http://delphi.about .com/od/windowsshellapi/a/get-active-ctrl.htm
  2. http://delphi.about.com/od/delphitips2010/qt/is-some-delphi-tcontrol-under-the-mouse.htm

    • 不走运。问题出在哪里……?

备注:global var z : byte;

PS 感谢您的反对票...将来使用此网站的巨大动力...

Sorry if there is already made such question earlier, but I have no time at the moment to dig in stackoverflow db ...

So, I have this code:

procedure TForm1.GraphPrevBtnMouseEnter(Sender: TObject);
var frm_PrevBtn : TForm;
begin
  GraphPrevBtn.Width := 75;
  if z = 0 then begin
    frm_PrevBtn := TForm.Create(nil);
    with frm_PrevBtn do begin
      Name := 'frm_PrevBtn';
      BorderStyle := bsNone;
      Position := poDesigned;
      Top := Form1.Top + GraphprevBtn.Top + (form1.Height - Form1.ClientHeight) - 3;
      Left := Form1.Left + GraphprevBtn.Left + 3;
      Width := GraphprevBtn.Width; Height := GraphprevBtn.Height; transparentColor := True; TransparentColorValue := clbtnFace;
      Show;
    end;
    GraphPrevBtn.Parent := frm_PrevBtn;
    if GetLastError = 0 then z := frm_prevBtn.GetHashCode;
  end;
end;

procedure TForm1.GraphPrevBtnMouseLeave(Sender: TObject);
    var frm_PrevBtn_H : THandle;
    begin
    // if form is created then- if mouse is under button then- if z = formshashcode ( form is on creatin stage )
      if not (FindVCLWindow(Mouse.CursorPos) = GraphPrevBtn) and ((FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm).Visible = True) and (GraphPrevBtn.Parent = FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm) then begin // if mouse is not under graphprevBtn
        ShowMessage(FindVCLWindow(Mouse.CursorPos).Name); // 
        if z = 112                                                       // then if form is created
        then begin
            GraphPrevBtn.Parent := Form1;
            GraphPrevBtn.bringtoFront;
            GraphPrevBtn.Top := 29; GraphPrevBtn.Left := 226;
            (FindControl(FindWindow('TForm','frm_PrevBtn')) as TForm).Free;
            if GetLastError = 0 then z := 0;
          end;
      end;
   end;

So, my wish is the following:
When I enter this GraphPrevBtn with mouse, form is created. As for is created, the focus goes from Control to new form. As focus is to new form, the OnMouseLeave event is fired. As event is fired, it should destroy the form, BUT ONLY IF user ( NOT active control / focus ) actually leaves control by mouse.

What happens now is that either new forms is not destroyed at all or both events goes infinite loop ( *frm_PrevBtn* is created and destroyed again and again and again...).

What would be best solution?

My idea is to get new forms rect and check whenever mouse is inside this rect. If it is, then perform allow OnMouseLeave event, otherwise deattach it ... would it work?

As much I tried with these samples:

  1. http://delphi.about.com/od/windowsshellapi/a/get-active-ctrl.htm
  2. http://delphi.about.com/od/delphitips2010/qt/is-some-delphi-tcontrol-under-the-mouse.htm

    • No luck. Where is the problem ... ?

Remarks: global var z : byte;

P.S. Thanks for negative votes ... great motivation to use this site in future ...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

感情废物 2024-10-07 09:53:58

鼠标进入“GraphPrevBtn”,您在该按钮上创建一个表单。一旦此表单变得可见,由于鼠标不再位于“GraphPrevBtn”上,因此会触发“OnMouseLeave”。您销毁了新表单,现在鼠标再次位于按钮上,因此“OnMouseEnter”被触发,因此出现无限循环。

作为解决方案,您可以将表单处理代码移至 Form1 的“OnMouseEnter”:

procedure TForm1.FormMouseEnter(Sender: TObject);
begin
  if z = 112
  then begin
    GraphPrevBtn.Parent := Form1;
    [...]

..以及“GetLastError”是什么,它似乎完全无关。如果您要使用它,请在开始操作之前至少通过调用 GetLastErrorSetLastError 将最后一个错误设置为“0”。

Mouse enters on 'GraphPrevBtn', you create a form over the button. As soon as this form becomes visible, since mouse is not anymore over 'GraphPrevBtn', 'OnMouseLeave' is fired. You destroy the new form and now mouse is again on the button so 'OnMouseEnter' is fired, hence the infinite loop.

As a solution, you can move the form disposing code to 'OnMouseEnter' of Form1:

procedure TForm1.FormMouseEnter(Sender: TObject);
begin
  if z = 112
  then begin
    GraphPrevBtn.Parent := Form1;
    [...]

.. and what's with the 'GetLastError', it seems fully irrelevant. If you're going to use it, at least set last error to '0' by calling GetLastError or SetLastErrorbefore beginning your operation.

洛阳烟雨空心柳 2024-10-07 09:53:58

也许类似这样的东西会对您有所帮助:

var
  frm_PrevBtn : TForm = nil;

procedure TForm1.GraphPrevBtnMouseEnter(Sender: TObject); 
var
  P: TPoint;
begin 
  GraphPrevBtn.Width := 75; 
  if frm_PrevBtn = nil then begin 
    P := GraphPrevBtn.ClientOrigin;
    frm_PrevBtn := TForm.Create(nil);
    with frm_PrevBtn do begin
      BorderStyle := bsNone; 
      Position := poDesigned; 
      SetBounds(P.X, P.Y, GraphPrevBtn.Width, GraphPrevBtn.Height);
      TransparentColor := True;
      TransparentColorValue := clBtnFace; 
      GraphPrevBtn.Parent := frm_PrevBtn;
      GraphPrevBtn.Top := 0;
      GraphPrevBtn.Left := 0;
      Show; 
    end;
  end; 
end; 

procedure TForm1.GraphPrevBtnMouseLeave(Sender: TObject); 
begin 
  if (FindVCLWindow(Mouse.CursorPos) <> GraphPrevBtn) and (frm_PrevBtn <> nil) then begin
    GraphPrevBtn.Parent := Self;
    GraphPrevBtn.BringToFront; 
    GraphPrevBtn.Top := 29;
    GraphPrevBtn.Left := 226; 
    FreeAndNil(frm_PrevBtn);
  end; 
end; 

Maybe something more like this will help you:

var
  frm_PrevBtn : TForm = nil;

procedure TForm1.GraphPrevBtnMouseEnter(Sender: TObject); 
var
  P: TPoint;
begin 
  GraphPrevBtn.Width := 75; 
  if frm_PrevBtn = nil then begin 
    P := GraphPrevBtn.ClientOrigin;
    frm_PrevBtn := TForm.Create(nil);
    with frm_PrevBtn do begin
      BorderStyle := bsNone; 
      Position := poDesigned; 
      SetBounds(P.X, P.Y, GraphPrevBtn.Width, GraphPrevBtn.Height);
      TransparentColor := True;
      TransparentColorValue := clBtnFace; 
      GraphPrevBtn.Parent := frm_PrevBtn;
      GraphPrevBtn.Top := 0;
      GraphPrevBtn.Left := 0;
      Show; 
    end;
  end; 
end; 

procedure TForm1.GraphPrevBtnMouseLeave(Sender: TObject); 
begin 
  if (FindVCLWindow(Mouse.CursorPos) <> GraphPrevBtn) and (frm_PrevBtn <> nil) then begin
    GraphPrevBtn.Parent := Self;
    GraphPrevBtn.BringToFront; 
    GraphPrevBtn.Top := 29;
    GraphPrevBtn.Left := 226; 
    FreeAndNil(frm_PrevBtn);
  end; 
end; 
云胡 2024-10-07 09:53:58

为什么不这样做:

  1. MainForm.OnMouseOver:创建辅助表单。
  2. secondaryForm.OnMouseOver:设置 FLAG_ON_SECONDARY。
  3. secondaryForm.OnMouseLeave:清除 FLAG_ON_SECONDARY。
  4. MainForm.OnMouseLeave:如果不是 FLAG_ON_SECONDARY,则销毁辅助窗体。

如果 secondaryForm.OnMouseOver 在 MainForm.OnMouseLeave 之后触发,这可能不起作用。好吧,想想类似的事情。另一个解决方案是启动一个计时器,如果鼠标既不在 Main 上也不在 secondaryForm 上,该计时器会销毁 secondaryForm 并禁用自身。

Why don't you do it like this:

  1. MainForm.OnMouseOver: Create a secondary form.
  2. SecondaryForm.OnMouseOver: Set FLAG_ON_SECONDARY.
  3. SecondaryForm.OnMouseLeave: Clear FLAG_ON_SECONDARY.
  4. MainForm.OnMouseLeave: if not FLAG_ON_SECONDARY then destroy the secondary form.

This might not work in case SecondaryForm.OnMouseOver fires after MainForm.OnMouseLeave. Well, think of something similar. Another solution is to start a timer which destroys SecondaryForm and disables itself if mouse is neither on Main nor on SecondaryForm.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文