在做一个MFC软件的时候有一个这样的需求,就是要有类似与AutoCad的命令输入框,如下图所示:
本着不重写已有功能的原则,在MFC中发掘了一圈,没发现有可用的现成控件,上网搜了一下,发现有人做过,但竟然还收费出售,so faint,只能自己动手做一个。
其实思路还是蛮简单的,就是放个Edit控件处理它的键盘输入事件,防止删除之前的记录和提示信息,还要处理结束命令,比如回车、空格之类的。主要有以下几个步骤:
1. 将输入框内的字符串分段,比如分成三段log, tip和command,前两段都不能被修改,command的内容为可修改的。在结束了command输入后,要同步各字符串,示例代码如下:
void CMainFrame::InitCommand(CString tip)
{
// 记录老字符串,类似于UpdateData(true)
this->GetText();
// 设置新的log
if(this->m_log != "")
    this->m_log += "\r\n";
this->m_log += tip;
// 更新字符串,类似与UpdataData(false)
this->SetText();
// 将光标置于字符串的尾部(否则光标会在一开始的位置)
((CEdit *)m_commandDialogBar.GetDlgItem(IDC_COMMAND))->SetSel(this->m_log.GetLength(),    
    this->m_log.GetLength());
}
 
2. 重载PreTranslateMessage事件,处理键盘信息,示例代码如下:
BOOL CMainFrame::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message == WM_KEYDOWN) // 处理键盘按下事件
{
    // 判断是否是在脚本输入框上输入的
    if(GetFocus() == m_commandDialogBar.GetDlgItem(IDC_COMMAND))
    {
     // 如果选择的是非正在输入的文字,抛弃这个事件
     DWORD selectedRegion = ((CEdit *)m_commandDialogBar.GetDlgItem(IDC_COMMAND))->GetSel();
     int selectedStart = LOWORD(selectedRegion);
     int selectedEnd     = HIWORD(selectedRegion);
     if(selectedStart != selectedEnd && selectedStart < m_log.GetLength())
        return true;
     if(pMsg->wParam == 8 && selectedStart <= m_log.GetLength()) // 阻止删除之前的文字
        return true;
     if(pMsg->wParam == 13 || pMsg->wParam == 32) // 当输入空格或回车是发送消息
        this->SendCommand();
    }
}
return CMDIFrameWnd::PreTranslateMessage(pMsg);
}
 
其中SendCommand的内容可自定义,处理完成后不要忘记执行1的操作,同步一下字符串就OK。实现效果如下:
当然,这是一个最简单的实现,还有很多问题没有处理,比如自定义菜单,屏蔽系统菜单等;还有很多工作可以做,比如封装成一个自定义控件,做更好的显示效果等等。但基本的思路还是一样的,恩,如果谁有更好的实现方案,也欢迎留言,谢谢先:)