开发者

Forms creation and destroying in OnMouseEnter ; OnMouseLeave events in Delphi

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开发者_JAVA百科.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 ...


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.


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; 


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜