如何修复列表视图中的错误?,封装控件时无法选择任何项



我正在 win32api 上开发一个储物柜管理器应用程序(已经在控制台上完成了(。第一个构建是"win32 普通样式代码"(函数定义和声明,无对象(。这是一个列表视图,用于显示与之交互的项目和按钮。 现在,这个版本就像一个魅力,我通过LVN_GETDISPINFO通知消息填充列表视图,并且我有一个拆分按钮来处理BCN_DROPDOWN通知消息。

在我看到它可以工作之后,我想让它封装窗口和控件,并为列表视图和按钮控件制作简单的包装器。 我以相同的方式处理相同的消息(LVN_GETDISPINFOBCN_DROPDOWN通知消息(,但在这种情况下,Listview 似乎已禁用(颜色不变(,我只是无法选择任何内容! 现在,如果我从 wndproc 中删除WM_NOTIFY消息,并手动填充列表(没有 dispinfo(,它可以正常工作,但是一旦我添加WM_NOTIFY消息来处理拆分按钮的BCN_DROWDOWN,事情再次出错,无法选择任何项目。

列表视图.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('');
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;
}

列表视图.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

主窗口.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处理程序成为静态的,但结果相同,项目和子项目在那里,但我无法选择任何东西。

希望你能帮助我,谢谢你的帮助!

顺便说一下,这是工作正常的代码:

主.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

文德普罗克.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;
}
}
}

好的,我解决了。

尽管MS Docs指出WM_NOTIFY不返回任何值"除了指定其他明智的通知消息",但LVN_GETDISPINFO和BCN_DROPDOWN都不会返回任何值。

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

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

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

所以,WM_NOTIFY应该不返回任何值,对吧?....好吧,在WM_NOTIFY的情况下,只要我添加了"return 0;",一切就工作了。

现在一切都解决了:D我希望这对其他人有用

这是唯一被更改的代码段: 在主窗口上.cpp

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

这是我问题的后续工作代码。非常感谢您的帮助。我希望代码不要太多:D(这是我拥有的最小值,删除了资源使用情况和其他不相关的代码(:

主.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);
}
}
};

主窗口.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!"}
};
};

主窗口.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;
}
}

应用程式

#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;
};

应用.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;
}

按钮.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

按钮.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;
}

列表视图.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

列表视图.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('');
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;
}

最新更新