Highlight view with focus

Many times it would be nice to have some visual feedback as to which pane in a split view currently has the focus. This is very useful if you have multiple view types and different keyboard strokes cause different actions in each.

NOTE: This uses an undocumented feature in MFC so be careful in the future.

Step 1) Derive your own SplitterWnd class.
Step 2) Override the undocumented OnDrawSplitter function.
Step 3) Replace the CSplitterWnd instance in the child frame with your splitter.

This example draws in red but you can adjust the color and width of the frame by altering the define values.
///////////////////////////////////////////////////////////////////////////// 
// MySplitterWnd.h

class MySplitterWnd : public CSplitterWnd
{
public: 
	int cRow;
	int cCol; 
	MySplitterWnd();
	void OnDrawSplitter(CDC* pDC, ESplitType nType,
		const CRect& rectArg);
	void RefreshSplitBars(void);
};



///////////////////////////////////////////////////////////////////////////// 
// MySplitterWnd.cpp

#include "StdAfx.h"
#include "MySplitterWnd.h"

#define FOCUS_HILIGHT_COLOR_ULO RGB(180, 75, 25)
#define FOCUS_HILIGHT_COLOR_LRO RGB(245, 5, 25)
#define FOCUS_HILIGHT_COLOR_ULI RGB(145, 95, 75)
#define FOCUS_HILIGHT_COLOR_LRI RGB(220, 65, 40)

#define FOCUS_HILIGHT_SHOW TRUE

#define SPLITTER_CX 4
#define SPLITTER_CY 4
#define SPLITTER_GAPX 4
#define SPLITTER_GAPY 4

void MySplitterWnd::RefreshSplitBars(void)
{
	CRect rectInside;

	GetInsideRect(rectInside);
	DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
}


MySplitterWnd::MySplitterWnd()
{
	cRow = 0;
	cCol = 0; 
	
	m_cxSplitter = SPLITTER_CX;
	m_cySplitter = SPLITTER_CY;
	m_cxSplitterGap = SPLITTER_GAPX;
	m_cySplitterGap = SPLITTER_GAPY;
}


void MySplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
{
	if((FOCUS_HILIGHT_SHOW) && ((GetRowCount()>1) || (GetColumnCount()>1)) && (nType == splitBorder))
	{
		int pRow = 0;
		int pCol = 0;
		if(rectArg.top)
		{
			pRow = 1;
		}
		if(rectArg.left)
		{
			pCol = 1;
		}
		if((cRow == pRow) && (cCol == pCol))
		{
			if (pDC == NULL)
			{
				RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
				return; 
			}
			ASSERT_VALID(pDC);
			CRect rect = rectArg;
			pDC->Draw3dRect(rect, FOCUS_HILIGHT_COLOR_ULO, FOCUS_HILIGHT_COLOR_LRO);
			rect.InflateRect(-GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
			pDC->Draw3dRect(rect, FOCUS_HILIGHT_COLOR_ULI, FOCUS_HILIGHT_COLOR_LRI);
			return; 
		}
	}
	
	CSplitterWnd::OnDrawSplitter(pDC,nType,rectArg); 
}



Comments

  • simpler solution

    Posted by Legacy on 08/20/2001 12:00am

    Originally posted by: Alan Kang

    Simply override CSplitterWnd::RecalcLayout - Works 
    
    with all sub-panes. You would still need to call
    SetRowInfo and SetColumnInfo as necessary but there is
    no need to do anything else

    void CSplitterWndEx::RecalcLayout()
    {
    CSplitterWnd::CRowColInfo* pInfo = m_pColInfo;
    CSplitterWnd::CRowColInfo* pInfoNext = pInfo;
    for (int i = 0; i < m_nCols - 1 && pInfo->nCurSize > -1; i++)
    {
    // Check next column
    int nXDiff = (++pInfoNext)->nMinSize -
    (pInfoNext->nCurSize - (pInfo->nIdealSize - pInfo->nCurSize));

    // Adjust the resizing step so that the size of the next col
    // will be at least its min size
    if (nXDiff > 0) pInfo->nIdealSize -= nXDiff;

    // Adjust the resizing step so that the size of this col
    // will be at least its min size
    pInfo->nIdealSize = max(pInfo->nIdealSize, pInfo->nMinSize);
    }

    pInfoNext = pInfo = m_pRowInfo;
    for (i = 0; i < m_nRows - 1 && pInfo->nCurSize > -1; i++)
    {
    // Check next row
    int nYDiff = (++pInfoNext)->nMinSize -
    (pInfoNext->nCurSize - (pInfo->nIdealSize - pInfo->nCurSize));

    // Adjust the resizing step so that the size of the next row
    // will be at least its min size
    if (nYDiff > 0) pInfo->nIdealSize -= nYDiff;

    // Adjust the resizing step so that the size of this row
    // will be at least its min size
    pInfo->nIdealSize = max(pInfo->nIdealSize, pInfo->nMinSize);
    }
    CSplitterWnd::RecalcLayout();
    }


    Reply
  • "total solution" improvements

    Posted by Legacy on 10/12/2000 12:00am

    Originally posted by: Hans-Georg Ulrich

    The "total solution" by Jiang Fan works, but ...
    
    - generates heavy flicker due to RedrawWindow
    - has some problems with more than 2 panes.

    Improvement: replace SetHighlight,
    and overwrite SetActivePane to call SetHighlight.

    --------------------------------------------------------

    void CSplitter::SetHighlight()
    {
    CWnd *pAct = GetActivePane();
    if(pAct && m_hwndAct != pAct->m_hWnd ) {
    // active pane changed
    m_hwndAct = pAct->m_hWnd;

    CPaintDC dc(this);
    CRect rectInside;
    GetInsideRect(rectInside);
    // CSplitterWnd::GetInsideRect -
    // undocumented public function
    // returns size of SplitterWnd minus size of scroll bars,
    // if any

    // CSplitterWnd::DrawAllSplitBars -
    // undocumented public function
    // Called with DeviceContext, it draws the frames.
    // Called with DeviceContext=NULL, it does a RedrawWindow
    // to make the changes visible

    DrawAllSplitBars(&dc,rectInside.right,rectInside.bottom);
    DrawAllSplitBars(NULL,rectInside.right,rectInside.bottom);

    //RedrawWindow(); // generates too much flicker
    }
    }

    // Do not forget to define this in the header
    void CSplitter::SetActivePane
    ( int row, int col, CWnd* pWnd /*= NULL*/ )
    {
    SplitterWnd::SetActivePane( row, col, pWnd);
    SetHighlight();
    }

    Reply
  • Total Solution

    Posted by Legacy on 03/19/1999 12:00am

    Originally posted by: Jiang Fan

    #if !defined(AFX_MYSPLITTERWND_H__138E6707_DE1A_11D2_BD45_0000F8771AA3__INCLUDED_)
    
    #define AFX_MYSPLITTERWND_H__138E6707_DE1A_11D2_BD45_0000F8771AA3__INCLUDED_

    #if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000
    // MySplitterWnd.h : header file
    //

    /////////////////////////////////////////////////////////////////////////////
    // CMySplitterWnd window

    class CMySplitterWnd : public CSplitterWnd
    {
    // Construction
    public:
    CMySplitterWnd();
    void SetHighlight();
    // Attributes
    public:
    HWND m_hwndAct;
    // Operations
    public:

    // Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CMySplitterWnd)
    protected:
    virtual BOOL OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult);
    virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
    //}}AFX_VIRTUAL

    // Implementation
    public:
    virtual ~CMySplitterWnd();
    virtual void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg);
    // Generated message map functions
    protected:
    //{{AFX_MSG(CMySplitterWnd)
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };

    /////////////////////////////////////////////////////////////////////////////

    //{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.

    #endif // !defined(AFX_MYSPLITTERWND_H__138E6707_DE1A_11D2_BD45_0000F8771AA3__INCLUDED_)


    // MySplitterWnd.cpp : implementation file
    //

    #include "stdafx.h"
    #include "ftms20.h"
    #include "MySplitterWnd.h"

    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif

    /////////////////////////////////////////////////////////////////////////////
    // CMySplitterWnd

    CMySplitterWnd::CMySplitterWnd()
    {
    m_hwndAct = NULL;
    }

    CMySplitterWnd::~CMySplitterWnd()
    {
    }


    BEGIN_MESSAGE_MAP(CMySplitterWnd, CSplitterWnd)
    //{{AFX_MSG_MAP(CMySplitterWnd)
    //}}AFX_MSG_MAP
    END_MESSAGE_MAP()


    /////////////////////////////////////////////////////////////////////////////
    // CMySplitterWnd message handlers

    void CMySplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
    {
    CSplitterWnd::OnDrawSplitter(pDC, nType, rectArg);
    CWnd *pAct = GetActivePane();
    if(pDC && pAct && !pAct->IsKindOf( RUNTIME_CLASS( CSplitterWnd)) && nType == splitBorder)
    {
    CRect rect;
    pAct->GetWindowRect(&rect);
    pDC->GetWindow()->ScreenToClient(&rect);
    if(rectArg.PtInRect(rect.CenterPoint()))
    {
    ASSERT_VALID(pDC);
    rect = rectArg;
    pDC->Draw3dRect(rect, GetSysColor( COLOR_HIGHLIGHT),GetSysColor( COLOR_HIGHLIGHT));
    rect.InflateRect(-GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
    pDC->Draw3dRect(rect, GetSysColor( COLOR_HIGHLIGHT),GetSysColor( COLOR_HIGHLIGHT));
    }

    }

    }

    BOOL CMySplitterWnd::OnNotify(WPARAM wParam, LPARAM lParam, LRESULT* pResult)
    {
    SetHighlight();
    return CSplitterWnd::OnNotify(wParam, lParam, pResult);
    }

    void CMySplitterWnd::SetHighlight()
    {
    CWnd *pAct = GetActivePane();
    if(pAct && m_hwndAct != pAct->m_hWnd )
    {
    m_hwndAct = pAct->m_hWnd;
    RedrawWindow();
    }
    }

    BOOL CMySplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam)
    {
    SetHighlight();
    return CSplitterWnd::OnCommand(wParam, lParam);
    }

    Reply
  • Get highlight splitterWnd when I click on mouse on view

    Posted by Legacy on 02/28/1999 12:00am

    Originally posted by: sikong

    get highlight active pane...
    
    

    I used Randy More's source..
    You do first see Randy More's source.

    I changed his source.
    I checked "<--" mark for changing..

    /////////////////////////
    void MySplitterWnd::OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg)
    {
    int x_ActivePane, y_ActivePane; // <---
    GetActivePane(x_ActivePane, y_ActivePane); // <--
    TRACE("%d, %d\n", x_ActivePane, y_ActivePane);

    if((FOCUS_HILIGHT_SHOW) && ((GetRowCount()>1) || (GetColumnCount()>1)) && (nType == splitBorder))
    {
    int pRow = 0;
    int pCol = 0;
    if(rectArg.top)
    {
    pRow = 1;
    }
    if(rectArg.left)
    {
    pCol = 1;
    }
    if((pCol == y_ActivePane) && (pRow == x_ActivePane)) // <--
    {
    if (pDC == NULL)
    {
    RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
    return;
    }
    ASSERT_VALID(pDC);
    CRect rect = rectArg
    pDC->Draw3dRect(rect, FOCUS_HILIGHT_COLOR_ULO, FOCUS_HILIGHT_COLOR_LRO);
    rect.InflateRect(-GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
    pDC->Draw3dRect(rect, FOCUS_HILIGHT_COLOR_ULI, FOCUS_HILIGHT_COLOR_LRI);
    return;
    }
    }

    CSplitterWnd::OnDrawSplitter(pDC,nType,rectArg);
    }

    ///////////////////
    I add the Focus checking routine of View.
    this is left pane

    void CMyTree::OnSetFocus(CWnd* pOldWnd)
    {
    CTreeView::OnSetFocus(pOldWnd);

    // TODO: Add your message handler code here
    ((CMainFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
    }

    void CMyTree::OnKillFocus(CWnd* pNewWnd)
    {
    CTreeView::OnKillFocus(pNewWnd);

    // TODO: Add your message handler code here
    ((CMainFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
    }

    //////

    and this is right pane


    void MyRightView::OnSetFocus(CWnd* pOldWnd)
    {
    CEditView::OnSetFocus(pOldWnd);

    // TODO: Add your message handler code here
    ((CMainFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
    TRACE("right get");
    }

    void MyRightView::OnKillFocus(CWnd* pNewWnd)
    {
    CEditView::OnKillFocus(pNewWnd);

    // TODO: Add your message handler code here
    ((CMainFrame*)GetParentFrame())->m_wndSplitter.RefreshSplitBars();
    TRACE("right kill");
    }

    thanks..


    Reply
  • How can I do if i want to get highlight splitterWnd when I click on mouse on view ?

    Posted by Legacy on 01/28/1999 12:00am

    Originally posted by: hg Choi

    hi.
    I called CMySplitterWnd , When WM_LBUTTONDOWN in view?
    but, it's not executed.


    How can I do if i want to get highlight splitterWnd when I click on mouse on view ?

    Thanks

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • As all sorts of data becomes available for storage, analysis and retrieval - so called 'Big Data' - there are potentially huge benefits, but equally huge challenges...
  • The agile organization needs knowledge to act on, quickly and effectively. Though many organizations are clamouring for "Big Data", not nearly as many know what to do with it...
  • Cloud-based integration solutions can be confusing. Adding to the confusion are the multiple ways IT departments can deliver such integration...

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date