65.9K
CodeProject 正在变化。 阅读更多。
Home

为控制台创建带有组合框的输入

starIconstarIconstarIcon
emptyStarIcon
starIcon
emptyStarIcon

3.89/5 (4投票s)

2005年1月25日

CPOL

3分钟阅读

viewsIcon

49305

downloadIcon

1170

使用组合框作为控制台输入字段的简单方法

引言

我正在制作一个应用程序,它有一个类似于 AutoCAD 中的控制台。我希望命令在一个 ComboBox 中输入,该控件在下拉列表中保持历史记录。通过按下 Enter 键并在其中输入或从下拉列表中选择一个命令来执行命令。用户还应该能够使用箭头键来滚动浏览以前的命令。这类似于视频游戏(如半条命 2)中的控制台。

问题

使用常规的 CComboBox,在用户按下 Enter 键时执行操作比较困难。当按下 Enter 键时,我希望该命令被放入 combobox 的历史记录(下拉列表)中,并且该命令被解析和执行。此外,我注意到当用户按下箭头键来滚动浏览以前的命令时,他们无法返回到他们正在处理的原始命令。最重要的是,当按下向上箭头键时,它会选择下拉列表中的上一个命令,但当您再次按下它时,它什么也不做。

解决方案

首先,我从 CComboBox 派生了一个名为 CConsoleCombo 的类。我添加了成员变量 CString m_currentint m_nPosm_current 保存用户正在处理的命令,以便他们可以随时返回到该命令,即使他们滚动浏览了以前的命令。 m_nPos 是用户滚动到的历史记录中的当前位置。我必须手动跟踪此位置。我做的下一件事是重写 CComboBoxPreTranslateMessage() 函数。重写的函数如下所示

BOOL CConsoleCombo::PreTranslateMessage(MSG* pMsg) 
{
  // TODO: Add your specialized code here 
  // and/or call the base class

  if (pMsg->message == WM_KEYDOWN)
  {
     CString str;
     int nVirtKey = (int) pMsg->wParam;

     switch (nVirtKey)
     {
     //checks if up arrow key is pressed
     case VK_UP:

        //if this is first position 
        // save current text
        if (m_nPos == -1)
        {
            GetWindowText(str);
            m_current = str;
        }

        //makes sure an invalid position 
        // isn't going to be set
        if (m_nPos + 1 < GetCount())
        {
            //increase position
            m_nPos++;
            //get text at current position 
            // display it highlighted
            GetLBText(m_nPos, str);
            SetWindowText(str);
            SetEditSel(0, str.GetLength());
        }

        return TRUE;
        
      case VK_DOWN:
            
         //if going back to bottom restore 
         // previously entered text
         if (m_nPos - 1 == -1)
         {
            SetWindowText(m_current);
            SetEditSel(m_current.GetLength(), 
                          m_current.GetLength());
            m_nPos = -1;
         }

         if (m_nPos - 1 >= 0)
         {
            //decrease position
            m_nPos--;
            //get text at current position 
            // display it highlighted
            GetLBText(m_nPos, str);
            SetWindowText(str);
            SetEditSel(0, str.GetLength());
         }
         return TRUE;
        
       //if enter key is pressed do following
       case VK_RETURN:

         GetWindowText(str);

         //make sure there is something input
         if (str != "")
         {
            //add string to the bottom of the list
            InsertString(0, str);
            m_nPos = -1;
            SetWindowText("");

            //function that must be customized 
            // for each program
            ParseCommand(str);

         }
       break;
     }
  }

  return CComboBox::PreTranslateMessage(pMsg);
}

该函数检查 Windows 消息是否为 WM_KEYDOWN。然后,如果是并且按下向下键,则向下移动位置 (m_nPos)。对于向上键,它会向上移动位置。当第一次按下向上键时,会存储当前命令 (m_current)。当按下向下键并且回到起始位置时,会恢复当前命令。滚动浏览以前的命令会将它们显示为 ComboBox 文本字段中选定的命令。如果 WM_KEYDOWNwParamEnter 键并且文本字段中有一个命令,则该命令将被添加到历史记录中,清除文本字段,并执行 ParseCommand() 函数。这是一个 virtual 成员函数,将在本文的使用代码部分中进行解释。

Using the Code

要有效地使用这个类,最好从中派生一个类。在演示中,这个类是 CInput。然后,您必须重写 ParseCommand(CString command) 函数。在此函数中,添加要执行的自定义代码。例如,解析命令字符串并执行其指令。为了简单起见,在演示中,此函数所做的只是将自定义用户消息 (WM_CCOMMAND) 发送到对话框,并将命令放在其 wParam 中。然后,对话框获取此命令并将其添加到只读编辑框中(此编辑框也是一个自定义控件,请查看我的文章“更改只读编辑控件的背景颜色”)。这是所有控制台都执行的任务。这也是用户消息的一个简洁而简单的示例。

注意:附加到本文的演示程序有一个对话框,其中包含一个编辑框和两个 ComboBox。一个是正常的,而另一个是 CConsoleCombo。我同时放了这两个来显示它们的比较。它们都将 string 添加到编辑框中,但对于正常的 combobox,您必须点击 添加 按钮。

历史

  • 2005 年 1 月 25 日 - 初始发布
© . All rights reserved.