MFC CListView 如何防止用户键入字母时搜索和自动选择?



TL;DR

在C++MFC CListView中,当CListView具有键盘焦点时,如何防止基于用户键入的字母的自动魔术选择?

情况:

MFC应用程序使用CListView显示包含字母数字字符串的行集合。如果我选择列表,使其具有键盘焦点,然后键入一个字母,则列表选择将跳到第一列值以该字母开头的第一个项目。

例如,如果我键入"r",则列表选择将跳到以字母"r"开头的第一项。如果我输入,比如说"b",那么列表选择就会跳到以字母b开头的第一个项目。依此类推。

当我使用VS2019新项目向导创建新应用程序时,这种行为在CListView中是自动魔术。

问题1:

如何在不干扰向上/向下箭头键导航的情况下防止发生这种自动魔术选择?

在我对此进行思考的过程中,我发现一个类为WC_LISTVIEW的直接WIN32窗口也会以这种方式运行,所以我认为一定有一种样式可以打开或关闭它?

如果它是一种样式,那么我可以在OnInitialUpdate()中的ModifyStyle()调用中更改它,甚至可以使用它的HWND向控件发送消息?

所以。。。问题2:

我可以在不进入CListView的消息处理循环中的杂草的情况下关闭它吗?

评论

我不是在寻找CListView可以做的高级多字母子字符串匹配搜索

当我键入字母或数字时,我希望CListView停止更改选择,并希望它继续响应向上/向下箭头、向上/向下翻页和主页/结束键更改选择的正常行为。所以,如果你愿意的话,请关闭搜索。

代码

我可以发布更多的代码,但这将是VS2019新项目的输出->C++->MFC->资源管理器样式向导。

我所做的唯一相关更改是将CListView派生类重命名为MyCFileListView,并填充列表。

填充列表:

static void AddData(CListCtrl &ctrl, int row, int col, const wchar_t *str) {
LVITEM lv;
lv.iItem = row;
lv.iSubItem = col;
lv.pszText = (LPTSTR) str;
lv.mask = LVIF_TEXT;
if(col == 0)
ctrl.InsertItem(&lv);
else
ctrl.SetItem(&lv);  
}
void MyCFileListView::OnInitialUpdate() {
CListView::OnInitialUpdate();
ModifyStyle(LVS_TYPEMASK, LVS_REPORT);

CListCtrl &the_list = GetListCtrl();
the_list.InsertColumn(0, L"File");
the_list.SetColumnWidth(0, 80);
the_list.InsertColumn(1, L"Size");
the_list.SetColumnWidth(1, 80);
the_list.InsertColumn(2, L"Modified");
the_list.SetColumnWidth(2, 80);
the_list.InsertColumn(3, L"Type");
the_list.SetColumnWidth(3, 80);
the_list.InsertColumn(4, L"Description");
the_list.SetColumnWidth(4, 80);
UINT ii = 0;
for (const FileInfo &fi: program_state.file_list) {
AddData(the_list, ii, 0, fi.filename.c_str());
AddData(the_list, ii, 1, fi.filesize.c_str());
AddData(the_list, ii, 2, L"NYI");
AddData(the_list, ii, 3, fi.filetype.c_str());
AddData(the_list, ii, 4, L"");
ii++;
}
}

其中FileInfo只是一个容器(应该是一个结构):

class FileInfo {
public:
FileInfo() : n_filesize(0), epoch_ms(0), is_dir(false) {};
virtual ~FileInfo() {
}
std::wstring filename;
std::wstring ext;
std::wstring fqfilename;
std::wstring filesize;
size_t       n_filesize;
__int64      epoch_ms;
std::wstring mod_date;
std::wstring filetype;
std::wstring description;
std::wstring properties;
bool is_dir;
};

并且program_state.file_list被这样声明:

class ProgramState {
public:
// ...
std::vector<FileInfo> file_list;
// ...
};

我已经浏览了CListViews上的MS页面,WIN32 ListViews AKA WC_LISTVIEW,它们的风格和;扩展的样式,并且找不到有关此行为的任何信息:

  • https://learn.microsoft.com/en-us/cpp/mfc/reference/clistview-class?view=msvc-160

  • https://learn.microsoft.com/en-us/windows/win32/controls/list-view-controls-overview

  • https://learn.microsoft.com/en-us/windows/win32/controls/extended-list-view-styles

  • https://learn.microsoft.com/en-us/windows/win32/msi/listview-control

。。。还有一些太多了,无法列举。

就好像这种行为太好了,没有人会想禁用它:-)

在类中,您应该处理LVN_KEYDOWN列表通知消息。

BEGIN_MESSAGE_MAP(MyCFileListView, CView)
...
ON_NOTIFY(LVN_KEYDOWN, IDC_MY_LIST, &MyCFileListView::OnListKeyDown)
...
END_MESSAGE_MAP()

在处理程序方法中,您可以过滤您想要的任何密钥:

void MyCFileListView::OnListKeyDown(NMHDR* pNMHDR, LRESULT* pResult)
{
const auto pKey = reinterpret_cast<NMLVKEYDOWN*>(pNMHDR);
if (pKey->wVKey != VK_UP || pKey->wVKey != VK_DOWN)
{
...
}
...
}

我希望你明白了。

最新更新