Я работаю над приложением менеджера шкафчиков (уже делал это на консоли) на 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;
}
}
}