The MFC ComboBox dropdown button is missing after using SetDroppedWidth - windows

This is an Windows MFC programming issue.
I have a derived CComboBox which implement its own item draw and measurement. I did a little enhancement that the drop down list width is adjustable based on the list content.
I use SetDroppedWidth in OnDropDown message handler to do it.
After I insert strings and click the combo box, the selected string content seized all static/edit area, and drop down button is missing.
I could see the width of the item, which has item ID -1, is changed/reset to the new dropped width in ItemDraw method. I don't think this is the right behavior. I want the new dropped width only take effect on list items, item ID of which is not less than 0.
Any idea?

Try to use this.
In your OnDropDown handler Call CComboBox::GetComboBoxInfo. It will return you the pointer of COMBOBOXINFO structure. This structure among the others contains the HWND of the dropdown listbox hwndList. Use MoveWindow() API on this hwndList directly and see if it works
If that does not work, try posting the CB_SETDROPPEDWIDTH message. As you know, SetDroppedWidth is just a wrapper for CB_SETDROPPEDWIDTH message. It is implemented as a SendMessage call. Try this one:
::PostMessage(m_myComboBox.GetSafeHwnd(), CB_SETDROPPEDWIDTH, nWidth, 0);

Related

How do I handle a message from a user generated combobox in my main window?

I've created a combobox manually in my main window using CreateWindow(). Because of this it has no ID associated with it only the handle returned by CreateWindow(). When the user makes a selection from the combobox list and the combobox throws a message, how do I handle that in the WinProc WM_COMMAND code since there is no ID associated with the combobox? As far as I can tell, I must know the combobox ID to handle the message. This is especially problematic once I have more than one combobox in the main window. Surely there is something I am missing and there is a simple answer.
Okay. So what Igor Tandetnik stated is the answer.
It does have an ID - whatever you passed for hMenu parameter of CreateWindow...
This is also discussed in the following link.
What is winapi HMENU and how do i use it?
From the above link:
HMENU is a handle to a menu, e.g. as created by LoadMenu (which creates a menu from a specification in a resource).
But, the CreateWindow function re-uses the same argument for two different purposes. With a top-level window it's a menu handle, but with a child window it's the child window id, which should be in 16-bit integer range...
When creating a child window, just cast the id to HMENU.

MFC: How do you get CMFCToolBarComboBoxButton to show on a CMFCToolBar?

Something I thought would be easy I can't get to work. How do I get a ComboBox to show on the CMFCToolBar? Here's what I have done that doesn't work (meaning it just shows the original placeholder button with the circle (grayed out)).
1 - I added a button to the toolbar in resource editor giving it the id ID_EDIT_FIND_COMBO (I also put a circle in it just to know it's in use).
2- in CMainFrame I added ON_REGISTERED_MESSAGE(AFX_WM_RESETTOOLBAR, OnToolbarReset) to message map and the OnToolbarReset() function below:
afx_msg LRESULT CMainFrame::OnToolbarReset(WPARAM wparm, LPARAM )
{
UINT uitoolbarid = (UINT) wparm;
if (uitoolbarid == IDR_MAINFRAME) {
CMFCToolBarComboBoxButton btncombo(ID_EDIT_FIND_COMBO, GetCmdMgr()->GetCmdImage(ID_EDIT_FIND));
m_wndToolBar.ReplaceButton(ID_EDIT_FIND_COMBO, btncombo);
}
return 0;
}
The ReplaceButton() returns 1 saying it replaced it.
What am I missing?
To be clear, here's what MS says to do which is what is done above:
1 - Reserve a dummy resource ID for the button in the parent toolbar resource. For more information about how to create buttons by using the Toolbar Editor in Visual Studio, see the Toolbar Editor article.
2 - Reserve a toolbar image (button icon) for the button in all bitmaps of the parent toolbar.
3 - In the message handler that processes the AFX_WM_RESETTOOLBAR message, do the following steps:
a. Construct the button control by using a CMFCToolbarButton-derived class.
b. Replace the dummy button with the new control by using CMFCToolBar::ReplaceButton. You can construct the button object on the stack, because ReplaceButton copies the button object and maintains the copy.
TIA!!
Here's a sample project where it doesn't work. Just the button on the toolbar, not a combobox. Even took code sample from MS sample.
Sample Project
The answer is that MFC caches the toolbar so if you ever run it without the combo, once you replace the button to use the combo it still doesn't use it. You can make it pick up the change by either going to customize for the toolbars (if you have that option enabled) and choose Reset All, otherwise, you'll find under Computer\HKEY_CURRENT_USER\Software\{NameAsUsedInSetRegistryCall}\{appname}\Workspace all the cache items, of which the various MFCToolBar entries. Delete the key and run app again, then it works. Why they wouldn't make it smart and have a timestamp to know if to automactially update, not sure?

What difference between control's window handle and controlID

I'm learning Win32 assembly. Have some question I search but not suitable result.
Anyone can explain for me What difference between control's window handle and controlID.
They have nothing in common. Every window has a handle, returned by CreateWindowEx(). Such a window can have a few extra properties attached, like a menu handle. The hMenu argument in CreateWindowEx(). If the window doesn't have a menu, a child window won't have one, then you can use that argument to pass an arbitrary other bit of data. It will be assigned to the GWLP_ID property (see GetWindowLongPtr). Also note the GWLP_USERDATA, an extra property that's entirely yours to use as you see fit.
Dialogs take advantage of this, a dialog template that you create in the resource editor gives you a way to number the child controls. With a helper function like GetDlgItem() to get the handle back for a control with a specific number. Which is pretty necessary for dialogs since it is Windows that create the child controls from the dialog template so you don't know the window handles for them yourself.

oddity with edit controls in property sheet

I have a property sheet with several pages. Most of the pages have one or more edit controls.
Most controls are initialized not from the page dialogs but from the dialog that created the property sheet; some however are initialized in the page dialogs and they behave the same.
Everything starts out fine. One can move between the pages. None of the controls have the input focus.
If one clicks on one of the edit controls in a property sheet page establishing input focus one can modify the control. Again all seems in order.
If one then moves to a different property page, the first edit control in that page gets the input focus AND all the text in that control gets selected! This behavior applies to all the pages except one having an edit control with read only style. After that one can move back to other pages and the initial nothing selected no input focus behavior is restored.
All of the pages handle the PSN_QUERYINITIALFOCUS notification and return zero through the SetWindowLong mechanism.
Is this expected behavior?
And why isn't some control given focus initially?
My primary interest here is to somehow kill the selection. I have tried killing the selection with EM_SETSEL in the PSN_SETACTIVE notification to no avail.
The MSDN says the following under PSN_QUERYINITIALFOCUS "Otherwise, return zero and focus will go to the default control." How do I go about setting a control as default?
I find the the actions described above bizarre! I would still like to know
if they are normal.
why no control receives the focus initially.
I was able to kill the selection by adding code to the property sheet pages to handle the WM_COMMAND/EN_SETFOCUS message for any edit controls. I do not know if other controls
send EN_SETFOCUS messages.
case EN_SETFOCUS:
{
char cn[16];
HWND H = (HWND) lParam;
GetClassName (H, cn, 15);
if (strcmp (cn,"Edit") == 0)
{
SendMessage (H, EM_SETSEL, -1, 0);
}
return true;
}
I presume it would be possible to save any selection in an EN_KILLFOCUS handler and restore it
in the EN_SETFOCUS handler but doing so for an unknown number of controls would be tedious.

Determine if a menu is dropped down

Is there a way to determine if a menu is dropped down in the win32 api? Something that could be used like so:
HMENU hMenu = GetMenu(hWnd);
HMENU hSubMenu = GetSubMenu(hMenu);
// Is hSubMenu dropped down?
I'm not sure of a way to operate specifically on HMENUs to see if the menu is showing (and a quick scan of the platform SDK docs didn't turn up anything specific), but you might be able to use the GetMenuItemInfo function to get a MENUITEMINFO struct relating to the menu item which owns the dropdown. If the fState member has MFS_HILITE set, that should indicate that the item is selected and the sub menu is most likely open. Correctness isn't guaranteed on my part but it's worth experimenting with.
Another possible option would be using FindWindow with the class "#32768" to find the hWnd of whatever menus may be open, and sending the MN_GETHMENU message to whichever windows you find to retrieve the HMENU and compare it to the expected value from GetSubMenu.

Resources