Sign in to follow this  
Followers 0
Ting

Help: The Z-order of the ownerdrawn button and the normal button

10 posts in this topic

#1 ·  Posted (edited)

Hi, dear all,

I'm trying to make a GUI with different draggable controls. When you double-click each control, it will expand to show more.

The problem I met is how to control the z-order correctly for different type controls.

In the following attached au3 file, you will see there are two detailed problems.

1. two ownerdrawn buttons are overlapping. The lately created one is shown above the previous one.

However, if you click and drag the top one, the one behind it will receive the mouse event and follow the move.

In my code you can see it's a mess because I tried many different methods to make the top control response the mouse event

and then commented them out:(

2. another problem is the normal button (not ownerdrawn) seems always pop to the top when I hover the mouse over

another ownerdrawn button above it.

After the normal button get to the top, it doesn't get the focus even. (because no mouse click yet) How can I prevent this.

In one sentence, I want to implement

Only the top-most control can be dragged and response other mouse events. The controls which are not top-most can be brought

to top ONLY when I click its VISIBLE region. (some part may be clipped by the top-most or upper ones)

In fact I also saw the similar question in some VC++ forum. It seems no good answer.

One way I'm thinking is to maintain a z-order list in my script manually, and setwindowpos after each mouse click. But this still

can't solve the normal button problem.

Can any one look into my problem and better give me a workable example if you have good solution. Thanks!

BTW: I'm using the latest AutoIt v3 and WinXP home edition

Ting

test.au3

Edited by Ting

Share this post


Link to post
Share on other sites



No one can help? At least give some explanation PLEASE!

I want to know if you have the same problem on your machine or not?

Share this post


Link to post
Share on other sites

No one can help? At least give some explanation PLEASE!

I want to know if you have the same problem on your machine or not?

I do have the same problem: Win XP Pro & AutoIt 3.2.8.1.

Sorry, no ideas on why... <_<

Share this post


Link to post
Share on other sites

No one can help? At least give some explanation PLEASE!

I want to know if you have the same problem on your machine or not?

I am surpised that $WS_CLIPSIBLINGS doesn't do the job. If you disable the button below the one above then there is no problem, so maybe you could detect if the cursor is outside the top button and if it is enable the bottom one, if it isn't disable the bottom button. That's the best I can think of at the moment.

Something like this in your while loop

for each control

disabled = (mouse over control) and (mouse over higher z-order control)


Serial port communications UDF Includes functions for binary transmission and reception.printing UDF Useful for graphs, forms, labels, reports etc.Add User Call Tips to SciTE for functions in UDFs not included with AutoIt and for your own scripts.Functions with parameters in OnEvent mode and for Hot Keys One function replaces GuiSetOnEvent, GuiCtrlSetOnEvent and HotKeySet.UDF IsConnected2 for notification of status of connected state of many urls or IPs, without slowing the script.

Share this post


Link to post
Share on other sites

Thank you for the replies!

I know I can maintain a z-order list manually in my program. Then according to the z-order list, send the mouse command explicitly to the topmost control.

But it seems ridiculous the problem cannot be solved even the M$ guys have already had some styles prepared for the controls.

I don't know if I will have the same problem if I don't use a button class but some other controls, e.g. derived from a picture or label class.

(Maybe the button class have some special behavior? )

However I'm still looking for the explanation for my problems. Anyone who is familiar with the win32api please help!

Share this post


Link to post
Share on other sites

#6 ·  Posted (edited)

Adding $WS_CLIPSIBLINGS to all your buttons certainly would help to see the problem.

Sometimes what you see isn't necessarily what it really is. If a button gets overdrawn by other button, doesn't mean it's below the second one as far as z-order is concerned, it just means that it gets drawn first, so whatever is drawn later, draws on top of it (but the first is still on top, so when you move mouse into that area, it's the one that gets activated - as illustrated with a normal button in your case #2). Which is what WS_CLIPSIBLINGS is intended to remedy.

Also, in your $GUI_EVENT_PRIMARYDOWN, stuff like this:

WinSetOnTop($rt[4],"",1)

even if it was the right function to use, it wouldn't work, because the param you pass is wrong - control ID as window title, huh?

Try using

DllCall("user32.dll", "int", "BringWindowToTop", 'hwnd', GUICtrlGetHandle($rt[4])) instead.

There's also a matter which I'm not quite sure about - sometimes GUIGetCursorInfo() is reporting wrong control too, so instead of it I'd use something that works correctly:

DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", $nX, "uint", $nY) to get the handle of control under mouse and use that.

Or if you need control ID,

$h = DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", MouseGetPos(0), "uint", MouseGetPos(1))

$id = DllCall("user32.dll", "int", "GetWindowLong", "hwnd", $h[0], "int", -12)

Combining all of these changes will get you what you want, "Only the top-most control can be dragged and response other mouse events. The controls which are not top-most can be brought to top ONLY when I click its VISIBLE region". At least it did for me.

Edited by Siao

"be smart, drink your wine"

Share this post


Link to post
Share on other sites

Adding $WS_CLIPSIBLINGS to all your buttons certainly would help to see the problem.

Sometimes what you see isn't necessarily what it really is. If a button gets overdrawn by other button, doesn't mean it's below the second one as far as z-order is concerned, it just means that it gets drawn first, so whatever is drawn later, draws on top of it (but the first is still on top, so when you move mouse into that area, it's the one that gets activated - as illustrated with a normal button in your case #2). Which is what WS_CLIPSIBLINGS is intended to remedy.

Also, in your $GUI_EVENT_PRIMARYDOWN, stuff like this:

WinSetOnTop($rt[4],"",1)

even if it was the right function to use, it wouldn't work, because the param you pass is wrong - control ID as window title, huh?

Try using

DllCall("user32.dll", "int", "BringWindowToTop", 'hwnd', GUICtrlGetHandle($rt[4])) instead.

There's also a matter which I'm not quite sure about - sometimes GUIGetCursorInfo() is reporting wrong control too, so instead of it I'd use something that works correctly:

DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", $nX, "uint", $nY) to get the handle of control under mouse and use that.

Or if you need control ID,

$h = DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", MouseGetPos(0), "uint", MouseGetPos(1))

$id = DllCall("user32.dll", "int", "GetWindowLong", "hwnd", $h[0], "int", -12)

Combining all of these changes will get you what you want, "Only the top-most control can be dragged and response other mouse events. The controls which are not top-most can be brought to top ONLY when I click its VISIBLE region". At least it did for me.

Thank you Siao!

The $WS_CLIPSIBLINGS style did solve the drawing problem. But the main problem in my script is still there. As you said, the GUIGetCursorInfo() sometimes returns 'wrong' controlID. I found this function in fact returns the ID of the lowest z-order control. If there is nothing overlapped, it works fine. But in my case, I think you pointed out a correct way, to get the Control ID by using

$h = DllCall("user32.dll", "hwnd", "WindowFromPoint", "uint", MouseGetPos(0), "uint", MouseGetPos(1))

$id = DllCall("user32.dll", "int", "GetWindowLong", "hwnd", $h[0], "int", -12)

. I tried these, as you may see in the new attached script, I can get correct control handle when I click on overlapping controls, but the 2nd command didn't return a correct Control ID. (It's empty in fact on my machine)

Could you please explain this? or give me a workable example base on my script. I hope this won't take you too much time. (I think everything should be fine if I can get the correct control ID, since the handle is correct.)

test.au3

Share this post


Link to post
Share on other sites

DllCall always returns array.

So the id is $id[0] the same way handle is $h[0]...


"be smart, drink your wine"

Share this post


Link to post
Share on other sites

DllCall always returns array.

So the id is $id[0] the same way handle is $h[0]...

Thank you, Siao! It's just the key.

I think this can be an example to show how to handle the overlapped controls correctly;) At least for newbie like me.

Share this post


Link to post
Share on other sites

It works just like what I want! :)

BTW, the way GUIGetCursorInfo() is using to determine the control ID has to be improved, because people normally need the control ID just below the mouse pointer in case there are some overlapped controls.

It returns

Return Value

Success: returns a five-element array that containing the mouse cursor information:

$array[0] = X coord (horizontal)

$array[1] = Y coord (vertical)

$array[2] = Primary down (1 if pressed, 0 if not pressed)

$array[3] = Secondary down (1 if pressed, 0 if not pressed)

$array[4] = ID of the control that the mouse cursor is hovering over (or 0 if none)

Failure: 0 and set @error to 1

So the 5th element in the returned array must be the topmost control ID. A suggestion to developers. <_<

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now
Sign in to follow this  
Followers 0