您的位置:首页 > 其它

在状态栏实现如编辑控件的光标移动 (VC/MFC)

2009-06-26 02:44 344 查看

背景:


 

MFC提供给我们一个基础状态栏类:CStatusBar,当我们在状态栏内显示的内容比较长,比较多时,我们可以把某一个PANE得宽度扩大,以便可以显示长的内容,但是如果我们的每一个PANE都要显示很多内容,而且有5个以上的PANE,问题就出来了,我们很难在中间做一个平衡。

 

方法:


可以在状态栏的PANE上,实现一个光标移动功能, 这样当内容较长时,在这个PANE上面做光标左右移动来显示出不完整的内容。

 

双击某个PANE显示光标, 左右键实现左右移动并显示不完整内容,状态栏失去焦点和大小调整后PANE内容恢复原状光标消失。我们继承基础类CStatusBar来完成我们的功能。

 

代码:


class MStatusBar : public CStatusBar

{

    ...

    int m_nActiveIndex;  // current active pane's index

    int m_nPreActIndex;  // previous active pane's index

    CString m_szActPaneText;  // current active pane's text content 

    CString m_szPreActPaneText;  // prevous active pane's text content

    int m_nTextLeft;  // left position of the displayed pane text

    int m_nTextRight;  // right position of the displayed pane text

    ...

};

void MStatusBar::OnLButtonDblClk(UINT nFlags, CPoint point)

{

    CStatusBarCtrl& statusBar = GetStatusBarCtrl();

    int i = -1;

    CRect rectPane;

    CPoint ptTmp(point);

    //ScreenToClient(&ptTmp);

    int nCount = GetCount();

    while (++i < nCount)

    {

        statusBar.GetRect(i, rectPane);

        if (rectPane.PtInRect(ptTmp) )

        {

            m_nActiveIndex = i;

            if( m_nPreActIndex != m_nActiveIndex )

            {

                // restore the text of previous active pane

                if( m_nPreActIndex != -1 )

                {

                    SetText(m_nPreActIndex, m_szPreActPaneText);

                    SetPaneText(m_nPreActIndex, m_szPreActPaneText);

                }

                // update previous by now active

                m_nPreActIndex = m_nActiveIndex;

                m_szActPaneText = GetText(i);

                if( m_szActPaneText.IsEmpty() ) m_szActPaneText = GetPaneText(i);

                if( m_szActPaneText.IsEmpty() )

                {

                    m_szPreActPaneText=m_szActPaneText;

                    return;

                }

                m_szPreActPaneText = m_szActPaneText;

                // get indices of two ends of a string

                m_nTextRight = m_szActPaneText.GetLength();

                m_nTextLeft = 0;

                // create caret

                ::CreateCaret(this->m_hWnd, (HBITMAP)NULL, 2, rectPane.Height());

                ::SetCaretPos(rectPane.left, 2);

                ::ShowCaret(this->m_hWnd);

                SetFocus();

            }

        }

    }

    CStatusBar::OnLButtonDblClk(nFlags, point);

}

void MStatusBar::OnKillFocus( CWnd* pNewWnd )

{

    RestorePanes();

}

BOOL MStatusBar::PreTranslateMessage(MSG* pMsg )

{

    if( pMsg->message == WM_KEYDOWN )

    {

        if( pMsg->wParam == VK_LEFT )

        {

            SetCaretPosEx(CARET_DIR_LEFT);

            return TRUE;

        }

        else if( pMsg->wParam == VK_RIGHT )

        {

            SetCaretPosEx(CARET_DIR_RIGHT);

            return TRUE;

        }

    }

    return CStatusBar::PreTranslateMessage(pMsg);

}

当然用OnChar来处理是最合理的, 但是我的项目比较大,好像之前的一些窗口把这个消息给劫走了, 我抓不住这个消息, 所以只有用PreTranslateMessage了。

 

#define CARET_DIR_LEFT            1

#define CARET_DIR_RIGHT            2

/******************************************************

*Params: nDirection: 1:Left, 2:Right

******************************************************/

BOOL MStatusBar::SetCaretPosEx(UINT nDirection)

{

    CWindowDC wdc(this);

    // Getting font dimension

    TEXTMETRIC tm;

    wdc.GetTextMetrics(&tm);

    int cxChar = tm.tmAveCharWidth;

    // Moving string infos

    /*SIZE cDim;

    CString strOpt_1 = GetPaneText(m_nActiveIndex);

    CString strOpt_2 = GetPaneText(m_nActiveIndex);

    int nLength = strOpt_1.GetLength();

    ::GetTextExtentPoint32(wdc.m_hDC, strOpt_1, nLength, &cDim);*/

    //Getting rect of active pane

    CRect rectAPane;

    GetItemRect(m_nActiveIndex, &rectAPane);

    int nDisLgt = rectAPane.Width()/cxChar;

    CString strOpt;

    POINT pt;

    int xAPane = rectAPane.left;

    if( m_nActiveIndex != -1 )

    {

        switch( nDirection )

        {

        case CARET_DIR_LEFT:

        {

            ::GetCaretPos(&pt);

            xAPane = pt.x - cxChar;

            if( xAPane > rectAPane.left)

            {

                ::SetCaretPos(xAPane, pt.y);

            }

            else

            {

                xAPane = rectAPane.left+1;

                ::SetCaretPos(xAPane, pt.y);

               

                m_nTextLeft--;

                if( m_nTextLeft < 0) m_nTextLeft = 0;

                strOpt = m_szActPaneText.Mid(m_nTextLeft);

                SetText(m_nActiveIndex, strOpt);

                SetPaneText(m_nActiveIndex, strOpt);

               

            }

            break;

        }

        case CARET_DIR_RIGHT:

        {

            ::GetCaretPos(&pt);

            xAPane = pt.x + cxChar;

            if( xAPane < rectAPane.right )

            {

                ::SetCaretPos(xAPane, pt.y);

            }

            else

            {

                xAPane = rectAPane.right-1;

                ::SetCaretPos(xAPane, pt.y);

               

                if( (m_nTextRight-m_nTextLeft) > nDisLgt )

                    m_nTextLeft++;

                if( m_nTextLeft > m_nTextRight) m_nTextLeft = m_nTextRight;

                strOpt = m_szActPaneText.Mid(m_nTextLeft);

                SetText(m_nActiveIndex, strOpt);

                SetPaneText(m_nActiveIndex, strOpt);

               

            }

            break;

        }

        default:

            break;

        }

        return TRUE;

    }

    return FALSE;

}

void MStatusBar::RestorePanes()

{

    ::DestroyCaret();

    if( m_nActiveIndex != -1 )

    {

        SetText(m_nActiveIndex, m_szActPaneText);

        SetPaneText(m_nActiveIndex, m_szActPaneText);

    }

    if( m_nPreActIndex != -1 )

    {

        SetText(m_nPreActIndex, m_szPreActPaneText);

        SetPaneText(m_nPreActIndex, m_szPreActPaneText);

    }

    m_nActiveIndex = -1;

    m_nPreActIndex = -1;

    m_szActPaneText = "";

    m_szPreActPaneText = "";

}

void MStatusBar::OnSize( UINT nType, int cx, int cy )

{

    RestorePanes();

    CStatusBar::OnSize(nType, cx, cy);

}

[b]总结:


[/b]

不是很难, 关键在状态栏获取焦点, 得到字体尺寸,然后左右移动一个简单算法。

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  string mfc class 算法 null