I like to use an on anywhere (keyboard) event to identify the widget (get widget handle) even it's not enabled/sensitive.
Is this possible with (old) ABL forms (it's possible with .Net)
Use ClientToScreen.
The coordinates of a widget are relative to frame upper left corner. So, start "scanning" frame widgets you must ClientToScreen frame upper left corner, passing frame hwnd and loading in point structure 0 for x and y. Then ClientToScreen function returns frame 0,0 in screen coordinates. After that screen coordinates of a widget are:
Top left: frame-x-screen + widget:x, frame-y-screen + widget:y;
Bottom right: top-left-x + widget:width-pixels; top-left-y + widget:height-pixels
I'm not sure what you mean. If a widget is insensitive it can't take focus and can't get keyboard events. Can you give a simple .NET example to demonstrate what you're asking for?
Now I see that the question is about the mouse, not the keyboard. I still would like more clarification about what you need to do. Do you want an event to fire when the mouse is over a widget or do you want to determine which widget is under the mouse? Or something else? Again, a .NET example that shows how it works there will be helpful to clarify the question.
Those samples would be fairly easy translatable into ABL:
stackoverflow.com/.../is-there-a-quick-way-to-get-the-control-thats-under-the-mouse
But how to get that running for old pure ABL forms (no .net controls)?
What is the ABL function to get the mouse position and find out whether it's in the bounds of a "inner" ABL widget (not the frame)
Matt,
"do you want to determine which widget is under the mouse?
Yes - that's what I like to know when I press like a F-key with an registered anywhere event.
I'll try to create an example of how to do this today. I have to warn you that it might not be perfect. The Windows functions that tell you which window is under a certain point don't always return what you'd expect.
That would be very nice, in the moment I only need a routine to iterate through all widget of the current window.
I found an example in KB but there it looks like I get all widgets in all windows and not only the current window.
How to prevent to iterate through every widget in the abl session?
hObject = current-window no-error.
RUN WalkChildTree (hObject).
PROCEDURE WalkChildTree:
DEFINE INPUT PARAMETER phObject AS HANDLE NO-UNDO.
DEFINE VARIABLE hNextObject AS HANDLE NO-UNDO.
/* Drill down child object chain first */
hNextObject = phObject:FIRST-CHILD NO-ERROR.
IF VALID-HANDLE (hNextObject)
THEN RUN WalkChildTree (hNextObject).
/* Check for siblings and their children.
*/
hNextObject = phObject:NEXT-SIBLING NO-ERROR.
IF VALID-HANDLE (hNextObject) THEN
RUN WalkChildTree (hNextObject).
/* This object does not have any children or siblings, or the children or
siblings have already been processed in the recursive call. Process
object information now.
*/
MESSAGE phObject:name phObject:screen-value
VIEW-AS ALERT-BOX INFO BUTTONS OK.*/
end.
That code walks through every widget in the widget tree. If you only want to walk through the children of the current window, pass CURRENT-WINDOW:FIRST-CHILD to procedure WalkChildTree:
RUN WalkChildTree(CURRENT-WINDOW:FIRST-CHILD).
Thanks, I think I need a course about widgets list childs/sibling.
With GetCursorPos and ScreenToClient I got the first positive result-
It sounds like you're moving ahead pretty well with this. I don't think you need an example if you've got GetCursorPos and ScreenToClient working. You may also want to look at ChildWindowFromPoint.
Yes, looks good for the first try, I have to check now dual screens and the functions are not safe for right to left configurations. (but I think we don't use this)
I hit a bug during my tests, the (external) debugger didn't starts/visible at the first call of these statements:
debugger:initiate().
debugger:set-break().
Hi Matt,
in general it's working.
With WalkingChild I get now every widget from the active-window.
This works with the most windows but not with all.
In some windows the coordinates are different than fetched with GetCursorPos and recalculated with ScreenToClient.
The pointer is on 228 where the upper left corner of the widget is, but the widget has 174 as Y value.
So I get the values being ~ 50 pixels above the visible widget.
The windows has many frames (visible and not visible)
The first frame at the top is o.k. and the one at the bottom.
The second with the offset, below the first once seems to have as offset the height of the first one above.
Other windows has many frames too but not this effect.
What can be the cause of the offset between the calculated mouse position and the widget position?
ScreenToClient converts screen coordinates to client coordinates relative to a the window you pass as the first parameter. A widget's X and Y attributes are always relative to the frame which contains the widget. Are you calling ScreenToClient for each frame as you walk through the widgets?
Use ClientToScreen.
The coordinates of a widget are relative to frame upper left corner. So, start "scanning" frame widgets you must ClientToScreen frame upper left corner, passing frame hwnd and loading in point structure 0 for x and y. Then ClientToScreen function returns frame 0,0 in screen coordinates. After that screen coordinates of a widget are:
Top left: frame-x-screen + widget:x, frame-y-screen + widget:y;
Bottom right: top-left-x + widget:width-pixels; top-left-y + widget:height-pixels
The next step would be to get the value from a cell of a browse widget ...