non-rectangular controls on a form - how to detect mouse events

Posted on 2002-06-06
Last Modified: 2010-04-04
I am building an application for viewing entities and relationships, and something that I expected to be trivial has instead been a very interesting problem.

Practically, the application GUI consists of a master form that contains other forms (representing entities) and a custom control that draws a line connecting two forms (representing associations).

The Delphi TControl methods that detect a mouse event are built on the assumption that all controls are rectangular.  On a screen showing a master entity and 50 owned entities with their relationships, I have 50 lines at varous angles extending from the master entity to the owned entities.

The math to detect whether a mouse click is on the line or not is trivial.  What I haven't figured out is how to get the mouse click event past the topmost control in a stack of overlapping rectangles - ie the control asks "Are you inside of me?  No -- let the next guy handle it" without creating an entirely new heirarchy from the TControl level down.

I can clone Borland's code and make the necessary changes (call it TFancyControl in the FancyControls unit if you like), but that seems like a kludge.

I am sure that this has been solved a hundred times, but my strength is in the business process rahter than in the GUI end of things.

Any assistance will be appreciated.

Thanks in advance.
Question by:swift99
  • 4
  • 3

Expert Comment

ID: 7061261
I think it may be done the following way:
obtain the coords of mouse pointer, convert them into coords
of the corresponding (maybe you must travel over all the controls you want to check) control and determine if the point
belong to this control.
LVL 27

Accepted Solution

kretzschmar earned 100 total points
ID: 7061278
get the devexpress forumlibrary (for free) at

just register yourself in the forum there
you may get then a welcome-mail with a download link

in this library is a dfxConnector-component,
(connects two controls with a line)

gussing thats it what you need

meikl ;-)


Author Comment

ID: 7061296
I have traced in the debugger and already determined that none of the available mouse events are fired on the parent form.  They are intercepted by the contained controls first.

This is intended for use in an enterprise environment, so I cannot guarantee that the associative representation control will always be on a form that I have defined.  The logic has to be self contained to the extent that the control will always behave correctly, at least within a Delphi VCL environment.

Hmmm ... Is there maybe a way to kick the mouse event back to the winProc?

The key to the whole thing is this method from the VCL, which (sadly) is private and is not virtual.

function TWinControl.ControlAtPos(const Pos: TPoint; AllowDisabled: Boolean): TControl;
  I: Integer;
  P: TPoint;
  if FControls <> nil then
    for I := FControls.Count - 1 downto 0 do
      Result := FControls[I];
      with Result do
        P := Point(Pos.X - Left, Pos.Y - Top);
        if PtInRect(ClientRect, P) and    // *** This is the line that causes my problem ***
          ((csDesigning in ComponentState) and (Visible or
          not (csNoDesignVisible in ControlStyle)) or
          (Visible and (Enabled or AllowDisabled) and
          (Perform(CM_HITTEST, 0, Longint(PointToSmallPoint(P))) <> 0))) then
  Result := nil;

function TWinControl.IsControlMouseMsg(var Message: TWMMouse): Boolean;
  Control: TControl;
  P: TPoint;
  if GetCapture = Handle then
    Control := nil;
    if (CaptureControl <> nil) and (CaptureControl.Parent = Self) then
      Control := CaptureControl;
  end else
    Control := ControlAtPos(SmallPointToPoint(Message.Pos), False);
  Result := False;
  if Control <> nil then
    P.X := Message.XPos - Control.Left;
    P.Y := Message.YPos - Control.Top;
    Control.Perform(Message.Msg, Message.Keys, Longint(PointToSmallPoint(P)));
    Result := True;  // *** This line means that once a control is recognized there is ***
                             //       no chance of passing the event back to the WndProc for
                             //       someone else to handle.
Courses: Start Training Online With Pros, Today

Brush up on the basics or master the advanced techniques required to earn essential industry certifications, with Courses. Enroll in a course and start learning today. Training topics range from Android App Dev to the Xen Virtualization Platform.


Author Comment

ID: 7061298
meikl: Thanks!  I'll check it out.

Author Comment

ID: 7061306
meikl: Now I feel foolish - we have developers express tools here as a part of our standard setup.  :o(

It's 2:00 in the morning, that's my excuse.   :o)

LVL 27

Expert Comment

ID: 7061313
you should go into your bed and sleep a while,
if i'm awake so long time, then i'm near dead in head ;-)
LVL 27

Expert Comment

ID: 7061319
thanks for the grade,
hope you get it work

meikl ;-)

Author Comment

ID: 7061365
I'd love to get to bed, but I have to wait for this !@#$%^&*() report to print.  It takes 3 hours on a maxed out IBM 9000, and it's three days late.  I'm on call for the first time in this group, and we didn't even know our group owned this program when it blew up.  Since I'm not an MVS COBOL person by inclination, it's been interesting trying to debug and run the program.

The good news is that while it's running I have time to focus on other things.  The bad news is that while it's running I have to stick around so I can check it's output before I go to bed.   :o)

Isn't on-call duty fun?  <insert heavy does of sarcasm>

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
How to convert wav to mp3 in delphi 9 196
find a node in VST 2 68
Delphi: ForceDirectory plain function 7 28
DBGrid or StringGrid ? 6 88
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In this video I am going to show you how to back up and restore Office 365 mailboxes using CodeTwo Backup for Office 365. Learn more about the tool used in this video here: (…
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

816 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

9 Experts available now in Live!

Get 1:1 Help Now