【问题标题】:How to redirect a WM_KEYDOWN message to another control in MFC?如何将 WM_KEYDOWN 消息重定向到 MFC 中的另一个控件?
【发布时间】:2011-08-27 03:53:01
【问题描述】:

我今天对 MFC 很满意! :D

我有一个文本框和一个列表视图控件。

当用户在文本框中按下VK_UPVK_DOWN键时,我希望发生这种情况:

  1. 做一些事情。
  2. 让列表视图控件处理消息(以突出显示上一个/下一个项目)。
  3. 我希望列表视图环绕当前选择,如果按键是其顺序中的第一个
  4. 做更多的事情。

我尝试在我的对话框中对我的编辑框进行子类化:

class MyEditBox : public CWnd
{
    bool allowWrap;

    afx_msg void OnKeyUp(UINT, UINT, UINT) { this->allowWrap = true; }

    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
    {
        CListCtrl &listView = static_cast<CListView *>(
            this->GetParent()->GetDlgItem(IDC_LIST_VIEW))->GetListCtrl();

        if (nChar == VK_UP || nChar == VK_DOWN)
        {
            int iSelBefore = listView.GetNextItem(-1, LVNI_SELECTED);

            this->GetParent()->GetDlgItem(IDC_LIST_VIEW)
                ->OnKeyDown(nChar, nRepCnt, nFlags);  //Oops! Protected member :(

            int iSelAfter  = listView.GetNextItem(-1, LVNI_SELECTED);

            if (iSelBefore == iSelAfter &&  // Did the selection reach an end?
                this->allowWrap)            // If so, can we wrap it around?
            {
                int i = a == 0 ? listView.GetItemCount() - 1 : 0;
                listView.SetItemState(i, LVIS_SELECTED | LVIS_FOCUSED,
                                         LVIS_SELECTED | LVIS_FOCUSED);
            }
        }
        this->allowWrap = false;
    }
}

但是OnKeyDown() 是一个受保护的成员,所以我不能只在另一个控件上调用它。

有没有比使用SendMessage 手动发送命令更好 的方法来解决这个问题?我应该改变我的设计吗?子类化其他东西,等等?

【问题讨论】:

    标签: winapi visual-c++ mfc


    【解决方案1】:

    您的意图是在列表控件中选择上一个或下一个项目,对吧?然后您应该直接调用该方法来执行此操作,而不是要求CListCtrl“处理”您的消息。

    您可以调用CListCtrl::SetSelectionMarkCListCtrl::SetItemState 来选择下一个或上一个按键。示例:

     cListCtrl.SetSelectionMark(nIndex);
     cListCtrl.SetItemState(nIndex, LVIS_SELECTED | LVIS_FOCUSED, 0xFF);
    

    您可以处理 Key Down、Key Up 以及 Page Down、Page Up、End、Home 或编辑框中的任何键。不过,您需要进行计算。

    或者你也可以SendMessage。无需直接拨打OnKeyDown。让框架在您发送消息时为您调用它。

    【讨论】:

    • 我希望有更好的解决方案,因为调用SendMessage 需要我手动创建wParamlParam 参数。这很有可能,但我觉得应该有更好的方法。
    • 您的要求 (2) 是选择上一个或下一个项目,而不是自定义消息处理。我添加了代码来说明如何做到这一点。
    • 我有点困惑,这与我之前的评论有何关联,抱歉...
    • 当用户在编辑框上做某事时,您需要在列表控件上执行一些操作,对吧?
    • 是的,但我确实想告诉列表视图“选择上一项”。我希望它做出反应,但它通常会对向上/向下键(以及后来的 Page Up/Page Down 键)做出反应——我不想自己强加任何特定行为。
    【解决方案2】:

    我还看到了解决此问题的其他方法:

    1. CListCtrl 派生一个名为MyListCtrl 的类并选择以下两项之一:

      1.1 声明MyEditBox为好友,现在可以调用MyEditBox上的protected方法

      1.2 将公共方法CallOnKeyDown(...)CallOnKeyup(...) 添加到它只做需要的事情。

      并且在创建控件时,实例化 MyListCtrl 而不是 CListCtrl。还将您在此处显示的 listView 变量替换为 MyListCtrl 并使用您现在可用的方法

    2. 使用PreTranslateMessage(...)。我认为这种“锤子”的解决方案比发送消息更糟糕。

    【讨论】:

      猜你喜欢
      • 2010-11-01
      • 2021-01-27
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-16
      • 1970-01-01
      • 2015-11-12
      • 1970-01-01
      相关资源
      最近更新 更多