如何根据所有者绘图组合框中的键入字母选择项目? [英] How do I select item based on typed letters on owner-draw combobox?

查看:58
本文介绍了如何根据所有者绘图组合框中的键入字母选择项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在常规组合框中,您可以跳到以键入的字母开头的项目.例如,如果您有"baa","arch","foo","art" 之类的项目,并输入"a"项目拱"被选中后,您输入"a"再一次,它跳到艺术".如何在所有者绘图组合框中实现此功能?我以为我可以像下面在comobobox的子过程中那样处理 WM_CHAR ,但是我什至无法测试,因为这样设置comobobox的过程失败了:

On a regular combobox, you can jump to items that starts with the typed letter. e.g., if you have items like "baa", "arch", "foo", "art" and type "a" the item "arch" gets selected, you type "a" again then it jumps to "art". How can I implement this on owner-draw combobox? I thought I could handle WM_CHAR like below in the comobobox's subprocedure, however I couldn't even test it, since setting a procedure to the comobobox like that fails:

      HWND hwndEdit = GetWindow(hwndCombo, GW_CHILD);
      assert(hwndEdit != NULL); // fails here
      lpfnEditWndProc = (WNDPROC) SetWindowLongPtr(hwndEdit, GWLP_WNDPROC, (LONG_PTR) SubClassProc);

过程将是这样的:

LRESULT CALLBACK SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{ 
   switch (msg)
   { 
      case WM_CHAR:
      {
        static int prevIndex = 0;
        static wchar_t buffer[2] = {0};

        memset(&buffer, 0, sizeof(buffer));
        buffer[0] = wParam;
        prevIndex = SendMessage(hwndCombo, CB_FINDSTRING, (WPARAM) prevIndex, (LPARAM) buffer);
        SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) prevIndex, 0);
        return 0;
      }
      break;
    }

    return CallWindowProc(lpfnEditWndProc, hwnd, msg, wParam, lParam);
}

这是owner-draw组合框的完整代码:

Here's the full code of owner-draw combobox:

   #pragma comment(lib, "user32.lib")
#pragma comment(lib, "Comctl32.lib")
#pragma comment(lib, "Gdi32.lib")
#pragma comment(lib, "UxTheme.lib")
#pragma comment(lib, "Comdlg32.lib")

#define WIN32_LEAN_AND_MEAN
#define UNICODE
#define _UNICODE

#include <windows.h>
#include <Commctrl.h>
#include <assert.h>
#include <uxtheme.h>
#include <Commdlg.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
void SetDefaultFont(HWND hwnd);
HFONT LoadSystemDefaultFont();
void DrawBorder(HDC hdc, RECT *rect);
void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2);
void freeBrushes();
HBRUSH getBrushAt(int index);
void drawColorRect(HDC dc, RECT *editRect, int colorIndex);
void EnableVisualStyles2(void);
LRESULT CALLBACK SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

HINSTANCE g_hinst;
HFONT hDefaultSystemFont;
HWND hwndCombo;

#define COUNTOF(a) (sizeof(a)/sizeof(a[0]))
#define LIST \
    X(L"Black", RGB(0, 0, 0)) \
    X(L"Red", RGB(255, 0, 0)) \
    X(L"Blue", RGB(0, 0, 255)) \
    X(L"Green", RGB(0, 128, 0)) \
    X(L"Yellow", RGB(255, 255, 0))

#define X(a, b) a,
const wchar_t *items[] = { LIST };
#undef X

#define X(a, b) b,
const int colorCodes[] = { LIST };
#undef X

HBRUSH brushes[COUNTOF(items)];
WNDPROC lpfnEditWndProc;

enum
{
    BTN_A = 20,
    BTN_COMBO,
};

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);
    }
    
    DeleteObject(hDefaultSystemFont);
    freeBrushes();

    return (int) msg.wParam;
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, 
        WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {
        case WM_CREATE:
        {
            hwndCombo = CreateWindow(L"Combobox", NULL, 
                WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
                CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | WS_VSCROLL | WS_HSCROLL,
                10, 10, 100, 110, hwnd, (HMENU) BTN_COMBO, g_hinst, NULL);
            SendMessage(hwndCombo, CB_SETMINVISIBLE, 5, 0);
            SetDefaultFont(hwndCombo);
            COMBOBOXINFO ci = {0};
            ci.cbSize = sizeof(COMBOBOXINFO);
            GetComboBoxInfo(hwndCombo, &ci);
            lpfnEditWndProc = (WNDPROC)SetWindowLongPtr(ci.hwndList, GWLP_WNDPROC, (LONG_PTR)SubClassProc);
            for (int i = 0; i < COUNTOF(items); ++i)
            {
                SendMessage(hwndCombo, CB_ADDSTRING, 0, (LPARAM) items[i]);
            }
        }
        break;

        case WM_DRAWITEM:
        {
              LPDRAWITEMSTRUCT b = (LPDRAWITEMSTRUCT) lParam;
              SetBkMode(b->hDC, TRANSPARENT);

              if(b->itemState & ODS_SELECTED)
              {
                FillRect(b->hDC, &b->rcItem, (HBRUSH) (COLOR_HIGHLIGHT+1));
                SetTextColor(b->hDC, GetSysColor(COLOR_HIGHLIGHTTEXT+1));
              }
              else
              {
                FillRect(b->hDC, &b->rcItem, (HBRUSH) (COLOR_WINDOW+1));
                SetTextColor(b->hDC, GetSysColor(COLOR_WINDOWTEXT+1));
              }

             if(b->itemID != -1)
             {
                drawColorRect(b->hDC, &b->rcItem, b->itemID);
                DrawText(b->hDC, items[b->itemID], -1, &b->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
             }
             
            if(b->itemAction & ODA_FOCUS)
            {
                DrawFocusRect(b->hDC, &b->rcItem);
            }

            return (INT_PTR) TRUE;
        }
        break;

        case WM_DESTROY:
            PostQuitMessage(0);
            break; 
    }

  
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

HFONT LoadSystemDefaultFont()
{
  if(hDefaultSystemFont == NULL) {
    NONCLIENTMETRICS ncm;
    ncm.cbSize = sizeof(NONCLIENTMETRICS);
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0);
    hDefaultSystemFont = CreateFontIndirect(&ncm.lfMessageFont);
  }
  return hDefaultSystemFont;
}


void SetDefaultFont(HWND hwnd)
{
    SendMessage(hwnd, WM_SETFONT, (LPARAM) LoadSystemDefaultFont(), TRUE);
}

void drawColorRect(HDC dc, RECT *editRect, int colorIndex)
{
    assert(colorIndex >= 0 && colorIndex < COUNTOF(brushes));
    assert(editRect != NULL);

    RECT rt = {0};
    rt.left = editRect->left + 2;
    rt.top = editRect->top - 2;
    rt.right = editRect->right / 5;
    rt.bottom = editRect->bottom - 2;
    InflateRect(&rt, -1, -1);
    DrawBorder(dc, &rt);
    //FrameRect(dc, &rt, getBrushAt(0));
    FillRect(dc, &rt, getBrushAt(colorIndex));
}

void DrawLine(HDC hdc, LONG x1, LONG y1, LONG x2, LONG y2)
{
    MoveToEx(hdc, x1, y1, NULL);
    LineTo(hdc, x2, y2);
}
    
void DrawBorder(HDC hdc, RECT *rect)
{
    DrawLine(hdc, rect->left, rect->top, rect->left, rect->bottom);
    DrawLine(hdc, rect->left, rect->top, rect->right, rect->top);
    DrawLine(hdc, rect->right, rect->top, rect->right, rect->bottom);
    DrawLine(hdc, rect->left, rect->bottom, rect->right, rect->bottom);
}

HBRUSH getBrushAt(int index)
{
    assert(index >= 0 && index < COUNTOF(brushes));
    HBRUSH b = brushes[index];
    if(b == NULL) {
        int code = colorCodes[index];
        brushes[index] = CreateSolidBrush(code);
        b = brushes[index];
    }
    return b;
}

void freeBrushes()
{
    for(int i = 0; i < COUNTOF(brushes); ++i){
        DeleteObject(brushes[i]);
        brushes[i] = NULL;
    }
}

void EnableVisualStyles2(void)
{
    TCHAR dir[MAX_PATH] = {0};
    GetSystemDirectory(dir, sizeof(dir) / sizeof(*dir));

    ACTCTX actCtx = {0};
    actCtx.cbSize = sizeof(ACTCTX);
    actCtx.dwFlags =  ACTCTX_FLAG_RESOURCE_NAME_VALID |
                      ACTCTX_FLAG_SET_PROCESS_DEFAULT |
                      ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
    actCtx.lpSource = L"shell32.dll";
    actCtx.lpAssemblyDirectory = dir;
    actCtx.lpResourceName = (LPCTSTR) 124;
    ULONG_PTR cookie = FALSE;
    HANDLE h = CreateActCtx(&actCtx);
    assert(h != INVALID_HANDLE_VALUE);
    ActivateActCtx(h, &cookie);
}

LRESULT CALLBACK SubClassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 
{
 
    switch (msg)
   { 
      case WM_CHAR:
      {
        static int prevIndex = 0;
        static wchar_t buffer[2] = {0};

        buffer[0] = wParam;
        MessageBox(NULL, buffer, L"", MB_OK);

        prevIndex = SendMessage(hwndCombo, CB_FINDSTRING, (WPARAM) prevIndex, (LPARAM) buffer);
        SendMessage(hwndCombo, CB_SETCURSEL, (WPARAM) prevIndex, 0);
        return 0;
      }
      break;
    }

    return CallWindowProc(lpfnEditWndProc, hwnd, msg, wParam, lParam);
}

更新,抱歉,我从所有者绘制组合框之外的其他文件中粘贴了代码示例.正如 @Song Zhu-MSFT 指出的那样,将过程设置为正确,但仍然无法处理WM_CHAR.

UPDDATE sorry, I past the code sample from other file than the owner-draw combobox. As pointed out by @Song Zhu - MSFT, set the procedure to properly but that still doesn't process WM_CHAR.

推荐答案

下拉式COMBOBOX没有EDIT控件.而是有一个下拉列表.

The drop-down COMBOBOX does not have an EDIT control. Instead, it has a drop-down list.

我建议您使用 GetComboBoxInfo 来获取COMBOBOX控件的子窗口.

I recommend you to use GetComboBoxInfo to get the child window of the COMBOBOX control.

尝试将代码修改为:

COMBOBOXINFO ci{};
ci.cbSize = sizeof(COMBOBOXINFO);
GetComboBoxInfo(hwndCombo, &ci);
lpfnEditWndProc = (WNDPROC)SetWindowLongPtr(ci.hwndList, GWLP_WNDPROC, (LONG_PTR)SubClassProc);

当然,您可以使用此代码查看 COMBOBOXINFO hwndItem 返回NULL.您可以根据组合框类型调整需要控制的手柄.

Of course, you can use this code to see that hwndItem of COMBOBOXINFO returns NULL. You can adjust which handle you need to control according to your combobox type.

您的消息循环代码和设置样式错误(需要 CBS_HASSTRINGS ),请参阅:

Your message loop code and setting style are wrong(need CBS_HASSTRINGS), please refer to:

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

......

 hwndCombo = CreateWindow(L"Combobox", NULL, 
                WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST |
                CBS_OWNERDRAWFIXED | CBS_AUTOHSCROLL | WS_VSCROLL | WS_HSCROLL | CBS_HASSTRINGS,
                10, 10, 100, 110, hwnd, (HMENU) BTN_COMBO, g_hinst, NULL);

这篇关于如何根据所有者绘图组合框中的键入字母选择项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆