最初代碼來源
https://www.codeproject.com/Articles/7891/Using-virtual-lists
csdn代碼下載
https://download.csdn.net/download/rembo254/2100719
知識點:
subclasswindow是更改窗口過程,就是類嚮導關聯自定義的列表控件會調用PreSubclassWindow
CreateWindowEx會調用PreCreateWindow,這個是動態創建的,筆者重載了這個函數,發現一直沒有調用,花了很長的時間去調試
#pragma once
#include <vector>
class CSampleData
{
public:
CString moduleName; // 模塊名稱
CString filePath; // 圖片路徑
int result; // 分析結果
int image; // 列表圖片
bool checked; // 複選框
};
// 虛擬列表,記得RC編輯界面改對話框屬性Owner Data爲true
class CVirtualListCtrl : public CListCtrl
{
DECLARE_DYNAMIC(CVirtualListCtrl)
public:
CVirtualListCtrl();
virtual ~CVirtualListCtrl();
public:
void AddItem(const CSampleData& data);
void Clear();
DWORD GetItemCount() { return m_database.size(); }
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow()override;
afx_msg void OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLvnOdfinditem(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLvnOdcachehint(NMHDR *pNMHDR, LRESULT *pResult);
private:
BOOL IsCheckBoxesVisible();
void ToggleCheckBox(int item);
private:
std::vector<CSampleData> m_database;
public:
afx_msg void OnNMClick(NMHDR *pNMHDR, LRESULT *pResult);
afx_msg void OnLvnKeydown(NMHDR *pNMHDR, LRESULT *pResult);
};
// VirtualListCtrl.cpp : 實現文件
//
#include "stdafx.h"
#include "VListTest.h"
#include "VirtualListCtrl.h"
// CVirtualListCtrl
IMPLEMENT_DYNAMIC(CVirtualListCtrl, CListCtrl)
CVirtualListCtrl::CVirtualListCtrl()
{
}
CVirtualListCtrl::~CVirtualListCtrl()
{
}
void CVirtualListCtrl::AddItem(const CSampleData & data)
{
m_database.push_back(data);
SetItemCount(m_database.size());
}
void CVirtualListCtrl::Clear()
{
m_database.clear();
SetItemCount(0);
}
BEGIN_MESSAGE_MAP(CVirtualListCtrl, CListCtrl)
ON_NOTIFY_REFLECT(LVN_GETDISPINFO, &CVirtualListCtrl::OnLvnGetdispinfo)
ON_NOTIFY_REFLECT(LVN_ODFINDITEM, &CVirtualListCtrl::OnLvnOdfinditem)
ON_NOTIFY_REFLECT(LVN_ODCACHEHINT, &CVirtualListCtrl::OnLvnOdcachehint)
ON_NOTIFY_REFLECT(NM_CLICK, &CVirtualListCtrl::OnNMClick)
ON_NOTIFY_REFLECT(LVN_KEYDOWN, &CVirtualListCtrl::OnLvnKeydown)
ON_WM_CREATE()
END_MESSAGE_MAP()
// CVirtualListCtrl 消息處理程序
void CVirtualListCtrl::PreSubclassWindow()
{
// TODO: 在此添加專用代碼和/或調用基類
ModifyStyle(LVS_TYPEMASK, LVS_REPORT);
SetExtendedStyle(LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES | LVS_EX_GRIDLINES);
CListCtrl::PreSubclassWindow();
}
// 虛擬列表顯示前,發送消息請求顯示的內容
void CVirtualListCtrl::OnLvnGetdispinfo(NMHDR *pNMHDR, LRESULT *pResult)
{
LV_DISPINFO* pDispInfo = (LV_DISPINFO*)pNMHDR;
LV_ITEM* pItem = &(pDispInfo)->item;
int itemid = pItem->iItem;
if (pItem->mask & LVIF_TEXT)
{
CString text;
if (pItem->iSubItem == 0){
text = m_database[itemid].moduleName;
}
else if (pItem->iSubItem == 1){
text = m_database[itemid].filePath;
}
lstrcpyn(pItem->pszText, text, pItem->cchTextMax);
}
if (pItem->mask & LVIF_IMAGE)
{
// pItem->iImage = m_database[itemid].m_image;
if (IsCheckBoxesVisible())
{
pItem->mask |= LVIF_STATE;
pItem->stateMask = LVIS_STATEIMAGEMASK;
if (m_database[itemid].checked) {
pItem->state = INDEXTOSTATEIMAGEMASK(2); // Turn check box on..
}
else {
pItem->state = INDEXTOSTATEIMAGEMASK(1); // Turn check box off
}
}
}
*pResult = 0;
}
// 快捷鍵查找項
void CVirtualListCtrl::OnLvnOdfinditem(NMHDR *pNMHDR, LRESULT *pResult)
{
// pNMHDR has information about the item we should find
// In pResult we should save which item that should be selected
NMLVFINDITEM* pFindInfo = (NMLVFINDITEM*)pNMHDR;
/* pFindInfo->iStart is from which item we should search.
We search to bottom, and then restart at top and will stop
at pFindInfo->iStart, unless we find an item that match
*/
// Set the default return value to -1
// That means we didn't find any match.
*pResult = -1;
//Is search NOT based on string?
if ((pFindInfo->lvfi.flags & LVFI_STRING) == 0)
{
//This will probably never happend...
return;
}
/*
Let's look on a sample list;
Name
Anders
* Anna
Annika
Bob
Emma
Emmanuel
Anna is selected.
If "A" is written, Annika should be selected.
If "AND" is written, Anders should be selected.
If "ANNK" is written, the selection should stay on Anna.
If "E" is written, Emma should be selected.
*/
//This is the string we search for
CString searchstr = pFindInfo->lvfi.psz;
// TRACE(_T("Find: %s\n"), searchstr);
int startPos = pFindInfo->iStart;
//Is startPos outside the list (happens if last item is selected)
if (startPos >= GetItemCount())
startPos = 0;
int currentPos = startPos;
//Let's search...
do
{
//Do this word begins with all characters in searchstr?
if (_tcsnicmp(m_database[currentPos].moduleName, searchstr, searchstr.GetLength()) == 0)
{
//Select this item and stop search.
*pResult = currentPos;
break;
}
//Go to next item
currentPos++;
//Need to restart at top?
if (currentPos >= GetItemCount())
currentPos = 0;
//Stop if back to start
} while (currentPos != startPos);
}
// 數據庫在網絡上另一臺電腦需要使用
void CVirtualListCtrl::OnLvnOdcachehint(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMLVCACHEHINT pCacheHint = reinterpret_cast<LPNMLVCACHEHINT>(pNMHDR);
// TODO: 在此添加控件通知處理程序代碼
*pResult = 0;
}
BOOL CVirtualListCtrl::IsCheckBoxesVisible()
{
DWORD style = GetStyle();
if (((style & LVS_TYPEMASK) == LVS_LIST) ||
((style & LVS_TYPEMASK) == LVS_REPORT))
return TRUE;
return FALSE;
}
void CVirtualListCtrl::ToggleCheckBox(int item)
{
m_database[item].checked = !m_database[item].checked;
RedrawItems(item, item);
}
void CVirtualListCtrl::OnNMClick(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLISTVIEW* pNMListView = (NM_LISTVIEW*)pNMHDR;
LVHITTESTINFO hitinfo;
hitinfo.pt = pNMListView->ptAction;
int item = HitTest(&hitinfo);
if (item != -1) {
if ((hitinfo.flags & LVHT_ONITEMSTATEICON) != 0) {
ToggleCheckBox(item);
}
}
*pResult = 0;
}
void CVirtualListCtrl::OnLvnKeydown(NMHDR *pNMHDR, LRESULT *pResult)
{
LV_KEYDOWN* pLVKeyDown = (LV_KEYDOWN*)pNMHDR;
if (pLVKeyDown->wVKey == VK_SPACE) {
if (IsCheckBoxesVisible()) {
if (GetSelectionMark() != -1)
ToggleCheckBox(GetSelectionMark());
}
}
*pResult = 0;
}