如何在 Win32 中创建带有位图的组合框?

发布于 2024-09-05 05:48:54 字数 533 浏览 4 评论 0 原文

我想创建一个像这样的自定义组合框(如在 MS Word 中),

替代文字

是否有任何 Win32 API 调用(我不能使用 MFC)来完成这项工作(如 ChooseColor() 或 ChooseFont())?如果没有,任何人都可以告诉我该怎么做吗?谢谢。

问候,

编辑: 创建自绘对话框!!这是唯一的方法吗? http://msdn.microsoft.com/ en-us/library/bb775794%28VS.85%29.aspx#creating_square_meal

I wanted to create a custom combo box like this (as in MS Word),

alt text

Are there any Win32 API calls (I can't use MFC) to get this job done, (like ChooseColor() or ChooseFont()? If there aren't any, can anyone please tell me how to do this? Thanks you.

Regards,

EDIT:
Creating the Owner-Drawn Dialog Box!! Is this the only way ?
http://msdn.microsoft.com/en-us/library/bb775794%28VS.85%29.aspx#creating_square_meal

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

夜访吸血鬼 2024-09-12 05:48:54

您有一些选择来解决您的问题:

  1. 所有常见控件都支持 WM_SETFONT,因此,如果您找到包含您需要的所有行元素的字体,您可以更改组合框控件的字体并用相应的项目填充项目文本。
  2. ComboBoxEx 控件将图像与文本组合在一起(请参阅http://msdn.microsoft.com/en-us/library/bb775738(VS.85).aspx)。请注意,将选择项目的哪些部分(只需尝试一下)。如果您可以稍微改变一下对组合框控件的要求,您将能够使用它。
  3. 您可以使用所有者绘制组合框。然后你就完全自由了,但是你的代码可能会更长一点,如果你使用非标准的 Windows 颜色模式或非默认主题,你应该更加小心。在这种情况下,我建议您使用函数GetSysColor

您应该自行决定哪种方式最适合您的项目要求。

You have some options to solve your problem:

  1. All common controls supports WM_SETFONT, so if you find a Font which has all line elements which you need, you can change font of the combobox control and fill items with corresponding textes.
  2. There are ComboBoxEx control which combines images with textes (see http://msdn.microsoft.com/en-us/library/bb775738(VS.85).aspx). Be careful, what part of items will be selected (just try it). If you can a little change your requirements to the combobox control you will be able to use this.
  3. You can use owner-draw combo-box. Then you are absolutely free, but your code can be a liitle longer and you should be more carful if you works with non-standard color shema of windows or a non-default theams. I'll recommend you use functions GetSysColor in this case.

You should deceide youself whay way is the best for your project requirements.

柠檬色的秋千 2024-09-12 05:48:54

您可以从 WTL::CComboBox。您必须实现

  • WM_MEASUREITEM / OCM_MEASUREITEM 的消息处理程序来测量组合框项目的大小
  • WM_DRAWITEM / OCM_DRAWITEM 来完成绘图本身。您实际上并不需要位图,您可以简单地使用 GDI 进行绘制。

You can derive from WTL::CComboBox. You'd have to implement the message handlers for

  • WM_MEASUREITEM / OCM_MEASUREITEM to do the size measurements of your combo box items
  • WM_DRAWITEM / OCM_DRAWITEM to do the drawing itself. You don't need bitmaps really, you could simply draw using GDI.
撞了怀 2024-09-12 05:48:54

在 Win32 中,这称为所有者绘制的组合框。在线文档的一个很好的起点是:

http://msdn.microsoft.com/en-us/library/bb775794%28VS.85%29.aspx#creating_owner_drawn

In Win32 this is called a owner-drawn combobox. A good startpoint in the online dicumentation is here:

http://msdn.microsoft.com/en-us/library/bb775794%28VS.85%29.aspx#creating_owner_drawn

苍白女子 2024-09-12 05:48:54

这是所有者绘制的组合框的工作代码,其中包含说明。

// List image Icon Test.cpp : Defines the entry point for the application.
//

// READ ME:
// Create a new c++ desktop application
// Remove all the code from the cpp section and insert all this code.
// Create a dialog in VS editor, which had a list box called IDLIST and a combobox called IDCOMBO
// it will already have ok and cancel buttons these can stay.
// Create 4 bitmaps any size, only 24x24 will be shown and put them in the source project directory,
// eg C:\Users\Pts1\source\repos\List image Icon Test\List image Icon Test
// Rename the bitmaps Black.bmp, Blue.bmp, Red.bmp, Green.bmp and make sure they are of the format bmp not just called bmp.
// or ideally create the bitmaps so that they are 24x24 and all black,blue etc
// add IDB_Bread bitmap to the editor or remove them from the code below as instructed. We can load bitmaps directly from file instead.
// Make sure you change the combobox properties as instructed at the header for the dialog callback procedure.
//
#include "stdafx.h"
#include "List image Icon Test.h"
#include "strsafe.h"

#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#define MAX_LOADSTRING 100

#define ID_BREAD 0
#define ID_DAIRY 1
#define ID_FRUIT 2
#define ID_MEAT  3

#define CX_BITMAP 24
#define CY_BITMAP 24

HBITMAP hbmBread, hbmDairy, hbmMeat, hbmFruit, hbmMask, hbmIcon;

HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

void InitGroupList(HWND hDlg);
void DeleteIconBitmaps(void);
BOOL LoadIconBitmaps(void);
void InitFoodList(HWND hDlg);
INT_PTR CALLBACK FoodDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_LISTIMAGEICONTEST, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow)) return FALSE;

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_LISTIMAGEICONTEST));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LISTIMAGEICONTEST));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_LISTIMAGEICONTEST);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, FoodDlgProc);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}


// Message handler for Square Meal dialog box. Click on Help -> ABout Box to activate this dialog.
// You must set the combo box properties to these for this to work.
//
// !!!!!   The combo box you create for this example uses the CBS_DROPDOWNLIST, CBS_OWNERDRAWFIXED, (optional)CBS_SORT, CBS_HASSTRINGS, WS_VSCROLL, and (optional) WS_TABSTOP styles. !!!!!!
//

INT_PTR CALLBACK FoodDlgProc(HWND hDlg, UINT message, WPARAM wParam,LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    TCHAR achTemp[256];
    HWND hwnd;

    switch (message)
    {
    case WM_INITDIALOG:

        // Call an application-defined function to load bitmap resources.
        if (!LoadIconBitmaps())
        {
            Beep(2000, 250);
            EndDialog(hDlg, -1);
            break;
        }

        // Initialize the food groups combo box and select the first item.
        InitGroupList(hDlg);
        SendDlgItemMessage(hDlg, IDCOMBO, CB_SETCURSEL, 0, 0);

        // Initialize the food list box and select the first item.
        InitFoodList(hDlg);
        SendDlgItemMessage(hDlg, IDLIST, LB_SETCURSEL, 0, 0);

        return (INT_PTR)TRUE;

    case WM_MEASUREITEM:
    {
        // Set the height of the items in the food groups combo box.
        LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam;

        if (lpmis->itemHeight < CY_BITMAP + 2) lpmis->itemHeight = CY_BITMAP + 2; 

    }
    break;

    case WM_DRAWITEM:
    {
        COLORREF clrBackground;
        COLORREF clrForeground;
        TEXTMETRIC tm;
        int x;
        int y;
        HRESULT hr;
        size_t cch;

        LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;

        if (lpdis->itemID == -1) // Empty item)
            break;

        // Get the food icon from the item data.
        hbmIcon = (HBITMAP)lpdis->itemData;

        // The colors depend on whether the item is selected.
        clrForeground = SetTextColor(lpdis->hDC,
            GetSysColor(lpdis->itemState & ODS_SELECTED ?
                COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));

        clrBackground = SetBkColor(lpdis->hDC,
            GetSysColor(lpdis->itemState & ODS_SELECTED ?
                COLOR_HIGHLIGHT : COLOR_WINDOW));

        // Calculate the vertical and horizontal position.
        GetTextMetrics(lpdis->hDC, &tm);
        y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
        x = LOWORD(GetDialogBaseUnits()) / 4;

        // Get and display the text for the list item.
        SendMessage(lpdis->hwndItem, CB_GETLBTEXT,
            lpdis->itemID, (LPARAM)achTemp);


        hr = StringCchLength(achTemp, 256, &cch);
        if (FAILED(hr))
        {
            // TODO: Write error handler.
        }


        ExtTextOut(lpdis->hDC, CX_BITMAP + 2 * x, y,
            ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
            achTemp, (UINT)cch, NULL);

        // Restore the previous colors.
        SetTextColor(lpdis->hDC, clrForeground);
        SetBkColor(lpdis->hDC, clrBackground);

        //  Draw the food icon for the item. 
        HDC hdc = CreateCompatibleDC(lpdis->hDC);
        if (hdc == NULL)
            break;

        SelectObject(hdc, hbmMask);
        BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
            CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCAND);

        SelectObject(hdc, hbmIcon);
        BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
            CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCPAINT);

        DeleteDC(hdc);

        // If the item has the focus, draw the focus rectangle.
        if (lpdis->itemState & ODS_FOCUS) DrawFocusRect(lpdis->hDC, &lpdis->rcItem);


    }
    break;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDCOMBO:
            if (HIWORD(wParam) == CBN_SELENDOK)
            {
                InitFoodList(hDlg);
                SendDlgItemMessage(hDlg, IDLIST,
                    LB_SETCURSEL, 0, 0);
            }
            break;

        case IDLIST:
            if (HIWORD(wParam) != LBN_DBLCLK)
                break;

            // For a double-click, process the OK case. 
        case IDOK:

            // Get the text for the selected list item. 
            hwnd = GetDlgItem(hDlg, IDLIST);

            // Here it is assumed the text can fit into achTemp.
            // If there is doubt, call LB_GETTEXTLENGTH first.
            SendMessage(hwnd, LB_GETTEXT,
                SendMessage(hwnd, LB_GETCURSEL, 0, 0),
                (LPARAM)achTemp);

            // TODO: Do something with the selected text.

            EndDialog(hDlg, 0);
            break;

        case IDCANCEL:
            hwnd = GetDlgItem(hDlg, IDCOMBO);
            if (SendMessage(hwnd, CB_GETDROPPEDSTATE, 0, 0))
                SendMessage(hwnd, CB_SHOWDROPDOWN, FALSE, 0);
            else EndDialog(hDlg, 0);
        }
        break;

    case WM_DESTROY:

        // Call the application-defined function to free the bitmap resources.
        DeleteIconBitmaps();
        break;
    }
    return (INT_PTR)FALSE;
}

// Loads string resources and adds them as items to the drop-down list of
//   the food groups combo box. The bitmap handle of each item's icon is
//   stored as item data for easy access when the item needs to be drawn.
// 
void InitGroupList(HWND hDlg)
{
    TCHAR achTemp[256];
    DWORD dwIndex;

    // Get the handle of the food groups combo box.
    HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);

//LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR)); //originals were strings in editor
////dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)achTemp);
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Bread"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm1);

//LoadString(hInst, IDS_DAIRY, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Dairy"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm2);

//LoadString(hInst, IDS_FRUIT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Meat"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm3);

//LoadString(hInst, IDS_MEAT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Fruit"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm4);

    return;
}

// Fills the food list based on the selected item in the food groups combo box.
void InitFoodList(HWND hDlg)
{
    TCHAR achTemp[256];

    HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);
    HWND hwndFoodList = GetDlgItem(hDlg, IDLIST);

    // Clear the list contents.
    SendMessage(hwndFoodList, LB_RESETCONTENT, 0, 0);

    // Find out which food group is selected.
    int idFoodGroup = SendMessage(hwndGroupsBox, CB_GETCURSEL, 0, 0);

    switch (idFoodGroup)
    {
    case ID_BREAD:
        LoadString(hInst, IDS_OATS, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_WHEAT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_RYE, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);
        break;

    case ID_DAIRY:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    case ID_FRUIT:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    case ID_MEAT:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    default:
        break;
    }

    return;
}

// Loads the food icon bitmaps from the application resources.
//
BOOL LoadIconBitmaps(void)
{   
    hbmBread = (HBITMAP)LoadImageW(hInst, (wchar_t*) L"Blue.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmBread != NULL) hbmDairy = (HBITMAP)LoadImageW(hInst, (wchar_t*) L"Green.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmDairy != NULL) hbmMeat = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Red.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmMeat != NULL) hbmFruit = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Black.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmFruit != NULL) hbmMask = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Black.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //Needs to be a black mask to show other images.

/*
    // original code which still works, you need to put in bitmaps into the editor itself. eg IDB_Bread, IDB_DAIRY, are 48x48 bitmaps in my editor by default.
    hbmBread = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD));
    if (hbmBread != NULL) hbmDairy = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_DAIRY));
    if (hbmDairy != NULL) hbmMeat = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_Green));
    */

    //if (hbmMeat != NULL) hbmFruit = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD)); //Bitmap defined in the editor(resource.h) which calls a Black.bmp file. See VS Bitmap editor.
    //if (hbmFruit != NULL) hbmMask = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD));

    if (hbmMask != NULL)
        return TRUE;


    return FALSE;
}

// Frees the icon bitmps.
//
void DeleteIconBitmaps(void)
{
    FreeResource(reinterpret_cast<HGLOBAL>(hbmBread));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmDairy));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmMeat));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmFruit));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmMask));
}

This is working code of an owner drawn combo-box, instructions within.

// List image Icon Test.cpp : Defines the entry point for the application.
//

// READ ME:
// Create a new c++ desktop application
// Remove all the code from the cpp section and insert all this code.
// Create a dialog in VS editor, which had a list box called IDLIST and a combobox called IDCOMBO
// it will already have ok and cancel buttons these can stay.
// Create 4 bitmaps any size, only 24x24 will be shown and put them in the source project directory,
// eg C:\Users\Pts1\source\repos\List image Icon Test\List image Icon Test
// Rename the bitmaps Black.bmp, Blue.bmp, Red.bmp, Green.bmp and make sure they are of the format bmp not just called bmp.
// or ideally create the bitmaps so that they are 24x24 and all black,blue etc
// add IDB_Bread bitmap to the editor or remove them from the code below as instructed. We can load bitmaps directly from file instead.
// Make sure you change the combobox properties as instructed at the header for the dialog callback procedure.
//
#include "stdafx.h"
#include "List image Icon Test.h"
#include "strsafe.h"

#pragma comment(linker, "\"/manifestdependency:type='Win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")

#define MAX_LOADSTRING 100

#define ID_BREAD 0
#define ID_DAIRY 1
#define ID_FRUIT 2
#define ID_MEAT  3

#define CX_BITMAP 24
#define CY_BITMAP 24

HBITMAP hbmBread, hbmDairy, hbmMeat, hbmFruit, hbmMask, hbmIcon;

HINSTANCE hInst;                                // current instance
WCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
WCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

void InitGroupList(HWND hDlg);
void DeleteIconBitmaps(void);
BOOL LoadIconBitmaps(void);
void InitFoodList(HWND hDlg);
INT_PTR CALLBACK FoodDlgProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam);

int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPWSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.

    // Initialize global strings
    LoadStringW(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadStringW(hInstance, IDC_LISTIMAGEICONTEST, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow)) return FALSE;

    HACCEL hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_LISTIMAGEICONTEST));

    MSG msg;

    // Main message loop:
    while (GetMessage(&msg, nullptr, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}



//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEXW wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_LISTIMAGEICONTEST));
    wcex.hCursor        = LoadCursor(nullptr, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCEW(IDC_LISTIMAGEICONTEST);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassExW(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   hInst = hInstance; // Store instance handle in our global variable

   HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE: Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
    case WM_COMMAND:
        {
            int wmId = LOWORD(wParam);
            // Parse the menu selections:
            switch (wmId)
            {
            case IDM_ABOUT:
                DialogBox(hInst, MAKEINTRESOURCE(IDD_DIALOG1), hWnd, FoodDlgProc);
                break;
            case IDM_EXIT:
                DestroyWindow(hWnd);
                break;
            default:
                return DefWindowProc(hWnd, message, wParam, lParam);
            }
        }
        break;
    case WM_PAINT:
        {
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            // TODO: Add any drawing code that uses hdc here...
            EndPaint(hWnd, &ps);
        }
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}


// Message handler for Square Meal dialog box. Click on Help -> ABout Box to activate this dialog.
// You must set the combo box properties to these for this to work.
//
// !!!!!   The combo box you create for this example uses the CBS_DROPDOWNLIST, CBS_OWNERDRAWFIXED, (optional)CBS_SORT, CBS_HASSTRINGS, WS_VSCROLL, and (optional) WS_TABSTOP styles. !!!!!!
//

INT_PTR CALLBACK FoodDlgProc(HWND hDlg, UINT message, WPARAM wParam,LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    TCHAR achTemp[256];
    HWND hwnd;

    switch (message)
    {
    case WM_INITDIALOG:

        // Call an application-defined function to load bitmap resources.
        if (!LoadIconBitmaps())
        {
            Beep(2000, 250);
            EndDialog(hDlg, -1);
            break;
        }

        // Initialize the food groups combo box and select the first item.
        InitGroupList(hDlg);
        SendDlgItemMessage(hDlg, IDCOMBO, CB_SETCURSEL, 0, 0);

        // Initialize the food list box and select the first item.
        InitFoodList(hDlg);
        SendDlgItemMessage(hDlg, IDLIST, LB_SETCURSEL, 0, 0);

        return (INT_PTR)TRUE;

    case WM_MEASUREITEM:
    {
        // Set the height of the items in the food groups combo box.
        LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam;

        if (lpmis->itemHeight < CY_BITMAP + 2) lpmis->itemHeight = CY_BITMAP + 2; 

    }
    break;

    case WM_DRAWITEM:
    {
        COLORREF clrBackground;
        COLORREF clrForeground;
        TEXTMETRIC tm;
        int x;
        int y;
        HRESULT hr;
        size_t cch;

        LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;

        if (lpdis->itemID == -1) // Empty item)
            break;

        // Get the food icon from the item data.
        hbmIcon = (HBITMAP)lpdis->itemData;

        // The colors depend on whether the item is selected.
        clrForeground = SetTextColor(lpdis->hDC,
            GetSysColor(lpdis->itemState & ODS_SELECTED ?
                COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));

        clrBackground = SetBkColor(lpdis->hDC,
            GetSysColor(lpdis->itemState & ODS_SELECTED ?
                COLOR_HIGHLIGHT : COLOR_WINDOW));

        // Calculate the vertical and horizontal position.
        GetTextMetrics(lpdis->hDC, &tm);
        y = (lpdis->rcItem.bottom + lpdis->rcItem.top - tm.tmHeight) / 2;
        x = LOWORD(GetDialogBaseUnits()) / 4;

        // Get and display the text for the list item.
        SendMessage(lpdis->hwndItem, CB_GETLBTEXT,
            lpdis->itemID, (LPARAM)achTemp);


        hr = StringCchLength(achTemp, 256, &cch);
        if (FAILED(hr))
        {
            // TODO: Write error handler.
        }


        ExtTextOut(lpdis->hDC, CX_BITMAP + 2 * x, y,
            ETO_CLIPPED | ETO_OPAQUE, &lpdis->rcItem,
            achTemp, (UINT)cch, NULL);

        // Restore the previous colors.
        SetTextColor(lpdis->hDC, clrForeground);
        SetBkColor(lpdis->hDC, clrBackground);

        //  Draw the food icon for the item. 
        HDC hdc = CreateCompatibleDC(lpdis->hDC);
        if (hdc == NULL)
            break;

        SelectObject(hdc, hbmMask);
        BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
            CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCAND);

        SelectObject(hdc, hbmIcon);
        BitBlt(lpdis->hDC, x, lpdis->rcItem.top + 1,
            CX_BITMAP, CY_BITMAP, hdc, 0, 0, SRCPAINT);

        DeleteDC(hdc);

        // If the item has the focus, draw the focus rectangle.
        if (lpdis->itemState & ODS_FOCUS) DrawFocusRect(lpdis->hDC, &lpdis->rcItem);


    }
    break;

    case WM_COMMAND:
        switch (LOWORD(wParam))
        {
        case IDCOMBO:
            if (HIWORD(wParam) == CBN_SELENDOK)
            {
                InitFoodList(hDlg);
                SendDlgItemMessage(hDlg, IDLIST,
                    LB_SETCURSEL, 0, 0);
            }
            break;

        case IDLIST:
            if (HIWORD(wParam) != LBN_DBLCLK)
                break;

            // For a double-click, process the OK case. 
        case IDOK:

            // Get the text for the selected list item. 
            hwnd = GetDlgItem(hDlg, IDLIST);

            // Here it is assumed the text can fit into achTemp.
            // If there is doubt, call LB_GETTEXTLENGTH first.
            SendMessage(hwnd, LB_GETTEXT,
                SendMessage(hwnd, LB_GETCURSEL, 0, 0),
                (LPARAM)achTemp);

            // TODO: Do something with the selected text.

            EndDialog(hDlg, 0);
            break;

        case IDCANCEL:
            hwnd = GetDlgItem(hDlg, IDCOMBO);
            if (SendMessage(hwnd, CB_GETDROPPEDSTATE, 0, 0))
                SendMessage(hwnd, CB_SHOWDROPDOWN, FALSE, 0);
            else EndDialog(hDlg, 0);
        }
        break;

    case WM_DESTROY:

        // Call the application-defined function to free the bitmap resources.
        DeleteIconBitmaps();
        break;
    }
    return (INT_PTR)FALSE;
}

// Loads string resources and adds them as items to the drop-down list of
//   the food groups combo box. The bitmap handle of each item's icon is
//   stored as item data for easy access when the item needs to be drawn.
// 
void InitGroupList(HWND hDlg)
{
    TCHAR achTemp[256];
    DWORD dwIndex;

    // Get the handle of the food groups combo box.
    HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);

//LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR)); //originals were strings in editor
////dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)achTemp);
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Bread"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm1);

//LoadString(hInst, IDS_DAIRY, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Dairy"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm2);

//LoadString(hInst, IDS_FRUIT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Meat"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm3);

//LoadString(hInst, IDS_MEAT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
dwIndex = SendMessage(hwndGroupsBox, CB_ADDSTRING, 0, (LPARAM)_T("Fruit"));
SendMessage(hwndGroupsBox, CB_SETITEMDATA, dwIndex, (LPARAM)hbm4);

    return;
}

// Fills the food list based on the selected item in the food groups combo box.
void InitFoodList(HWND hDlg)
{
    TCHAR achTemp[256];

    HWND hwndGroupsBox = GetDlgItem(hDlg, IDCOMBO);
    HWND hwndFoodList = GetDlgItem(hDlg, IDLIST);

    // Clear the list contents.
    SendMessage(hwndFoodList, LB_RESETCONTENT, 0, 0);

    // Find out which food group is selected.
    int idFoodGroup = SendMessage(hwndGroupsBox, CB_GETCURSEL, 0, 0);

    switch (idFoodGroup)
    {
    case ID_BREAD:
        LoadString(hInst, IDS_OATS, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_WHEAT, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_RYE, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);
        break;

    case ID_DAIRY:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    case ID_FRUIT:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    case ID_MEAT:
        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        LoadString(hInst, IDS_BREAD, achTemp, sizeof(achTemp) / sizeof(TCHAR));
        SendMessage(hwndFoodList, LB_ADDSTRING, 0, (LPARAM)achTemp);

        break;

    default:
        break;
    }

    return;
}

// Loads the food icon bitmaps from the application resources.
//
BOOL LoadIconBitmaps(void)
{   
    hbmBread = (HBITMAP)LoadImageW(hInst, (wchar_t*) L"Blue.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmBread != NULL) hbmDairy = (HBITMAP)LoadImageW(hInst, (wchar_t*) L"Green.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmDairy != NULL) hbmMeat = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Red.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmMeat != NULL) hbmFruit = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Black.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //File has to be of format .bmp
    if (hbmFruit != NULL) hbmMask = (HBITMAP)LoadImageW(hInst, (wchar_t*)L"Black.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); //Needs to be a black mask to show other images.

/*
    // original code which still works, you need to put in bitmaps into the editor itself. eg IDB_Bread, IDB_DAIRY, are 48x48 bitmaps in my editor by default.
    hbmBread = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD));
    if (hbmBread != NULL) hbmDairy = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_DAIRY));
    if (hbmDairy != NULL) hbmMeat = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_Green));
    */

    //if (hbmMeat != NULL) hbmFruit = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD)); //Bitmap defined in the editor(resource.h) which calls a Black.bmp file. See VS Bitmap editor.
    //if (hbmFruit != NULL) hbmMask = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_BREAD));

    if (hbmMask != NULL)
        return TRUE;


    return FALSE;
}

// Frees the icon bitmps.
//
void DeleteIconBitmaps(void)
{
    FreeResource(reinterpret_cast<HGLOBAL>(hbmBread));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmDairy));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmMeat));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmFruit));
    FreeResource(reinterpret_cast<HGLOBAL>(hbmMask));
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文