How do I place a toolbar inside an edit control?
My original goal was to put an X button inside an edit control (I later found out that this edit control itself should be part of a combo box.) I was suggested to use this article as a guide.
To make it look a little "prettier" I decided to use the toolbar for this X button. So I came up with the following code. Here's how the control is initialized inside the ComboBox:
//Initialization
#define EDIT_X_TOOLBAR_BTN_W 10
#define EDIT_X_TOOLBAR_BTN_H 11
//Find edit control handle using GetComboBoxInfo() API
COMBOBOXINFO cbi2 = {0};
cbi2.cbSize = sizeof(cbi2);
GetComboBoxInfo(hComboWnd, &cbi2);
HWND hEditCtrl = cbi2.hwndItem;
HINSTANCE hInst = ::GetModuleHandle(NULL);
//Create toolbar as a child of the edit control
hWndToolbar = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL,
WS_CHILD | WS_VISIBLE |
CCS_NODIVIDER | CCS_NOPARENTALIGN |
CCS_NORESIZE | CCS_NOMOVEY | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT,
0, 0, 0, 0,
hEditCtrl,
(HMENU)ID_CMD_EDIT_X_TOOLBAR, hInst, 0);
::SendMessage(hWndToolbar, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0);
::SendMessage(hWndToolbar, TB_SETBITMAPSIZE, 0, MAKELONG(EDIT_X_TOOLBAR_BTN_W, EDIT_X_TOOLBAR_BTN_H));
::SendMessage(hWndToolbar, TB_SETBUTTONSIZE, 0, MAKELONG(EDIT_X_TOOLBAR_BTN_W, EDIT_X_TOOLBAR_BTN_H));
//Load bitmap
TBADDBITMAP tbab = {0};
tbab.hInst = hInst;
tbab.nID = IDB_BITMAP_TOOLBAR_X;
VERIFY(::SendMessage(hWndToolbar, TB_ADDBITMAP, 1, (LPARAM)&tbab) != -1);
TBBUTTON tbbs[1] = {0};
tbbs[0].iBitmap = 0;
tbbs[0].idCommand = CMD_EDIT_X_TOOLBAR_CLOSE;
tbbs[0].fsState = TBSTATE_ENABLED;
tbbs[0].fsStyle = TBSTYLE_BUTTON;
tbbs[0].iString = -1;
VERIFY(::SendMessage(hWndToolbar, TB_ADDBUTTONS, SIZEOF(tbbs), (LPARAM)tbbs));
//Subclass edit control
oldProc = (WNDPROC)::SetWindowLong(hEditCtrl, GWL_WNDPROC, (LONG)wndProcEditCtrl);
//And redraw the edit control
::SetWindowPos(hEditCtrl, NULL, 0, 0, 0, 0,
SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER);
And this is the subclass proc window for the edit control:
CRect rcToolbar;
LRESULT CALLBACK wndProcEditCtrl(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCCALCSIZE:
{
if(wParam)
{
//First let edit box process it
::CallWindowProc(oldProc, hWnd, msg, wParam, lParam);
RECT* pRc = (RECT*)lParam;
//Define toolbar size & move it
int nTB_w = pRc->bottom - pRc->top;
int nTB_h = nTB_w;
//Adjust the edit client area
pRc->right -= nTB_w;
//Set toolbar rect
rcToolbar.SetRect(pRc->right, pRc->top, pRc->right + nTB_w, pRc->top + nTB_h);
//And move the toolbar
::MoveWindow(hWndToolbar, pRc->right, pRc->top, nTB_w, nTB_h, TRUE);
return 0;
}
}
break;
case WM_NCHITTEST:
{
POINT pnt;
pnt.x = GET_X_LPARAM(lParam);
pnt.y = GET_Y_LPARAM(lParam);
if(::ScreenToClient(hWnd, &pnt))
{
if(rcToolbar.PtInRect(pnt))
{
return HTBORDER;
}
}
}
break;
}
return ::CallWindowProc(oldProc, hWnd, msg, wParam, lParam);
}
The problem is that I can see that the toolbar is created (via Spy ++), but it remains inactive and I cannot see my button (all I get is the gray rectangle on the right):
To make sure that I can create the toolbar myself, if I change the parent window from the edit control (i.e. hEditCtrl
) to the main dialog, it shows up (in the wrong place) and responds just fine. So I came to the conclusion that I must block some messages in my subclass. The question is which ones?
Any idea what I'm missing here?
source to share
No one has answered this question yet
See similar questions:
or similar: