0

i'm not being succefull on drawing my own listbox, heres the code:

LRESULT CALLBACK ListBoxProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
        switch (msg)
        {
               case WM_DRAWITEM:
                    LPDRAWITEMSTRUCT Item;
                    Item = (LPDRAWITEMSTRUCT)lParam;

                if (Item->itemState == ODS_SELECTED)
                {
                    FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0));
                    SetTextColor(Item->hDC, 0x0000FF);
                }
                else
                {
                    SetBkColor(Item->hDC, 0);
                    FillRect(Item->hDC, &Item->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
                    SetTextColor(Item->hDC, 0xFFFFFF);
                }
                LPSTR lpBuff;
                SendMessageA(Item->hwndItem , LB_GETTEXT, Item->itemID, (LPARAM)lpBuff);
                TextOutA(Item->hDC, Item->rcItem.left, Item->rcItem.top, (lpBuff), strlen(lpBuff)-1);
                if (Item->itemState & ODS_FOCUS)
                {
                   DrawFocusRect(Item->hDC, &Item->rcItem);
                }
                return true;
                break;
           case WM_MEASUREITEM:
                break;
           default:
                   DefWindowProcA(hwnd, msg, wParam, lParam);
    }
    return 0;
}

I create the ListBox like this:

lbLogs = CreateWindowExA(0, "LISTBOX", "", WS_VISIBLE + WS_CHILD + WS_BORDER + LBS_HASSTRINGS + LBS_NOINTEGRALHEIGHT + WS_TABSTOP, 15, 115, 515, 180, hwnd, (HMENU)1005, hInstance, NULL);
         //-----------------------------
         SetWindowLong(lbLogs, GWL_WNDPROC, (LONG)&ListBoxProcedure);

Could someone explain to me whats wrong in it? I'm trying to make a listbox that has black bg and red text and when an item gets selected it's text transforms to white.But the listbox just don't add nothing.

Deduplicator
  • 44,692
  • 7
  • 66
  • 118

2 Answers2

5

You are creating a listbox, then installing your own WNDPROC to process messages sent to the listbox. However, an owner-draw listbox sends WM_MEASUREITEM and WM_DRAWITEM messages to its owner, so you need to handle those messages in the parent window's WNDPROC, not the listbox WNDPROC.

Also, even if subclassing was the correct approach (which it is not in this case), your subclass WNDPROC should pass unprocessed messages to the original listbox WNDPROC, not DefWindowProc(). Bypassing the original listbox WNDPROC will most likely cause trouble.

cbranch
  • 4,709
  • 2
  • 27
  • 25
3

You are not specifying any LBS_OWNERDRAW... window style when creating the ListBox. Those messages are also sent to the ListBox's parent window, not the ListBox itself, so you need to catch them in WindowProcedure() instead of ListBoxProcedure(). That is why you are not getting any WM_MEASUREITEM or WM_DRAWITEM messages.

You have to implement the WM_MEASUREITEM message, not discard it like you currently are.

You need to use the | operator instead of the + operator when combining bit-based flags together, like window styles.

You are not using the LB_GETTEXT message or DefWindowProc() function correctly.

Try this instead:

#include <windows.h>
#include <tchar.h>

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

const TCHAR szClassName[] = TEXT("JMBSoftwares");

HWND hMainWnd, btnClose, btnMinimize, txtFileName, btnLoad, btnGo, lbLogs;

WINAPI _tWinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPTSTR lpszArgument,
                    int nFunsterStil)
{
    WNDCLASSEX wincl = {0};
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;
    wincl.style = CS_DBLCLKS;
    wincl.cbSize = sizeof (WNDCLASSEX);
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;
    wincl.cbClsExtra = 0;
    wincl.cbWndExtra = 0;
    wincl.hbrBackground = CreateSolidBrush(0);

    if (!RegisterClassEx (&wincl))
        return 0;

    hMainWnd = CreateWindowEx (
           0,
           szClassName,
           TEXT("JMB Encryptor - V1.0"),
           WS_VISIBLE | WS_DLGFRAME,
           CW_USEDEFAULT,
           CW_USEDEFAULT,
           544,
           375,
           HWND_DESKTOP,
           NULL,
           hThisInstance,
           NULL
           );

    if (!hMainWnd)
        return 0;

    SetWindowLong(hMainWnd, GWL_STYLE, GetWindowLong(hMainWnd, GWL_STYLE) & ~(WS_BORDER | WS_DLGFRAME));
    ShowWindow (hMainWnd, nFunsterStil);

    MSG messages;
    while (GetMessage (&messages, NULL, 0, 0) > 0)
    {
        TranslateMessage(&messages);
        DispatchMessage(&messages);
    }

    return 0;
}

void DrawMyText(HDC hDC, COLORREF Color, DWORD Size, DWORD X, DWORD Y, LPTSTR FontName, LPTSTR Text, BOOL SolidBG)
{
    HFONT hFont = CreateFont(Size, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH, FontName);
    if (!hFont) return;

    HFONT hOldFont = (HFONT) SelectObject(hDC, hFont);

    int iOldBkMode;
    if (!SolidBG)
        iOldBkMode = SetBkMode(hDC, TRANSPARENT);
    else
    {
        SetBkColor(hDC, RGB(0, 0, 0));
        iOldBkMode = SetBkMode(hDC, OPAQUE);
    }

    COLORREF clrOldColor = SetTextColor(hDC, Color);
    TextOut(hDC, X, Y, Text, lstrlen(Text));
    SetTextColor(hDC, clrOldColor);
    SetBkMode(hDC, iOldBkMode);

    SelectObject(hDC, hOldFont);
    DeleteObject(hFont);
}

LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch (message)
    {
        case WM_DESTROY:
            PostQuitMessage (0);
            break;

        case WM_CREATE:
        {
             HINSTANCE hInstance = GetModuleHandle(NULL);
             btnClose = CreateWindowEx(0, TEXT("STATIC"), TEXT("X"), WS_VISIBLE | WS_CHILD | SS_NOTIFY, 530, 1, 10, 15, hwnd, (HMENU)1001, hInstance, NULL);
             btnMinimize = CreateWindowEx(0, TEXT("STATIC"), TEXT("_"), WS_VISIBLE | WS_CHILD | SS_NOTIFY, 515, -3, 10, 18, hwnd, (HMENU)1002, hInstance, NULL);
             txtFileName = CreateWindowEx(0, TEXT("EDIT"), TEXT(""), WS_VISIBLE | WS_CHILD, 75, 40, 280, 15, hwnd, NULL, hInstance, NULL);
             btnLoad = CreateWindowEx(0, TEXT("STATIC"), TEXT("Load a file"), WS_VISIBLE | WS_CHILD | WS_BORDER | SS_NOTIFY | SS_CENTER, 380, 38, 150, 20, hwnd, (HMENU)1003, hInstance, NULL);
             btnGo = CreateWindowEx(0, TEXT("STATIC"), TEXT("Protect my file!"), WS_VISIBLE | WS_CHILD | WS_BORDER | SS_NOTIFY | SS_CENTER, 380, 70, 150, 20, hwnd, (HMENU)1004, hInstance, NULL);
             lbLogs = CreateWindowEx(0, TEXT("LISTBOX"), TEXT(""), WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWVARIABLE | LBS_NOTIFY | WS_TABSTOP, 15, 115, 515, 180, hwnd, (HMENU)1005, hInstance, NULL);
             break;
        }

        case WM_COMMAND:
        {
             switch (wParam)
             {
                    case 1004: //Protect my File!
                    {
                         SendMessage(lbLogs, LB_ADDSTRING, 0, (LPARAM)TEXT("TEST"));
                         break;
                    }
             }
             break;
        }

        case WM_PAINT:
        {
             PAINTSTRUCT ps;
             HDC hDC = BeginPaint(hwnd, &ps);
             HPEN hPen = CreatePen(PS_SOLID, 3, 0x0000FF);
             HPEN hOldPen = (HPEN) SelectObject(hDC, hPen);
             HBRUSH hOldBrush = (HBRUSH) SelectObject(hDC, GetStockObject(NULL_BRUSH));
             Rectangle(hDC, 1, 1, 544, 374);
             DrawMyText(hDC, RGB(0xFF, 0xFF, 0xFF), 15, 1, 3, TEXT("Arial Black"), TEXT("JMB Encryption V1.1"), FALSE);
             MoveToEx(hDC, 1, 20, NULL);
             LineTo(hDC, 544, 20);
             MoveToEx(hDC, 1, 354, NULL);
             LineTo(hDC, 544, 354);
             DrawMyText(hDC, RGB(0xFF, 0xFF, 0xFF), 15, 1, 357, TEXT("Arial Black"), TEXT("Written by João Marcelo Brito - BETA Version"), FALSE);
             DrawMyText(hDC, RGB(0xFF, 0xFF, 0xFF), 12, 10, 42, TEXT("Arial Black"), TEXT("File Name:"), FALSE);
             DrawMyText(hDC, RGB(0xFF, 0xFF, 0xFF), 15, 10, 70, TEXT("Arial Black"), TEXT("You can also use Drag and Drop"), FALSE);
             MoveToEx(hDC, 75, 56, NULL);
             LineTo(hDC, 360, 56);
             Rectangle(hDC, 10, 110, 534, 300);
             DrawMyText(hDC, RGB(0xFF, 0xFF, 0xFF), 12, 25, 105, TEXT("Arial Black"), TEXT("Logs "), TRUE);
             SelectObject(hDC, hOldPen);
             SelectObject(hDC, hOldBrush);
             DeleteObject(hPen);
             EndPaint(hwnd, &ps);
             break;
        }

        case WM_CTLCOLORSTATIC:
        {
             SetBkMode((HDC)wParam, TRANSPARENT);
             SetTextColor((HDC)wParam, 0x0000FF);
             return (LRESULT)GetStockObject(NULL_BRUSH);
        }

        case WM_CTLCOLOREDIT:
        {
             SetBkColor((HDC)wParam, 0);
             SetTextColor((HDC)wParam, 0x0000FF);
             break;
        }

        case WM_DRAWITEM:
        {
            LPDRAWITEMSTRUCT Item = (LPDRAWITEMSTRUCT)lParam;
            if (Item->CtlID == 1005)
            {
                if (Item->itemID != -1)
                {
                    if (Item->itemState == ODS_SELECTED)
                    {
                        FillRect(Item->hDC, &Item->rcItem, CreateSolidBrush(0));
                        SetTextColor(Item->hDC, 0x0000FF);
                    }
                    else
                    {
                        SetBkColor(Item->hDC, 0);
                        FillRect(Item->hDC, &Item->rcItem, (HBRUSH)GetStockObject(BLACK_BRUSH));
                        SetTextColor(Item->hDC, 0xFFFFFF);
                    }

                    int len = SendMessage(Item->hwndItem , LB_GETTEXTLEN, Item->itemID, 0);
                    if (len > 0)
                    {
                        LPTSTR lpBuff = new TCHAR[len+1];
                        len = SendMessage(Item->hwndItem , LB_GETTEXT, Item->itemID, (LPARAM)lpBuff);
                        if (len > 0)
                            TextOut(Item->hDC, Item->rcItem.left, Item->rcItem.top, lpBuff, len);
                        delete[] lpBuff;
                    }
                }

                if (Item->itemState & ODS_FOCUS)
                {
                    DrawFocusRect(Item->hDC, &Item->rcItem);
                }

                return TRUE;
            }
            break;
        }

        case WM_MEASUREITEM:
        {
            MEASUREITEMSTRUCT *mis = (MEASUREITEMSTRUCT*) lParam;
            if (mis->CtlID == 1005)
            {
                mis->itemHeight = 15; // your desired item height, in pixels
                return TRUE;
            }
            break;
        }

        default:
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I tryied now lbLogs = CreateWindowExA(0, "LISTBOX", "", WS_VISIBLE | WS_CHILD | WS_BORDER | LBS_HASSTRINGS | LBS_NOINTEGRALHEIGHT | LBS_OWNERDRAWFIXED | WS_TABSTOP, 15, 115, 515, 180, hwnd, (HMENU)1005, hInstance, NULL); and it still don´t work – João Marcelo Brito Aug 08 '12 at 19:04
  • Still nothing, heres the link of the hole source to you see if its some erros outside this function: [link](http://paste.ubuntu.com/1136734/) – João Marcelo Brito Aug 08 '12 at 19:14
  • That code is not adding any items to the ListBox, so there is nothing to owner-draw. And you did not update your other calls to CreateWindowEx() to use `|` instead of `+`. – Remy Lebeau Aug 08 '12 at 19:52
  • They are working with +, but yeah i'm adding a item at line 150 – João Marcelo Brito Aug 08 '12 at 19:55
  • You are trying to catch the `WM_DRAWITEM` and `WM_MEASUREITEM` messages in `ListBoxProcedure()`, but they are actually sent to `WindowProcedure()` instead. That is because those messages are sent to the ListBox's parent window, not to the ListBox itself. There are various other problems with the code, including the fact that `LB_ADDSTRING` is failing to add items. I am looking at the code to figure out why. – Remy Lebeau Aug 08 '12 at 20:45
  • 1
    `LB_ADDSTRING` is failing because the `lbLogs` variable is local to the `WM_CREATE` handler, so it is invalid inside the `WM_COMMAND` handler. You need to make it a global variable instead so it can persist across multiple calls to `WindowProcedure()`. Once I made those changes, it started working. – Remy Lebeau Aug 08 '12 at 20:51