Link to home
Start Free TrialLog in
Avatar of wuxz
wuxz

asked on

Q: How to write a window class to replace the dropdown window of combo box

Hi,

  I want to write a window class to replace the combolbox window of combox, so that in my own combobox control, I can popup this window to act as the dropdown window. But I meet some difficulties:

1. If I use a popup window, when my window appear, the background window become gray.

2. If I use combolbox, I can not know when the user click out of my dropdown window at which time I can close my dropdown window.

3. If I use SetCapture() to trace mouse input, the scroll bar of my dropdown window acts strengly. When you click at the scroll bar, my mouse capture disappears.

4. I have seen some controls which do not use mouse capture at all, but they act well. When I click outside of it, it disappears, without receiving any mouse message. How can they do that?

Can anyone give me any advice?
Thank a lot in advance.

Regards
wu xz
Avatar of dagangwang
dagangwang

Why do you replace the combolbox window? What are you doing? I think that the default combolbox window is almost suitable for  everything. If not, you can change style owner it......
1) The background window becomes grey.
This is because it is getting a WM_NCACTIVATE message with wParam == 0.  It gets this because your popup window becomes the active window for the thread when you bring it to the top of the Z order.  You want your window to be a popup, on top, but not the active window -- the only way to do this is make your window WS_EX_TOPMOST.

2) The two ways to know about a BUTTONDOWN outside of your window are setting capture and hooks.  Capture is preferred because there are other events which should cause you to close the dropdown window.  These other events will send your window a WM_CANCELMODE message which, when passed to DefWindowProc will cause a ReleaseCapture.

3) The scrollbar acts funny when your ComboLBox has capture.  Indeed it does. The scrolling happens when a WM_NCLBUTTONDOWN with HTVSCROLL goes to DefWindowProc.  When a window has capture, windows delivers only WM_LBUTTONDOWN messages.  The real comboLBox gets around this roughly like this:
case WM_LBUTTONDOWN:
// did this hit the scrollbar?
// yes.
ReleaseCapture();
SendMessage(h, WM_NCLBUTTONDOWN)
SetCapture(h);
// End hit the scrollbar

4) When you click outside of the control, on a window which belongs to another thread, you get activation messages which you could use to return to the normal state.  But if you click on you own parent window and you don't have capture, you don't get any messages.  The choices are capture or a hook.

5) You are definitely doing this the hard way.  The Combo box and the ComboLBox work together and talk to each other.  Chances are good that you want to change only some of the ComboLBox behaviour.  The way to do this is to subclass the ComboLBox.  Then you have complete control of it, but you can use the default behaviour when convenient.  To subclass the comboLBox, you can use a hook if you need to subclass it when it is first created.  If you can wait until it's infancy, then an wasier way to subclass it is when you are given a WM_CTLCOLORLISTBOX, the lParam is the hWnd of the listbox.  Then you can call:
pOldProc= SetWindowLong(GWL_WNDPROC, (LONG)YourWndProc);
and in YourWndProc, to get the default behaviour,
CallWindowProc(pOldProc, hWnd, message, wParam, lParam);

If you only want to change the appearance of the items, then an owner draw combo box is for you.


1) The background window becomes grey.
This is because it is getting a WM_NCACTIVATE message with wParam == 0.  It gets this because your popup window becomes the active window for the thread when you bring it to the top of the Z order.  You want your window to be a popup, on top, but not the active window -- the only way to do this is make your window WS_EX_TOPMOST.

2) The two ways to know about a BUTTONDOWN outside of your window are setting capture and hooks.  Capture is preferred because there are other events which should cause you to close the dropdown window.  These other events will send your window a WM_CANCELMODE message which, when passed to DefWindowProc will cause a ReleaseCapture.

3) The scrollbar acts funny when your ComboLBox has capture.  Indeed it does. The scrolling happens when a WM_NCLBUTTONDOWN with HTVSCROLL goes to DefWindowProc.  When a window has capture, windows delivers only WM_LBUTTONDOWN messages.  The real comboLBox gets around this roughly like this:
case WM_LBUTTONDOWN:
// did this hit the scrollbar?
// yes.
ReleaseCapture();
SendMessage(h, WM_NCLBUTTONDOWN)
SetCapture(h);
// End hit the scrollbar

4) When you click outside of the control, on a window which belongs to another thread, you get activation messages which you could use to return to the normal state.  But if you click on you own parent window and you don't have capture, you don't get any messages.  The choices are capture or a hook.

5) You are definitely doing this the hard way.  The Combo box and the ComboLBox work together and talk to each other.  Chances are good that you want to change only some of the ComboLBox behaviour.  The way to do this is to subclass the ComboLBox.  Then you have complete control of it, but you can use the default behaviour when convenient.  To subclass the comboLBox, you can use a hook if you need to subclass it when it is first created.  If you can wait until it's infancy, then an wasier way to subclass it is when you are given a WM_CTLCOLORLISTBOX, the lParam is the hWnd of the listbox.  Then you can call:
pOldProc= SetWindowLong(GWL_WNDPROC, (LONG)YourWndProc);
and in YourWndProc, to get the default behaviour,
CallWindowProc(pOldProc, hWnd, message, wParam, lParam);

If you only want to change the appearance of the items, then an owner draw combo box is for you.


Avatar of wuxz

ASKER

Ok,

Thank you for your answer, but I find that capturing mouse is not a good method. In fact, the DBCombo control in Microsoft DataBind Listbox control(c:\windows\system\dblist32.ocx) does not use mouse capture at all, but it know when to close itself, what technology it uses?

Thank you very much

Regards
wu xz
As I indicated in my previous comment, the other way to know about mouse events outside of your window is to set a hook.  dblist32.ocx does exactly that.
It sets a WH_MOUSE hook when it drops down.  If you want to do the same, see SetWindowsHookEx.
When it gets a LBUTTONDOWN in it's hook, it pops up.

It also uses a scrollbar child control, not a scroll style.

Avatar of wuxz

ASKER

Hi,

Thank you for your answer. You are right, only mouse hook can work.

I already know that mouse hook can work, but I do not like it, it likes waste its talent on petty job. Now, it seems that it is not a "simple job".

BTW, how can you sure that dblist32.ocx use hook?

Thank you very much.

I made a test program, put a dbcombo on it, and ran it using Bounds Checker.  Bounds Checker is a program which can make a log of every API called by an application, and every message processed by the application.
When I looked at the log produced by Bounds Checker, I saw the dblist created, saw the hook get set, and saw the unhook occur when I clicked the mouse.
Bounds Checker is made by NuMega Software (www.numega.com).  Whenever I'm curious how a program implements something, I check it with Bounds Checker.
I find it and SoftIce to be valuable tools.

Avatar of wuxz

ASKER

Thand you very much.

Have you gotten my points? I do not find anywhere let me to accept your answer and give my points to you. If you do not get the deserved point, please tell me.

Thank you again.
ASKER CERTIFIED SOLUTION
Avatar of zyqwert
zyqwert

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial