MouseEnter - MouseLeave Messages

[Home]   [Puzzles & Projects]    [Delphi Techniques]   [Math topics]   [Library]   [Utilities]

 

 

Search

Search WWW

Search DelphiForFun.org

As of October, 2016, Embarcadero is offering a free release of Delphi (Delphi 10.1 Berlin Starter Edition ).     There are a few restrictions, but it is a welcome step toward making more programmers aware of the joys of Delphi.  They do say "Offer may be withdrawn at any time", so don't delay if you want to check it out.  Please use the feedback link to let me know if the link stops working.

 

Support DFF - Shop

 If you shop at Amazon anyway,  consider using this link. 

     

We receive a few cents from each purchase.  Thanks

 


Support DFF - Donate

 If you benefit from the website,  in terms of knowledge, entertainment value, or something otherwise useful, consider making a donation via PayPal  to help defray the costs.  (No PayPal account necessary to donate via credit card.)  Transaction is secure.

Mensa® Daily Puzzlers

For over 15 years Mensa Page-A-Day calendars have provided several puzzles a year for my programming pleasure.  Coding "solvers" is most fun, but many programs also allow user solving, convenient for "fill in the blanks" type.  Below are Amazon  links to the two most recent years.

Mensa® 365 Puzzlers  Calendar 2017

Mensa® 365 Puzzlers Calendar 2018

(Hint: If you can wait, current year calendars are usually on sale in January.)

Contact

Feedback:  Send an e-mail with your comments about this program (or anything else).

Search DelphiForFun.org only

 

 

 

Problem Description

Here is a demonstration of how to process two Delphi mouse messages that are normally ignored - MouseEnter and MouseLeave.       

Background & Techniques

A recent version of Oscilloscope adds a bar chart of the frequencies contained in the input sample.  I wanted to display the current frequency and amplitude values as the user moved the mouse cursor over the chart (a Timage control).  I decided to use a TLabel and show it along side the mouse cursor, updated each time the cursor moved.  If the cursor was not over the image, the label should disappear, but how to know if the cursor left the image?   I decided to use the MouseEnter and MouseLeave messages generated by  the Forms control when the mouse enters or leaves a control.   The message triggers code to set the "visible" property of the information label.

Here's a demo program that illustrates the technique.  It also illustrates how to make an temporary component that has all the advantages of a visual designed without the hassle of making a true component.  

Temporary Components

Special purpose components are easy to generate but a nuisance to install and maintain.  They reduce the portability of programs since any other system must have installed all of the components the program uses.  Here's an alternative.  Drop the root visual component on  the form and resize, move, color, set exits - whatever features will apply to the descendent component.  Then define the descendent component, create it in the FormsCreate procedure and make (or override) an Assign procedure to assign to the new component all of the ancestor control properties we have modified.  (Two special considerations:  The windowed parent control of our visual model is automatically assigned by Delphi, so we must assign the parent property to our new control even though we may not even be aware of its existent to the ancestor.  Also, names of controls must be unique, so if you need to generate a unique name for your control. (For example:   name:='My'+prototype.name;)   

The Message Mechanics

The  VCL unit Controls.Pas defines sixty-some "VCL Control Message"  numbers all prefixed with CM_, including CM_MouseEnter and CM_MouseLeave.   Unit Forms.pas checks during it's idle time processing loop.  Whenever the previous mouse owner changes, it sends a CM_MouseLeave message to the old owner and a CM_MouseEnter message to the new owner.    The ancestor for all VCL components, TControl, has default processing routines,  CMMouseEnter and CMMouseLeave, for these messages which you may override in any descendent control.  If not overridden, the default routines  each check to see if the parent processor has routines and if so, calls them.  So  your enter/leave mouse processing will receive messages only when the mouse "enters from" or "leaves to" a non-child control.     

The Demo

In our current case, I wanted to intercept the mouse messages in a couple of TShape controls.   The definition  for the descendent class looks like this:

TMyShape=class(TShape)
     procedure CMMouseEnter(var Msg: TMessage); message CM_MouseEnter;
     procedure CMMouseLeave(var Msg: TMessage); message CM_MouseLeave;
     procedure assign(proto:TShape);
end;

We have overridden the default handling procedures for these messages.  In the public section of the form, I defined the two shapes:

     Square:TMyShape;
    Circle:TMyShape;

In the FormCreate procedure we'll create the shapes

   Square:=TMyShape.Create(self);
   Square.Assign(Shape1);
   Circle:=TMyShape.Create(self);
   Circle.Assign(Shape2);

You can click the "Browse Source Extract" button below to see the Assign procedure and the rest of the code.

At mouse enter time, a label caption is set to "Cursor is in ..." + the shape name.  At mouse exit time then caption is change to "Cursor is not in any shape" and it is moved to the bottom left corner of the Panel that contains the shapes.    The shape color is also brightened as the mouse enters and dimmed when the mouse leaves each shape.  An OnMouseMove event exit moves the label to follow the cursor as moves across the shape.    

Considerations

A couple of items worth mentioning.  

The program moves a label to the mouse cursor location each time the mouse moves either of the shapes.  My original location for the label was so close to the  mouse cursor location that many, many  CM_MouseLeave & CM_MouseEnter messages were generated as the mouse moved over the label anf then the label moved so the mouse again entered the shape.    Adding an extra 5 pixel buffer between the cursor and the label solved the problem.    

I also wanted to have the effect of a light coming on when the mouse entered the shape by brightening it up.   I accomplished this by defining a "dark blue" for shape1 by setting the blue byte value of the brush.color field to 127.  For the other shape, I defined "dark red" with a red byte value of 127.    With these  definitions I can multiply the color value by 2 when mouse enter is received brighten it and divide the color by 2  when mouse leave is received to darken it again.   Just be aware that this technique will not work in general.  For that we would have to split out the RGB color bytes, adjust them individually, and then reconstruct the color word from the bytes.

Running/Exploring the Program  

bulletBrowse source extract
bulletDownload source

 

 

Original Date: December 7, 2004 

Modified: May 12, 2018

 
  [Feedback]   [Newsletters (subscribe/view)] [About me]
Copyright © 2000-2018, Gary Darby    All rights reserved.