Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Creating an Input for a Console using a Combo Box

0.00/5 (No votes)
25 Jan 2005 1  
A simple way to use a combo box for an input field for a console

Introduction

I am making an application that has a console similar to the one found in AutoCAD. I want the commands to be input in a ComboBox that keeps a history in the dropdown. Commands are implemented by pressing the Enter key with a command typed in or selected from the dropdown. The user should also be able to use the arrow keys to scroll through previous commands. This is similar to consoles in video games such as Half-Life 2.

The Problem

With the regular CComboBox, it is difficult to do an action when the user hits the Enter key. When the Enter key is pressed, I want the command to be put into the combobox's history (the dropdown) and the command to be parsed and implemented. Also, I noticed that when a user presses the arrow keys to scroll through previous commands, they cannot go back to the original command they were working on. On top of that, when the up arrow key is pressed, it selects the previous command in the dropdown but when you press it again, it does nothing.

The Solution

First of all, I derived a class from CComboBox called CConsoleCombo. I added member variables, CString m_current and int m_nPos. m_current holds the command the user is working on so if they scroll through their previous commands, they can always come back to it. m_nPos is the current position in the history the user has scrolled to. I have to keep track of this position manually. The next thing I did was to override CComboBox's PreTranslateMessage() function. The overridden function looks like this:

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);
}

The function checks if the Windows message is WM_KEYDOWN. Then if it is and the down key is pressed, it moves the position down (m_nPos). For the up key, it moves the position up. When the up key is first pressed, the current command is stored (m_current). When the down key is pressed and it is back to the starting position, the current command is restored. Scrolling through previous commands displays them selected in the ComboBox's text field. If the WM_KEYDOWN's wParam is the Enter key and there is a command in the text field then that command is added to the history, the text field is cleared, and the ParseCommand() function is performed. This is a virtual member function which is explained in the Using the Code section of this article.

Using the Code

To use this class effectively, it is best to derive a class from it. In the demo, this class is CInput. You must then override the ParseCommand(CString command) function. In this function, you add the custom code you want to perform. For instance, parsing the command string and carrying out its instructions. For the sake of simplicity, in the demo, all this function does is to send a custom user message (WM_CCOMMAND) to the dialog with the command in its wParam. The dialog then takes this command and adds it to a read only edit box (this edit box is a custom control as well, check out my article 'Changing the background color of a read-only edit control'). This is a task that all consoles perform. This is also a neat and simple example of user messages.

Note: The demo attached to this article has a dialog with an edit box and two ComboBoxes. One is normal while the other one is a CConsoleCombo. I have put both to show a comparison of the two. They both add strings to the edit box but for the normal combobox, you must hit the Add button.

History

  • 25th January, 2005 - Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here