Search code examples
winapicomboboxstylesruntimedropdown

How doI change combobox's drop down style at runtime?


How can I change the combobox's style drop down style at runtime? I've tried using SetWindowLongPtr() but it neither change the style nor return any error. I'm trying to change like below, from button click. What am missing:

here's the piece of code that deal with it:

assert(SetWindowLongPtr(hwndCombo, GWL_STYLE, WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST));
                 assert(SetWindowPos(hwndCombo,
                    0, 0, 0, 0, 0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW));

here's full code:

#pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
    
#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <assert.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

HINSTANCE g_hinst;
int comboStyle = CBS_SIMPLE;
int createButton = 1;

int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PWSTR lpCmdLine, int nCmdShow) {

    HWND hwnd;
    MSG  msg ;    
    WNDCLASSW wc = {0};
    wc.lpszClassName = L"Application";
    wc.hInstance     = hInstance ;
    wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
    wc.lpfnWndProc   = WndProc ;
    wc.hCursor       = LoadCursor(0,IDC_ARROW);

    g_hinst = hInstance;
  
    RegisterClassW(&wc);
    hwnd = CreateWindowW(wc.lpszClassName, L"Combo box",
                  WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                  100, 100, 270, 170, 0, 0, hInstance, 0);  


    while (GetMessage(&msg, NULL, 0, 0)) {
        DispatchMessage(&msg);
    }

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
        WPARAM wParam, LPARAM lParam) {

    static HWND hwndCombo;
    const wchar_t *items[] = { L"foo", L"baa", L"lol" };
    
    switch(msg)
    {
        case WM_CREATE:
        {
            hwndCombo = CreateWindow(L"Combobox", NULL, 
                WS_CHILD | WS_VISIBLE | comboStyle,
                10, 10, 120, 110, hwnd, NULL, g_hinst, NULL);   

            if(createButton)
            {
                CreateWindow(L"Button", L"Change Style", 
                        WS_CHILD | WS_VISIBLE,
                        150, 10, 90, 25, hwnd, (HMENU) 1, g_hinst, NULL);
            }

            for (int i = 0; i < sizeof(items)/sizeof(items[0]); ++i)
            {
                SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
            }
        }
        break;

        case WM_COMMAND:
             if (HIWORD(wParam) == BN_CLICKED)
             {            
                 //MessageBox(NULL, L"!", NULL, MB_OK);
                 comboStyle = CBS_DROPDOWNLIST;
                 createButton = 0;
                 //InvalidateRect(hwndCombo, NULL, TRUE);
                 //SendMessage(hwnd, WM_CREATE, 0, lParam);
                 assert(SetWindowLongPtr(hwndCombo, GWL_STYLE, WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST));
                 assert(SetWindowPos(hwndCombo,
                    0, 0, 0, 0, 0,
                    SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED | SWP_SHOWWINDOW));
             }
             break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break; 
    }
  
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

Solution

  • Although the document says:

    If you have changed certain window data using SetWindowLong, you must call SetWindowPos for the changes to take effect. Use the following combination for uFlags: SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_FRAMECHANGED.

    But some styles only take effect during window creation and so can not be set by this call.

    If you want to modify the style of static controls at runtime, your best option would be to simply destroy and recreate the control with the new style:

    case WM_COMMAND:
        if (HIWORD(wParam) == BN_CLICKED)
        {
            comboStyle = CBS_DROPDOWNLIST;
            createButton = 0;
            DestroyWindow(hwndCombo);
            hwndCombo = CreateWindow(L"Combobox", NULL,
                WS_CHILD | WS_VISIBLE | comboStyle,
                10, 10, 120, 110, hwnd, NULL, g_hinst, NULL);
            for (int i = 0; i < sizeof(items) / sizeof(items[0]); ++i)
            {
                SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM)items[i]);
            }
        }
        break;
    

    More references: Change Win32 Window Style, SetWindowLong() function doesn't change window style even after calling SetWindowPos()