Как я могу исправить ошибку в ListView ?, не могу выбрать какие-либо элементы, когда я инкапсулирую элемент управления - PullRequest
0 голосов
/ 08 октября 2019

Я работаю над приложением менеджера шкафчиков (уже делал это на консоли) на win32api. Первая сборка была в "коде нормального стиля win32" (определения и объявления функций, без объектов). Это был список, чтобы показать элементы и кнопки для взаимодействия с ним. Теперь, эта версия работает как талисман, я заполняю список с помощью LVN_GETDISPINFO уведомляющего сообщения, и у меня есть кнопка разделения, которая обрабатывает также уведомляющее сообщение BCN_DROPDOWN.

После того, как я увидел, что это работает, я хотелчтобы сделать его инкапсулирующим окна и элементы управления, и сделал простые обертки для списка и кнопок управления. Я одинаково обрабатываю те же сообщения (LVN_GETDISPINFO и BCN_DROPDOWN уведомляющие сообщения), но в этом случае просмотр списка кажется отключенным (без изменения цвета), я просто не могу ничего выбрать !. Теперь, если я удаляю сообщение WM_NOTIFY из wndproc и заполняю список вручную (без dispinfo), все работает нормально, но как только я добавляю сообщение WM_NOTIFY для обработки BCN_DROWDOWN для кнопки разделения, вещиповторить ошибку, не могу выбрать любой элемент.

ListView.cpp:

#include "ListView.h"
#include <vector>

ListView::ListView()
    :
    hWnd(nullptr), x(0), y(0), width(0), height(0), id(0), nTotalItems(0)/*, lvi({0}), lvc({0})*/
{

    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(icex);
    icex.dwICC = ICC_LISTVIEW_CLASSES;

    InitCommonControlsEx(&icex);
}

void ListView::Create(DWORD dwStyle, int x_in, int y_in, int width_in, int height_in, HWND hWndParent, int id_in)
{
    assert(hWnd == nullptr);

    x = x_in;
    y = y_in;
    width = width_in;
    height = height_in;
    id = id_in;

    hWnd = CreateWindow(WC_LISTVIEW, "", dwStyle, x, y, width, height, hWndParent, (HMENU)id, GetModuleHandle(nullptr), nullptr);

    assert(hWnd != 0);
}

BOOL ListView::InsertRows(int nRows)
{
    LVITEM lvi = {};

    lvi.mask = LVIF_TEXT | LVIF_STATE;
    lvi.pszText = LPSTR_TEXTCALLBACK;
    lvi.iSubItem = 0;
    lvi.stateMask = 0;
    lvi.state = 0;

    for(int i = 0; i < nRows; ++i)
    {
        lvi.iItem = i;

        if(ListView_InsertItem(hWnd, &lvi) == -1)
            return FALSE;
    }

    return TRUE;
}

BOOL ListView::InsertColumns(int nCols)
{
    LVCOLUMN lvc = {};
    char textCol[] = "Columna";
    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvc.cx = 100;
    lvc.pszText = textCol;
    lvc.fmt = LVCFMT_LEFT;

    for(int i = 0; i < nCols; ++i)
    {
        lvc.iSubItem = i;

        if(ListView_InsertColumn(hWnd, i, &lvc) == -1)
            return FALSE;
    }

    return TRUE;
}


void ListView::SetSubItemText(int nRow, int nCol, const std::string& strText)
{
    std::vector<char> tmpChar(strText.begin(), strText.end());
    tmpChar.push_back('\0');

    ListView_SetItemText(hWnd, nRow, nCol, &tmpChar[0]);
}


void ListView::SetSubItemText(int nRow, int nCol, char * szText)
{
    ListView_SetItemText(hWnd, nRow, nCol, szText);
}

void ListView::SetExStyle(DWORD dwExStyle)
{
    ListView_SetExtendedListViewStyle(hWnd, dwExStyle);
}

HWND ListView::Hwnd() const
{
    return this->hWnd;
}

ListView.h

#ifndef _LISTVIEW_H_
#define _LISTVIEW_H_

#include "../stdafx.h"
#include <CommCtrl.h>
#include <cassert>
#include <string>

class ListView
{
public:
    ListView();
    void Create(DWORD dwStyle, int x_in, int y_in, int width_in, int height_in, HWND hWndParent, int id_in);
    BOOL InsertRows(int nRows);
    BOOL InsertColumns(int nCols);
    void SetSubItemText(int nRow, int nCol, const std::string& strText);
    void SetSubItemText(int nRow, int nCol, char* szText);
    std::string GetSubItemText(int nRow, int nCol) const;
    void SetExStyle(DWORD dwExStyle);
    HWND Hwnd() const;

public:

private:
    HWND hWnd;
    int id;
    int x;
    int y;
    int width;
    int height;
    int nTotalItems;
};

#endif

MainWindow.cpp

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
    {
        OnCreate();
        return 0;
    }
    break;

    case WM_COMMAND:
    {
        if(HIWORD(wParam) == BN_CLICKED)
            OnCommand(LOWORD(wParam));

        return 0;
    }
    break;

    case WM_NOTIFY:
    {
        OnNotify(lParam);
    }
    break;

    case WM_DESTROY:
        PostQuitMessage(0);
    return 0;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    break;
    }

    return TRUE;
}

void MainWindow::OnCreate()
{
    lvMain.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_ALIGNTOP | LVS_SHOWSELALWAYS | LVS_SINGLESEL,
        11, 11, 438, 322, hWnd, ID_LISTVIEW_MAIN);
    lvMain.SetExStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

    btnAceptar.Create(IDS_ASIGNAR, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | BS_TEXT,
        456, 11, hWnd, ID_BUTTON_ASIGNAR);

    btnFiltro.Create(IDS_TODOS, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | BS_TEXT | BS_SPLITBUTTON,
        456, 41, hWnd, ID_BUTTON_VERTODOS);

    const int nColsWidths[] = { 50, 250, 80, 20, 20 };

    lvMain.InsertColumns(3);
    lvMain.InsertRows(3);

    EnumChildWindows(hWnd, SetChildWndFontProc, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
}

void MainWindow::OnCommand(WORD wCmdId)
{
    switch (wCmdId)
    {
    case ID_BUTTON_ASIGNAR:
    {
        MessageBox(Window(), "hola mundo!", "info", MB_OK);
    }
    break;
    }
}

void MainWindow::OnNotify(LPARAM lParam)
{
    switch ( ((LPNMHDR)lParam)->code)
    {
    case BCN_DROPDOWN:
    {
        if (((NMBCDROPDOWN*)lParam)->hdr.hwndFrom == btnFiltro.Hwnd())
        {
            RECT rcButton;
            GetClientRect(btnFiltro.Hwnd(), &rcButton);
            POINT pt;
            pt.x = rcButton.left;
            pt.y = rcButton.bottom;
            ClientToScreen(btnFiltro.Hwnd(), &pt);

            // Create a menu and add items.
            HMENU hSplitMenu = CreatePopupMenu();
            char szStringBuffer[255];

            LoadStringA(GetModuleHandle(nullptr), IDS_ASIGNADOS, szStringBuffer, 255);
            AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VERASIGNADOS, szStringBuffer);

            LoadStringA(GetModuleHandle(nullptr), IDS_SINASIGNAR, szStringBuffer, 255);
            AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VERSINASIGNAR, szStringBuffer);

            // Display the menu.
            TrackPopupMenu(hSplitMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION, pt.x, pt.y, 0, hWnd, NULL);
        }
    }
    break;
    case LVN_GETDISPINFO:
    {
        if (((LPNMHDR)lParam)->hwndFrom == lvMain.Hwnd() )
        {
            NMLVDISPINFO* plvdi = (NMLVDISPINFO*)lParam;

            switch (plvdi->item.iSubItem)
            {
            case 0:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 0", 100);
                plvdi->item.pszText = buff;
            }
            break;
            case 1:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 1", 100);
                plvdi->item.pszText = buff;
            }
            break;
            case 2:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 2", 100);
                plvdi->item.pszText = buff;
            }
            break;
            default:
            break;
            }
        }
    }
    break;
    default:
    break;
    }
}

Я ожидаю того же результата, что и использование функций и глобальных переменных для создания и управления элементами и подэлементами списка просмотра. Я не знаю, что идет не так, я уже пытался сделать обработчик OnNotify статичным, но тот же результат, Предметы и подэлементы есть, но я не могу ничего выбрать.

Надеюсь, вы можете помочь мне, спасибо заВаша помощь!.

Кстати, этот код работает нормально:

Main.h

#ifndef _MAIN_H_
#define _MAIN_H_

//#define NDEBUG // for assert
//#define UNICODE
#define _WIN32_IE 0x0601
#define _WIN32_WINNT 0x0601
#include <sdkddkver.h>
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#include <commctrl.h>
#include <cassert>
#include "LM/CLockManager.h"
#include "resource.h"

#define ID_LISTVIEW 1200
#define ID_BUTTON_ASIGNAR 1201
#define ID_BUTTON_VER_TODOS 1202
#define ID_BUTTON_BUSCAR 1203
#define ID_BUTTON_ELIMINAR 1204
#define ID_BUTTON_AGREGAR 1205
#define ID_MENU_VER_ASIGNADOS 1300
#define ID_MENU_VER_SIN_ASIGNAR 1301

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND CreateListView(HWND hWndParent);
HWND CreateButton(HWND hWndParent, const char* szBtnText, int x, int y, int id, DWORD dwStyle = 0);
BOOL InsertListViewColumns(HWND hWndLv_, int nColumns);
BOOL InsertListViewItem(HWND hWndLv_, unsigned int cItems);
BOOL InsertListViewRow(HWND hWndLv_, unsigned int nRows, unsigned int nCols);
void HandleWM_NOTIFY(LPARAM lParam);

#endif

WndProc.cpp

#include "main.h"
#include <string>
#include <vector>
#include <stdexcept>

char szDialogContent[256] = {};
HIMAGELIST hImage = nullptr;

HWND hWndTest = nullptr;
char columnas[3][255] =
{
    {"Col 1"},
    {"Col 2"},
    {"Col 3"}
};

CLockManager manager("basedatos.txt");
std::vector<CLockers> lockers;

LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
        case WM_CREATE:
        {
            manager.GetLockers(lockers, CLockers::Filter::All);

            char szStringBuffer[256];
            LoadString(GetModuleHandle(nullptr), IDS_ASIGNAR, szStringBuffer, 255);
            HWND hWndBt = CreateButton(hWnd, szStringBuffer, 456, 11, ID_BUTTON_ASIGNAR);

            LoadString(GetModuleHandle(nullptr), IDS_TODOS, szStringBuffer, 255);
            HWND hWndBt2 = CreateButton(hWnd, szStringBuffer, 456, 41, ID_BUTTON_VER_TODOS, BS_SPLITBUTTON);

            LoadString(GetModuleHandle(nullptr), IDS_BUSCAR, szStringBuffer, 255);
            HWND hWndBt3 = CreateButton(hWnd, szStringBuffer, 456, 71, ID_BUTTON_BUSCAR);

            LoadString(GetModuleHandle(nullptr), IDS_ELIMINAR, szStringBuffer, 255);
            HWND hWndBt4 = CreateButton(hWnd, szStringBuffer, 456, 101, ID_BUTTON_ELIMINAR);

            LoadString(GetModuleHandle(nullptr), IDS_AGREGAR, szStringBuffer, 255);
            HWND hWndBt5 = CreateButton(hWnd, szStringBuffer, 456, 131, ID_BUTTON_AGREGAR);

            HWND hWndLv = CreateListView(hWnd);

            hImage = ImageList_Create(16, 16, ILC_COLOR32, 1, 1);

            HICON hIcon = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_ICONLOCKER));
            ImageList_AddIcon(hImage, hIcon);
            DestroyIcon(hIcon);

            hIcon = LoadIcon(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDI_ICONDISABLED));
            ImageList_AddIcon(hImage, hIcon);
            DestroyIcon(hIcon);

            ListView_SetImageList(hWndLv, hImage, LVSIL_SMALL);

            BOOL ilvcResult = InsertListViewColumns(hWndLv, 5);
            assert(ilvcResult == TRUE);
            BOOL ilviResult = InsertListViewItem(hWndLv, lockers.size());

            assert(ilviResult == TRUE);

            EnumChildWindows(hWnd, SetFontProc, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
        }
            break;
        case WM_COMMAND:
        {
            if(HIWORD(wParam) == BN_CLICKED)
            {
                switch(LOWORD(wParam))
                {
                    case ID_BUTTON_VER_TODOS:
                    {

                    }
                    break;
                    case ID_MENU_VER_ASIGNADOS:
                    {

                    }
                    break;
                    case ID_MENU_VER_SIN_ASIGNAR:
                    {

                    }
                    break;
                    case ID_BUTTON_AGREGAR:
                    {

                    }
                    break;
                    case ID_BUTTON_BUSCAR:
                    {

                    }
                    break;
                    case ID_BUTTON_ASIGNAR:
                    {

                    }
                    break;
                    case ID_BUTTON_ELIMINAR:
                    {

                    }
                    break;
                }
            }
        }
            break;
        case WM_NOTIFY:
            switch( ((LPNMHDR)lParam)->code )
            {
                case LVN_GETDISPINFO:
                {
                    if( ((LPNMHDR)lParam)->hwndFrom == GetDlgItem(hWnd, ID_LISTVIEW) )
                    {
                        HandleWM_NOTIFY(lParam);
                    }
                }
                break;
                case BCN_DROPDOWN:
                {
                    HWND hWndFiltro = GetDlgItem(hWnd, ID_BUTTON_VER_TODOS);

                    if( ((NMBCDROPDOWN*)lParam)->hdr.hwndFrom == hWndFiltro )
                    {
                        RECT rcButton;
                        GetClientRect(hWndFiltro, &rcButton);
                        POINT pt;
                        pt.x = rcButton.left;
                        pt.y = rcButton.bottom;
                        ClientToScreen(GetDlgItem(hWnd, ID_BUTTON_VER_TODOS), &pt);

                        // Create a menu and add items.
                        HMENU hSplitMenu = CreatePopupMenu();
                        char szStringBuffer[255];

                        LoadString(GetModuleHandle(nullptr), IDS_ASIGNADOS, szStringBuffer, 255);
                        AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VER_ASIGNADOS, szStringBuffer);

                        LoadString(GetModuleHandle(nullptr), IDS_SINASIGNAR, szStringBuffer, 255);
                        AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VER_SIN_ASIGNAR, szStringBuffer);

                        // Display the menu.
                        TrackPopupMenu(hSplitMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION, pt.x, pt.y, 0, hWnd, NULL);
                    }
                }
                break;
            }
            break;
        case WM_DESTROY:
            ImageList_Destroy(hImage);
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
            break;
    }

    return 0;
}

HWND CreateListView(HWND hWndParent)
{
    RECT rcClient = {};
    GetClientRect(hWndParent, &rcClient);

    HWND hWndLv_ = CreateWindowEx(0, WC_LISTVIEW,
            "", WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT  |LVS_ALIGNTOP | LVS_SHOWSELALWAYS,
            11,11, 438, 322,// rcClient.bottom - rcClient.top - 50,
            hWndParent, (HMENU)ID_LISTVIEW, GetModuleHandle(nullptr), nullptr);

    ListView_SetExtendedListViewStyle(hWndLv_, LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);
    assert(hWndLv_ != nullptr);

    return hWndLv_;
}

HWND CreateButton(HWND hWndParent, const char* szBtnText, int x, int y, int id, DWORD dwStyle)
{
    HWND hWndBtn_ = CreateWindow("BUTTON", szBtnText,
            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON | dwStyle, x, y, 75, 23,
            hWndParent, (HMENU)(long long)id, GetModuleHandle(nullptr), nullptr);

    assert(hWndBtn_ != nullptr);

    return hWndBtn_;
}

BOOL InsertListViewColumns(HWND hWndLv_, int nColumns)
{
    LVCOLUMN lvc = {};
    int iCol;
    int wCols[] = {50, 250, 80, 20, 20};

    LoadString(GetModuleHandle(nullptr), IDS_LOCKER, columnas[0], 255);
    LoadString(GetModuleHandle(nullptr), IDS_USUARIO, columnas[1], 255);
    LoadString(GetModuleHandle(nullptr), IDS_FECHA, columnas[2], 255);

    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;

    for(iCol = 0; iCol < nColumns; ++iCol)
    {
        if(iCol < 1)
        {
            lvc.fmt = LVCFMT_RIGHT;
        }
        else
        {
            lvc.fmt = LVCFMT_LEFT;
        }

        lvc.iSubItem = iCol;
        lvc.pszText = columnas[iCol];
        lvc.cx = wCols[iCol];

        if (ListView_InsertColumn(hWndLv_, iCol, &lvc) == -1)
            return FALSE;
    }

    return TRUE;
}

BOOL InsertListViewItem(HWND hWndLv_, unsigned int cItems)
{
    //HWND hWnd = GetParent(hWndLv_);
    LVITEM lvi = {0};

    lvi.pszText = LPSTR_TEXTCALLBACK;
    lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
    lvi.iSubItem = 0;
    lvi.stateMask = 0;
    lvi.state = 0;

    //SendMessage((HWND)hWnd, WM_SETREDRAW, (WPARAM)FALSE, 0);

    for(int i = 0; i < cItems; ++i)
    {
        lvi.iItem = i;

        if(!lockers.at(i).Enabled())
            lvi.iImage = 1;
        else
            lvi.iImage = 0;

        if(ListView_InsertItem(hWndLv_, &lvi) == -1)
        {
            return FALSE;
        }
    }

    return TRUE;
}

void HandleWM_NOTIFY(LPARAM lParam)
{
    NMLVDISPINFO* plvdi;

    switch ( ((LPNMHDR) lParam)->code )
    {
        case LVN_GETDISPINFO:
        {
            static constexpr size_t size = 256;
            plvdi = (NMLVDISPINFO*)lParam;

            switch(plvdi->item.iSubItem)
            {
            case 0:
            {
                std::string tmp = std::to_string( lockers.at(plvdi->item.iItem).GetLockerNumber());

                char buff[size];
                strncpy(buff, tmp.c_str(), size );
                plvdi->item.pszText = buff;
            }
                break;

            case 1:
            {
                std::string tmp = lockers.at(plvdi->item.iItem).GetAssignedUser();

                char buff[size];
                strncpy(buff, tmp.c_str(), size );
                plvdi->item.pszText = buff;
            }
                break;

            case 2:
            {
                std::string tmp = lockers.at(plvdi->item.iItem).GetDate();

                char buff[size];
                strncpy(buff, tmp.c_str(), size );
                plvdi->item.pszText = buff;
            }
                break;
            case 3:
            {
                char key[2][2] = {"N", "S"};
                plvdi->item.pszText = key[lockers.at(plvdi->item.iItem).HasKey()];
            }
                break;
            case 4:
            {
                char status[3][2] = {"B", "R", "M"};
                plvdi->item.pszText = status[lockers.at(plvdi->item.iItem).GetStatusInt()];
            }
                break;
            default:
                break;
            }
            break;
        }
    }
}

Ответы [ 2 ]

1 голос
/ 08 октября 2019

Хорошо, я решил это.

Несмотря на то, что MS Docs заявляет, что WM_NOTIFY не возвращает никакого значения «за исключением уведомительных сообщений, которые указывают другое», ни LVN_GETDISPINFO и BCN_DROPDOWN не возвращают никакого значения.

https://docs.microsoft.com/en-us/windows/win32/controls/wm-notify

https://docs.microsoft.com/en-us/windows/win32/controls/bcn-dropdown

https://docs.microsoft.com/en-us/windows/win32/controls/lvn-getdispinfo

Итак, WM_NOTIFY должен не возвращать никакого значения, верно? .... хорошо, все работало, как только я добавил "return 0;"в случае WM_NOTIFY.

Теперь все решено: надеюсь, это может пригодиться кому-то еще

Это единственный фрагмент кода, который был изменен: на MainWindow.cpp

case WM_NOTIFY:
{
    OnNotify(lParam);
    return 0;
}
break;
0 голосов
/ 08 октября 2019

это рабочий код в ответ на мой вопрос. Спасибо большое за помощь. Я надеюсь, что не слишком много кода: D (это минимум, который у меня есть, использование удаленных ресурсов и другой не относящийся к делу код для проблемы):

Main.cpp

#include "stdafx.h"
#include "App.h"

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

    App app;

    return app.Run();
}

stdafx.h

#pragma once
#define _WIN32_WINNT 0X0601
#include <SDKDDKVer.h>

// Excluir material rara vez utilizado de encabezados de Windows


#ifdef UNICODE
#undef UNICODE
#endif

#ifdef _UNICODE
#undef _UNICODE
#endif

#define WIN32_LEAN_AND_MEAN
#define NORPC
#define NOMCX
#define NOTAPE
#define NOKERNEL
#define NOSERVICE
#define NOKANJI
#define NOPROFILER
#define NOPROXYSTUP
#define NOMINMAX
#define STRICT
// Archivos de encabezado de Windows
#include <windows.h>
#include <CommCtrl.h>

#pragma comment(lib, "ComCtl32.lib")

BaseWindow.h

#pragma once
#include "stdafx.h"
#include <cassert>

template <class DERIVED_T>
class BaseWindow
{
public:
    BaseWindow() : hWnd(nullptr), hInst(GetModuleHandle(nullptr)), wcx({}) {}
    BOOL Create(LPCSTR lpWindowName, DWORD dwStyle, DWORD dwExStyle = 0,
        int x = CW_USEDEFAULT, int y = CW_USEDEFAULT, int width_in = CW_USEDEFAULT, int height_in = CW_USEDEFAULT,
        HWND hWndParent = 0, HMENU hMenu = 0)
    {
        RECT wr = {};
        wr.left = x;
        wr.right = width_in + x;
        wr.top = y;
        wr.bottom = height_in + y;
        AdjustWindowRect(&wr, dwStyle, FALSE);

        width = wr.right - wr.left;
        height = wr.bottom - wr.top;

        wcx.cbSize = sizeof(wcx);
        wcx.hInstance = hInst;
        wcx.lpszClassName = ClassName();
        wcx.lpfnWndProc = DERIVED_T::WndProc;
        wcx.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wcx.hCursor = LoadCursor(nullptr, IDC_ARROW);
        wcx.hIcon = LoadIcon(nullptr, IDI_APPLICATION);

        ATOM aResult = RegisterClassEx(&wcx);
        assert(aResult != 0);

        hWnd = CreateWindowEx(
            dwExStyle, ClassName(), lpWindowName, dwStyle,
            x, y, width, height,
            hWndParent, hMenu, hInst, this
        );

        assert(hWnd != 0);

        return (hWnd ? TRUE : FALSE);
    }
    void Show(int nCmdShow) { ShowWindow(hWnd, nCmdShow); }
    HWND Window() const { return hWnd; }

protected:
    virtual LPCSTR ClassName() const = 0;
    virtual LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) = 0;

protected:
    HWND hWnd;
    HINSTANCE hInst;
    int width;
    int height;
    WNDCLASSEX wcx;

public:
    static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        DERIVED_T* pThis = nullptr;

        if (uMsg == WM_NCCREATE)
        {
            CREATESTRUCT* pCreate = (CREATESTRUCT*)lParam;
            pThis = (DERIVED_T*)pCreate->lpCreateParams;
            SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)pThis);

            pThis->hWnd = hWnd;
        }
        else
        {
            pThis = (DERIVED_T*)GetWindowLongPtr(hWnd, GWLP_USERDATA);
        }
        if (pThis)
        {
            return pThis->HandleMessage(uMsg, wParam, lParam);
        }
        else
        {
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
        }

    }
};

MainWindow.h

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

#include "BaseWindow.h"
#include "button.h"
#include "ListView.h"

class MainWindow : public BaseWindow<MainWindow>
{
public:
    MainWindow();

public:
    LPCSTR ClassName() const override { return "Window Example"; }
    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
    static BOOL CALLBACK SetChildWndFontProc(HWND hWndChild, LPARAM font);

private:
    void OnCreate();
    void OnCommand(WORD wCmdId);
    void OnNotify(LPARAM lParam);

private:
    enum CONTROLS_ID { ID_LISTVIEW_MAIN = 1200, ID_BUTTON_ASIGNAR, ID_BUTTON_VERTODOS, ID_BUTTON_BUSCAR,
        ID_BUTTON_ELIMINAR, ID_BUTTON_AGREGAR, ID_MENU_VERASIGNADOS, ID_MENU_VERSINASIGNAR };
    ListView lvMain;
    Button btnAceptar;
    Button btnFiltro;
    char buff[3][255] = {
        {"HELLO WORLD!"},
        {"HOW ARE YOU?"},
        {"FINE, THX!"}
    };
};

Mainwindow.cpp

#pragma once
#include "MainWindow.h"

MainWindow::MainWindow() 
    : BaseWindow<MainWindow>() 
{
}

LRESULT MainWindow::HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
    case WM_CREATE:
    {
        OnCreate();
        return 0;
    }
    break;

    case WM_COMMAND:
    {
        if(HIWORD(wParam) == BN_CLICKED)
            OnCommand(LOWORD(wParam));

        return 0;
    }
    break;

    // here lies the problem
    case WM_NOTIFY:
    {
        OnNotify(lParam);
    }
    break;

    case WM_DESTROY:
        PostQuitMessage(0);
    return 0;

    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    break;
    }

    return TRUE;
}

BOOL CALLBACK MainWindow::SetChildWndFontProc(HWND hWndChild, LPARAM font)
{
    SendMessage(hWndChild, WM_SETFONT, (WPARAM)font, TRUE);
    return TRUE;
}

void MainWindow::OnCreate()
{
    lvMain.Create(WS_CHILD | WS_VISIBLE | WS_BORDER | LVS_REPORT | LVS_ALIGNTOP | LVS_SHOWSELALWAYS | LVS_SINGLESEL,
        11, 11, 438, 322, hWnd, ID_LISTVIEW_MAIN);
    lvMain.SetExStyle(LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES);

    btnAceptar.Create("Asign", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | BS_TEXT,
        456, 11, hWnd, ID_BUTTON_ASIGNAR);

    btnFiltro.Create("View all", BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | BS_TEXT | BS_SPLITBUTTON,
        456, 41, hWnd, ID_BUTTON_VERTODOS);

    const int nColsWidths[] = { 50, 250, 80 };


    lvMain.InsertColumns(3);
    lvMain.InsertRows(3);

    // Uncomment the following three lines to set manually the subitem text
    // and comment the WM_NOTIFY message
    // string casted to char* just for testing purposes
    //lvMain.SetSubItemText(0, 0, std::string("HELLO WORLD!"));
    //lvMain.SetSubItemText(1, 1, (char*)"HOW ARE YOU!?");
    //lvMain.SetSubItemText(2, 2, std::string("FINE THX!"));

    EnumChildWindows(hWnd, SetChildWndFontProc, (LPARAM)GetStockObject(DEFAULT_GUI_FONT));
}

void MainWindow::OnCommand(WORD wCmdId)
{
    switch (wCmdId)
    {
    case ID_BUTTON_ASIGNAR:
    {
        MessageBox(Window(), "Hello hello!!", "info", MB_OK);
    }
    break;
    }
}

void MainWindow::OnNotify(LPARAM lParam)
{
    switch ( ((LPNMHDR)lParam)->code)
    {
    case BCN_DROPDOWN:
    {
        if (((NMBCDROPDOWN*)lParam)->hdr.hwndFrom == btnFiltro.Hwnd())
        {
            RECT rcButton;
            GetClientRect(btnFiltro.Hwnd(), &rcButton);
            POINT pt;
            pt.x = rcButton.left;
            pt.y = rcButton.bottom;
            ClientToScreen(btnFiltro.Hwnd(), &pt);

            // Create a menu and add items.
            HMENU hSplitMenu = CreatePopupMenu();

            AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VERASIGNADOS, "menu item 1");
            AppendMenu(hSplitMenu, MF_BYPOSITION, ID_MENU_VERSINASIGNAR, "menu item 2");

            // Display the menu.
            TrackPopupMenu(hSplitMenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION, pt.x, pt.y, 0, hWnd, NULL);
        }
    }
    break;
    // parent window receives the LVN_GETDISPINFO msg and populates the list view
    // in this example, 3 rows and 3 columns
    case LVN_GETDISPINFO:
    {
        if (((LPNMHDR)lParam)->hwndFrom == lvMain.Hwnd() )
        {
            NMLVDISPINFO* plvdi = (NMLVDISPINFO*)lParam;

            switch (plvdi->item.iSubItem)
            {
            case 0:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 0", 100);
                plvdi->item.pszText = buff;
            }
            break;
            case 1:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 1", 100);
                plvdi->item.pszText = buff;
            }
            break;
            case 2:
            {
                char buff[100];
                strncpy_s(buff, "SubItem Index 2", 100);
                plvdi->item.pszText = buff;
            }
            break;
            default:
            break;
            }
        }
    }
    break;
    default:
    break;
    }
}

App.h

#pragma once
#include "MainWindow.h"

class App
{
public:
    App();
    App(const App&) = delete;
    App& operator=(const App&) = delete;
    ~App();
    int Run();

private:
    HINSTANCE hInst;
    MainWindow win;
};

App.cpp

#include "App.h"

App::App()
    : hInst(GetModuleHandle(nullptr))
{
    win.Create("My app", WS_OVERLAPPEDWINDOW, 0, CW_USEDEFAULT, CW_USEDEFAULT, 542, 343);
    win.Show(SW_SHOWDEFAULT);
}

App::~App()
{
}

int App::Run()
{
    MSG msg = {};

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

Button.h

#ifndef _BUTTON_H_
#define _BUTTON_H_

#include "stdafx.h"
#include <cassert>

class Button
{
public:
    Button();
    void Create(LPCSTR lpszText, DWORD dwStyle, int x_in, int y_in, HWND hWndParent, int id_in);
    void Create(int idString, DWORD dwStyle, int x_in, int y_in, HWND hWndParent, int id_in);
    HWND Hwnd() const;

public:

private:
    HWND hWnd;
    int id;
    int x;
    int y;
    static constexpr int width = 75;
    static constexpr int height = 24;
    static constexpr int nMaxLoadString = 100;
};

#endif

Button.cpp

#include "Button.h"

Button::Button()
    :
    hWnd(nullptr), x(0), y(0), id(0)
{
}

void Button::Create(LPCSTR lpszText, DWORD dwStyle, int x_in, int y_in, HWND hWndParent, int id_in)
{
    // we don't want to create another button with the same object
    assert(hWnd == nullptr);

    x = x_in;
    y = y_in;
    id = id_in;

    hWnd = CreateWindow("Button", lpszText, dwStyle, x, y, width, height, hWndParent, (HMENU)id, GetModuleHandle(nullptr), 0);

    assert(hWnd != 0);
}

void Button::Create(int idString, DWORD dwStyle, int x_in, int y_in, HWND hWndParent, int id_in)
{
    char szButtonName[nMaxLoadString] = {};
    LoadString(GetModuleHandle(nullptr), idString, szButtonName, nMaxLoadString);

    Create(szButtonName, dwStyle, x_in, y_in, hWndParent, id_in);
}

HWND Button::Hwnd() const
{
    return hWnd;
}

ListView.h

#ifndef _LISTVIEW_H_
#define _LISTVIEW_H_

#include "stdafx.h"
#include <CommCtrl.h>
#include <cassert>
#include <string>

class ListView
{
public:
    ListView();
    void Create(DWORD dwStyle, int x_in, int y_in, int width_in, int height_in, HWND hWndParent, int id_in);
    BOOL InsertRows(int nRows);
    BOOL InsertColumns(int nCols);
    BOOL InsertColumn(int iCol, char* szText, int nWidthCol = 50);
    void SetSubItemText(int nRow, int nCol, const std::string& strText);
    void SetSubItemText(int nRow, int nCol, char* szText);
    std::string GetSubItemText(int nRow, int nCol) const;
    void SetExStyle(DWORD dwExStyle);
    HWND Hwnd() const;

public:

private:
    HWND hWnd;
    int id;
    int x;
    int y;
    int width;
    int height;
    int nTotalItems;
};

#endif

ListView.cpp

#include "ListView.h"
#include <vector>

ListView::ListView()
    :
    hWnd(nullptr), x(0), y(0), width(0), height(0), id(0), nTotalItems(0)
{

    INITCOMMONCONTROLSEX icex;
    icex.dwSize = sizeof(icex);
    icex.dwICC = ICC_LISTVIEW_CLASSES;

    InitCommonControlsEx(&icex);
}

void ListView::Create(DWORD dwStyle, int x_in, int y_in, int width_in, int height_in, HWND hWndParent, int id_in)
{
    // we don't want to create another listview with the same object
    assert(hWnd == nullptr);

    x = x_in;
    y = y_in;
    width = width_in;
    height = height_in;
    id = id_in;

    hWnd = CreateWindow(WC_LISTVIEW, "", dwStyle, x, y, width, height, hWndParent, (HMENU)id, GetModuleHandle(nullptr), nullptr);

    assert(hWnd != 0);
}

BOOL ListView::InsertRows(int nRows)
{
    LVITEM lvi = {};

    lvi.mask = LVIF_TEXT | LVIF_STATE;
    // remove LPSTR_TEXTCALLBACK and replace with a non const string if you want
    // to manually insert the items and subitems
    lvi.pszText = LPSTR_TEXTCALLBACK;
    lvi.iSubItem = 0;
    lvi.stateMask = 0;
    lvi.state = 0;

    for(int i = 0; i < nRows; ++i)
    {
        lvi.iItem = i;

        if(ListView_InsertItem(hWnd, &lvi) == -1)
            return FALSE;
    }

    return TRUE;
}

BOOL ListView::InsertColumns(int nCols)
{
    LVCOLUMN lvc = {};
    char textCol[] = "Test name";  // test name for the columns
    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvc.cx = 100;  // hardcoded for testing purposes
    lvc.pszText = textCol;
    lvc.fmt = LVCFMT_LEFT;

    for(int i = 0; i < nCols; ++i)
    {
        lvc.iSubItem = i;

        if(ListView_InsertColumn(hWnd, i, &lvc) == -1)
            return FALSE;
    }

    return TRUE;
}

// another method to insert columns
BOOL ListView::InsertColumn(int iCol, char * szText, int nWidthCol)
{
    LVCOLUMN lvc = {};
    lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
    lvc.cx = nWidthCol;
    lvc.pszText = szText;
    lvc.iSubItem = iCol;
    lvc.fmt = LVCFMT_LEFT;

    if (ListView_InsertColumn(hWnd, iCol, &lvc) == -1)
        return FALSE;

    return TRUE;
}

void ListView::SetSubItemText(int nRow, int nCol, const std::string& strText)
{
    std::vector<char> tmpChar(strText.begin(), strText.end());
    tmpChar.push_back('\0');

    ListView_SetItemText(hWnd, nRow, nCol, &tmpChar[0]);
}


void ListView::SetSubItemText(int nRow, int nCol, char * szText)
{
    ListView_SetItemText(hWnd, nRow, nCol, szText);
}

void ListView::SetExStyle(DWORD dwExStyle)
{
    ListView_SetExtendedListViewStyle(hWnd, dwExStyle);
}

HWND ListView::Hwnd() const
{
    return this->hWnd;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...