Mega Code Archive

 
Categories / Delphi / Forms
 

A Hint Window That Follows The Mouse

Title: A Hint Window That Follows The Mouse Question: How to show a hint that follows the mouse and that hides properly... This seems to be the problem of the month. I can see that I'm not the only one who had that problem. What follows here is more an extension to Michael Burton and Mike Tumy's article (Real Time Mouse Coordinates Display) because Mott Adler (Using OnHint for Real-Time Mouse Coordinates) provides a nice work around that has the strength of simplicity. Those two solutions share the same problem : when you have other controls on the form the hint is behaving strangely. Either it is waiting for the cursor to leave the component or it is immediately showing the component hint. The problem is not here, I think that you noticed the fact and that it was not the point in your article. Ok, we can show a hint that follows the mouse. But we have two problems. The first and most important is to hide the hint when the cursor is leaving the form. The second is to hide the hint when the cursor is over a component and act normal again. I don't know if we can handle the first problem with windows 95 or NT 3.5 or less. But windows 98 and NT 4 or greater bring to us a new function called TrackMouseEvent. This is the only way I can see for us to know each time that the cursor left the form. Answer: This is how to use it : evtTrack: tagTRACKMOUSEEVENT; with evtTrack do begin cbSize := sizeOf(tagTRACKMOUSEEVENT); dwFlags := TME_LEAVE; hwndTrack := form1.Handle; dwHoverTime := HOVER_DEFAULT; end; if not isTracking then begin if not TrackMouseEvent(evtTrack) then MessageDlg('Sorry, I' + #39 + 'm not in the mood of tracking' + #13 + #10 + 'your stupid events.', mtError, [mbOK], 0); isTracking := True; end; The TME_LEAVE flag asks windows to post us WM_MOUSELEAVE message. We keep track with the isTracking := True that we have already asked windows. I don't know if it matters. So next time the cursor leaves the form we get the message. We handle it with the following proc : private { Private declarations } procedure MouseLeavesTheForm(var m: TMessage); message WM_MOUSELEAVE; procedure TForm1.MouseLeavesTheForm(var m: TMessage); begin inherited; hwHint.ReleaseHandle; //we release the hint here isTracking := False; m.Result := 1; end; Sorry, but I don't know if I have to call inherited and if I shall tell with m.Result := 1 that I handled the message. Here we are. The first problem is solved. procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var pt: TPoint; sText: string; begin if not isTracking then begin if not TrackMouseEvent(evtTrack) then MessageDlg('Sorry, I' + #39 + 'm not in the mood of tracking' + #13 + #10 + 'your stupid events.', mtError, [mbOK], 0); isTracking := True; end; getCursorPos(pt); sText := Format('%d,%d', [pt.x, pt.y]); hwHint.ActivateHint(Rect(pt.x + 10, pt.y + 10, pt.x + hwHint.Canvas.TextWidth(sText) + 19, pt.y + hwHint.Canvas.TextHeight(sText) + 10), sText); UpdateTracking; end; You may have noticed the UpdateTracking procedure ? This is something I snipped from the method used is speedbuttons to look if the cursor is over the speedbutton. This will help us to release the hint whenever the mouse is not over the nude background but still inside of the form. //check if the cursor is no longer over the background //e.g.. he is over a button or something procedure TForm1.UpdateTracking; var P: TPoint; begin GetCursorPos(P); if not (FindDragTarget(P, True) = Self) then Perform(WM_MOUSELEAVE, 0, 0); end; When the cursor leaves the background we post us a WM_MOUSELEAVE message, the speedbutton is using a CM_MOUSELEAVE. That way the hint is working properly over the other controls. Unfortunately the MSDN help file says : not for windows 95. This is sad because many of you are still using it I suppose. The work around is to use a TTimer, but this is not very clean. Another solution would be to use the SetCapture function to capture mouse events even when the mouse is not over the form.