【问题标题】:MFC CListView how to prevent search & auto-selection when user types letters?当用户键入字母时,MFC CListView 如何防止搜索和自动选择?
【发布时间】:2021-09-12 20:53:08
【问题描述】:

TL;DR

在 C++ MFC CListView 中,当 CListView 具有键盘焦点时,如何防止根据用户键入的字母进行自动选择?

情况:

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

ie:如果我键入“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;
   // ...
};

我浏览过 MS 在 CListViews、WIN32 ListViews AKA WC_LISTVIEW、它们的样式和扩展样式上的页面,但找不到任何关于此行为的信息:

...以及其他太多,无法一一列举。

就好像这种行为非常好,以至于没有人愿意禁用它:-)

【问题讨论】:

    标签: c++ mfc message-loop clistview


    【解决方案1】:

    在您的班级中,您应该处理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)
       {
           ...
       }
    ...
    }
    

    我希望你明白了。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-04
      • 2015-02-17
      • 1970-01-01
      • 2021-01-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多