Hi,

I need a ComboBox control which doesnt paint a frame around the edit control (CBS_DROPDOWN style). It seems to be a hard job with the standard combobox or comboboxex controls. Before I start to write my own control I would like to ask:

1. Has anyone written a combobox custom control in ASM or C and will share his/her code?
2. Possibly I missed a more simple solution. Can the feature I described above achieved more easily by subclassing the standard combobox?

Thanks in advance for any thoughts about this topic

Japheth
Posted on 2003-11-01 01:31:14 by japheth
I 'll try to solution this problem by subclassing the standard combobox.

Manos.
Posted on 2003-11-01 03:43:50 by Anonymous
Try this:

.data?
hCombo dd ?
oldProc dd ?

.data
szComboClass db "COMBOBOX",0

;------------------------------------------------------------
On WM_CREATE put:

invoke CreateWindowEx,0,addr szComboClass,NULL,\
WS_CHILD or WS_VISIBLE or CBS_DROPDOWN,\
0,0,200,40,hWin,20,hInstance,NULL
mov hCombo,eax

invoke SetWindowLong,hCombo,GWL_WNDPROC,addr NewControlProc
mov oldProc,eax

;--------------------------------------------------
NewControlProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL rc :RECT
LOCAL hdc :DWORD
LOCAL holdPen :DWORD
LOCAL holdBrush :DWORD
.if uMsg==WM_PAINT
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
invoke GetClientRect,hWin,addr rc
invoke InflateRect,addr rc,-1,-1
invoke GetDC,hWin
mov hdc,eax
invoke GetStockObject,NULL_BRUSH
mov holdBrush,eax
invoke SelectObject,hdc,eax
invoke GetStockObject,WHITE_PEN
mov holdPen,eax
invoke SelectObject,hdc,eax
invoke Rectangle,hdc,rc.left,rc.top,rc.right,rc.bottom
invoke SelectObject,hdc,holdBrush
invoke SelectObject,hdc,holdPen
invoke ReleaseDC,hWin,hdc
ret
.endif

invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
ret
NewControlProc endp
;------------------------------------------------
Regards,
Manos.


Note:
It is preferable to create a new Pen with color COLOR_WINDOW
instead of WHITE_PEN.
Also you can set the appropriate width of pen to accomplish this.
Posted on 2003-11-01 04:38:34 by Anonymous
Hi manos,

thanks for your suggestion. Its appreciated.

Regretably its not exactly what I want. Thats because I was unable to express myself clearly. Your code paints a white rectangle around the combobox so it looks less "sunken". But I want to have no "room" around the edit control, in fact placing it at location 0,0 in the combobox's client area. While it is most likely possible to "move" the edit control child window, I see no way to move the "down arrow" at the right side, because it seems not to be a child window of the combobox control.

Japheth
Posted on 2003-11-01 06:28:50 by japheth
Here's an example how it should look l?ke (second column of "clipcontrols" line only :) ):
Posted on 2003-11-01 06:33:20 by japheth
OK japheth.

I 'll try to help you.

Manos.
Posted on 2003-11-01 07:29:18 by Anonymous
Hi japheth.

Try This:

.data?
hCombo dd ?
hEdit dd ?
oldProc dd ?

.data
szComboClass db "COMBOBOX",0
szEditClass db "EDIT",0
fPushed dd 0

;------------------------------------------------------------
On WM_CREATE put:

invoke CreateWindowEx,0,addr szComboClass,NULL,\
WS_CHILD or WS_VISIBLE or CBS_DROPDOWN,\
0,0,200,100,hWin,20,hInstance,NULL
mov hCombo,eax
invoke FindWindowEx,hCombo,NULL,addr szEditClass,NULL
mov hEdit,eax

invoke SetWindowLong,hCombo,GWL_WNDPROC,addr NewControlProc
mov oldProc,eax

;--------------------------------------------------

NewControlProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL rc :RECT
LOCAL rcBtn :RECT
LOCAL rcEdit :RECT
LOCAL hdc :DWORD
LOCAL hPen :DWORD
LOCAL holdPen :DWORD
LOCAL holdBrush :DWORD
.if uMsg==WM_PAINT
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
invoke GetClientRect,hWin,addr rc
invoke GetClientRect,hEdit,addr rcEdit
invoke InflateRect,addr rc,-1,-1
invoke GetDC,hWin
mov hdc,eax
invoke GetStockObject,NULL_BRUSH
invoke SelectObject,hdc,eax
mov holdBrush,eax
invoke GetSysColor,COLOR_WINDOW
invoke CreatePen,PS_SOLID,2,eax
mov hPen,eax
invoke SelectObject,hdc,eax
mov holdPen,eax
invoke Rectangle,hdc,rc.left,rc.top,rc.right,rc.bottom
invoke InflateRect,addr rc,+1,+1
mov eax,rcEdit.right
add eax,3
invoke SetRect,addr rcBtn,eax,rc.top,rc.right,rc.bottom
.if fPushed==TRUE
invoke DrawFrameControl,hdc,addr rcBtn,DFC_SCROLL,DFCS_SCROLLDOWN or DFCS_PUSHED
.else
invoke DrawFrameControl,hdc,addr rcBtn,DFC_SCROLL,DFCS_SCROLLDOWN
.endif
invoke SelectObject,hdc,holdBrush
invoke SelectObject,hdc,holdPen
invoke DeleteObject,hPen
invoke ReleaseDC,hWin,hdc
ret
.elseif uMsg==WM_LBUTTONDOWN
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
mov fPushed,TRUE
invoke InvalidateRect,hWin,NULL,FALSE
ret
.elseif uMsg==WM_LBUTTONUP
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
mov fPushed,FALSE
invoke InvalidateRect,hWin,NULL,FALSE
ret
.endif

invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
ret
NewControlProc endp


Manos.
Posted on 2003-11-01 13:26:57 by Anonymous
Thanks again, manos

Your last code still draws a white frame around the edit control, which I cannot use. But your usage of API "DrawFrameControl" - which I wasnt aware of - is a very good idea and combined with moving the child edit control to location 0,0 this code solves my problem, at least in my little test app.

Heres the modified version which works as it should



NewControlProc proc hWin:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL rc :RECT
LOCAL rcBtn :RECT
LOCAL rcEdit :RECT
LOCAL hdc :DWORD

.if uMsg==WM_PAINT
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
invoke GetDC, hWin
mov hdc, eax
invoke GetClientRect,hWin,addr rc
invoke GetClientRect,hEdit,addr rcEdit
invoke SetRect,addr rcBtn,rcEdit.right,0,rc.right,rc.bottom
.if fPushed==TRUE
invoke DrawFrameControl,hdc,addr rcBtn,DFC_SCROLL,DFCS_SCROLLDOWN or DFCS_PUSHED
.else
invoke DrawFrameControl,hdc,addr rcBtn,DFC_SCROLL,DFCS_SCROLLDOWN
.endif
invoke ReleaseDC, hWin, hdc
ret
.elseif uMsg==WM_LBUTTONDOWN
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
mov fPushed,TRUE
invoke InvalidateRect,hWin,NULL,FALSE
ret
.elseif uMsg==WM_LBUTTONUP
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
mov fPushed,FALSE
invoke InvalidateRect,hWin,NULL,FALSE
ret
if 1
.elseif uMsg==WM_SIZE
invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
invoke GetWindowRect,hEdit,addr rc
invoke ScreenToClient, hWin, addr rc.left
invoke ScreenToClient, hWin, addr rc.right
mov ecx, rc.bottom
add ecx, rc.top
invoke SetWindowPos, hEdit, NULL, 0, 0, rc.right, ecx, SWP_NOZORDER
ret
endif
.endif

invoke CallWindowProc,oldProc,hWin,uMsg,wParam,lParam
ret
NewControlProc endp


And the creation part looks like


invoke CreateWindowEx,0, CStr("combobox"),NULL,\
WS_CHILD or WS_VISIBLE or WS_VSCROLL or CBS_DROPDOWN or CBS_NOINTEGRALHEIGHT,\
12,100,200,80,hWnd,20,g_hInstance,NULL
mov hwndCB,eax

invoke SetWindowLong,hwndCB,GWL_WNDPROC,addr NewControlProc
mov oldProc,eax
invoke FindWindowEx,hwndCB,NULL,CStr("edit"),NULL
mov hEdit,eax

invoke SendMessage, hWnd, WM_GETFONT, 0, 0
invoke SendMessage, hwndCB, WM_SETFONT, eax, 0

ComboBox_SetItemHeight hwndCB, -1, 10


Now all I have to do is to integrate this code in my "editable" listview control (report style).

Japheth
Posted on 2003-11-02 04:01:06 by japheth
Hi japheth,

The simplest way to achieve something similar to what you want is to create a STATIC "container", that will be 4 pixels narrower and 4 pixels shorter than the combobox. Then place the combobox in it (SetParent()) and move it to (-2,-2) position inside the "container". Disadvantage of this solution is that the dropdown list will maintain its original width and will be 2 pixels below the edit control. This however can be changed using some simple piece of code when you don't care for Windows95 users or more complex when you do. I do not have this "simple" version at hand, because I've written the harder one (I do care for Win95 users :) ). I havent tried the "simple" solution yet, but I think the GetComboBoxInfo() function might be of interest here.
Posted on 2003-11-02 04:04:41 by Morris
Hi japheth.

I am building a custom Combo Control with open source code.
In a few time,I'll upload this.

Manos.
Posted on 2003-11-02 04:07:41 by Anonymous
Hi japheth.

You can not use WM_SIZE.
I tried this yesterday,but the system does not use this message.
Also if you expand the Edit Control,you must modificate the text rectangle of the Edit Control,
so that to be symmetrical.
The height of Combo calculate in relation of font.
My code does not draw outside of Combo.Simply,delete the border.

Manos.
Posted on 2003-11-02 05:44:04 by Anonymous
Hi manos,

the code I posted works for XP. You can never be sure, thats right, but WM_SIZE should be "used" on all systems. Will test win9x environment immediately.
Regretably I dont understand "My code does not draw outside of Combo.Simply,delete the border".

Morris, this container idea is good. Moving the listbox 2 pixels higher should be no problem. If the other solution doesnt work on all systems (I care for win95b as well), I will give it a try.

Japheth
Posted on 2003-11-02 07:40:02 by japheth

Hi manos,

the code I posted works for XP. You can never be sure, thats right, but WM_SIZE should be "used" on all systems. Will test win9x environment immediately.
Regretably I dont understand "My code does not draw outside of Combo.Simply,delete the border".

Morris, this container idea is good. Moving the listbox 2 pixels higher should be no problem. If the other solution doesnt work on all systems (I care for win95b as well), I will give it a try.

Japheth


I signify that the system does not use WM_SIZE in this case,but moves the Edit Control in another message.

"My code does not draw outside of Combo.Simply,delete the border".

I signify that my code does not increase the size of Combo.

I had tried to move the Edit Control,but the symmetrical fails.

Manos.
Posted on 2003-11-02 08:40:47 by Anonymous
Hi manos,

I tested the code with XP, win95b and win98. These versions seem to work.

As already mentioned, I need the customized combobox for my "in-place-editable" listview.
Have integrated the code there and it works satisfactory.

Japheth
Posted on 2003-11-02 11:57:24 by japheth