This can be done using a CExtScrollWnd
-derived class (e.g., CExtGridWnd
demonstrated in the AdoRecordsetView sample), the CExtScrollBar
class, and the CExtToolControlBar
class.
The CExtScrollWnd
class implements a scrollable window which can use either built-in window scroll bars in the non-client area of the window or external scroll bar windows. The latter can be used when you need to implement some kind of non-standard scroll bars, i.e. those that have some controls at left/right side of the horizontal scroll bar or at top/bottom side of the vertical scroll bar. CExtScrollBar
is handy in this case because it is able to stick to the borders of the CExtScrollWnd
window automatically and it also supports two HWND
properties: m_hWndBefore
and m_hWndAfter
. These properties can be NULL
or handles to child windows of a CExtScrollWnd
-based window. The CExtScrollBar
window aligns them automatically. The m_hWndBefore
window is placed at the left side of the horizontal scroll bar or at the top side of the vertical scroll bar. The m_hWndAfter
window is placed at the right side of the horizontal scroll bar or at the bottom side of the vertical scroll bar.
We recommend you use an improved version of the Prof-UIS toolbar for implementing buttons in the same row as the horizontal scroll bar. Here is the source code for this class:class CInplaceToolbarWnd : public CExtToolControlBar
{
class TinyButton : public CExtBarButton
{
public:
TinyButton(
CExtToolControlBar * pBar = NULL,
UINT nCmdID = ID_SEPARATOR,
UINT nStyle = 0
)
: CExtBarButton(
pBar,
nCmdID,
nStyle
)
{
}
virtual CSize CalculateLayout(
CDC & dc,
CSize sizePreCalc,
BOOL bHorz
)
{
ASSERT_VALID( this );
dc;
sizePreCalc;
bHorz;
return CSize( 13, 13 );
}
}; // class TinyButton
protected:
virtual LRESULT WindowProc(
UINT message,
WPARAM wParam,
LPARAM lParam
)
{
ASSERT_VALID( this );
if( message == WM_NCCALCSIZE )
return 0L;
if( message == WM_SIZEPARENT )
return 0L;
return
CExtToolControlBar::
WindowProc( message, wParam, lParam );
}
virtual CExtBarContentExpandButton *
OnCreateBarRightBtn()
{
ASSERT_VALID( this );
return NULL;
}
virtual CExtBarButton *
OnCreateBarCommandBtn(
UINT nCmdID,
UINT nStyle = 0
)
{
ASSERT_VALID( this );
CExtBarButton * pTBB =
new TinyButton(
this, nCmdID, nStyle );
ASSERT_VALID( pTBB );
return pTBB;
}
};
NOTE: Please use 11x11 icons for toolbar buttons. Such a toolbar has a good, consistent look.
Your CExtScrollWnd
-derived class may look like: class CYourScrollableControl : public CExtScrollWnd
{
public:
CInplaceToolbarWnd m_wndToolBar;
CExtScrollBar m_wndScrollBarH, m_wndScrollBarV;
//{{AFX_VIRTUAL( CYourScrollableControl )
public:
virtual CScrollBar * GetScrollBarCtrl(int nBar) const;
protected:
virtual BOOL PreCreateWindow( CREATESTRUCT& cs );
//}}AFX_VIRTUAL
//{{AFX_MSG( CYourScrollableControl )
afx_msg int OnCreate( LPCREATESTRUCT lpCreateStruct );
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP( CYourScrollableControl, CExtScrollWnd )
//{{AFX_MSG_MAP( CYourScrollableControl )
ON_WM_CREATE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
CScrollBar * CYourScrollableControl::GetScrollBarCtrl(
int nBar
) const
{
ASSERT_VALID( this );
if( m_hWnd == NULL || (! ::IsWindow(m_hWnd) ) )
return NULL;
ASSERT( nBar == SB_HORZ || nBar == SB_VERT );
if( nBar == SB_HORZ )
{
if( m_wndScrollBarH.GetSafeHwnd() != NULL )
return ( const_cast < CExtScrollBar * >
( &m_wndScrollBarH ) );
}
else
{
if( m_wndScrollBarV.GetSafeHwnd() != NULL )
return ( const_cast < CExtScrollBar * >
( &m_wndScrollBarV ) );
}
return NULL;
}
BOOL CYourScrollableControl::PreCreateWindow(
CREATESTRUCT & cs
)
{
if( ! CExtScrollWnd::PreCreateWindow(
cs ) )
{
ASSERT( FALSE );
return FALSE;
}
cs.style &=
~(WS_BORDER);
cs.style |=
WS_CLIPSIBLINGS|WS_CLIPCHILDREN;
cs.dwExStyle &=
~(WS_EX_STATICEDGE|WS_EX_CLIENTEDGE);
return TRUE;
}
int CYourScrollableControl::OnCreate(
LPCREATESTRUCT lpCreateStruct
)
{
if( CExtScrollWnd::OnCreate(
lpCreateStruct
) == -1
)
{
ASSERT( FALSE );
return -1;
}
m_wndScrollBarH.m_eSO =
CExtScrollBar::__ESO_BOTTOM;
m_wndScrollBarV.m_eSO =
CExtScrollBar::__ESO_RIGHT;
if( ! m_wndScrollBarV.Create(
WS_CHILD
| WS_VISIBLE
| SBS_VERT
| SBS_RIGHTALIGN,
CRect(0,0,0,0),
this,
1
)
)
{
ASSERT( FALSE );
return -1;
}
if( ! m_wndScrollBarH.Create(
WS_CHILD
| WS_VISIBLE
| SBS_HORZ
| SBS_BOTTOMALIGN,
CRect(0,0,0,0),
this,
2
)
)
{
ASSERT( FALSE );
return -1;
}
m_wndScrollBarH.
SyncReservedSpace( &m_wndScrollBarV );
m_wndScrollBarV.
SyncReservedSpace( &m_wndScrollBarH );
if( (! m_wndToolbar.Create(
NULL,
this,
3,
WS_CHILD
| WS_VISIBLE
| CBRS_ALIGN_BOTTOM
| CBRS_TOOLTIPS
| CBRS_FLYBY
| CBRS_SIZE_DYNAMIC
) )
|| (! m_wndToolbar.LoadToolBar(
IDR_TOOLBAR_WITH_ICONS
) )
)
{
ASSERT( FALSE );
return -1;
}
m_wndToolbar.MoveWindow( 0, 0, 28, 1 );
m_wndScrollBarH.m_hWndAfter =
m_wndToolbar.GetSafeHwnd();
return 0;
}