📄 treelistheaderctrl.cpp
字号:
// TreeListHeaderCtrl.cpp : implementation file
//
#include "stdafx.h"
#include "TreeListColumnInfo.h"
#include "TreeListDC.h"
#include "TLHDragWnd.h"
#include "TLHDropWnd.h"
#include "TreeListHeaderCtrl.h"
#include "TreeListTipCtrl.h"
#include "TreeListStaticCtrl.h"
#include "TreeListEditCtrl.h"
#include "TreeListComboCtrl.h"
#include "TreeListCtrl.h"
#include "TreeListResource.h"
#include "resource.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CTreeListHeaderCtrl
CTreeListHeaderCtrl::CTreeListHeaderCtrl() :
m_dwStyle( 0 ),
m_bSubclassFromCreate( FALSE ),
m_bOffScreenBuffer( TRUE ),
m_pImageList( NULL ),
m_pTreeListCtrl( NULL ),
m_hSize( NULL ),
m_hSplit( NULL ),
m_hArrow( NULL ),
m_bSplit( FALSE ),
m_bSizing( FALSE ),
m_bDraging( FALSE ),
m_nHeaderHeight( 0 ),
m_pDragWnd( NULL ),
m_pDropWnd( NULL )
{
// register window class
WNDCLASS wndclass;
HINSTANCE hInst = AfxGetInstanceHandle();
CTreeListResource TreeListResource;
if( !::GetClassInfo(hInst, TREELISTHEADERCTRL_CLASSNAME, &wndclass) )
{
wndclass.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
wndclass.lpfnWndProc = ::DefWindowProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInst;
wndclass.hIcon = NULL;
wndclass.hCursor = AfxGetApp()->LoadStandardCursor( IDC_ARROW );
wndclass.hbrBackground = (HBRUSH)COLOR_WINDOW;
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = TREELISTHEADERCTRL_CLASSNAME;
if (!AfxRegisterClass(&wndclass))
AfxThrowResourceException();
}
// default color
m_cr3DBkgnd = 0x808080;
m_cr3DFace = GetSysColor( COLOR_3DFACE );
m_cr3DLight = GetSysColor( COLOR_3DHILIGHT );
m_cr3DShadow = GetSysColor( COLOR_3DSHADOW );
m_crText = GetSysColor( COLOR_BTNTEXT );
// default font
m_Font.CreateStockObject( SYSTEM_FIXED_FONT );
// load cursors
m_hSize = AfxGetApp()->LoadCursor( IDC_CURSOR_SIZE );
m_hSplit = AfxGetApp()->LoadCursor( IDC_CURSOR_SPLIT );
m_hArrow = AfxGetApp()->LoadStandardCursor( IDC_ARROW );
}
CTreeListHeaderCtrl::~CTreeListHeaderCtrl()
{
// free font
if( m_Font.m_hObject != NULL )
m_Font.DeleteObject();
// free cursors
if( m_hSize != NULL )
DestroyCursor( m_hSize );
if( m_hSplit != NULL )
DestroyCursor( m_hSplit );
if( m_hArrow != NULL )
DestroyCursor( m_hArrow );
}
BEGIN_MESSAGE_MAP(CTreeListHeaderCtrl, CWnd)
//{{AFX_MSG_MAP(CTreeListHeaderCtrl)
ON_WM_ERASEBKGND()
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDBLCLK()
ON_WM_CANCELMODE()
ON_WM_RBUTTONDOWN()
ON_WM_RBUTTONUP()
ON_WM_RBUTTONDBLCLK()
//}}AFX_MSG_MAP
ON_MESSAGE(HDM_LAYOUT, OnLayout)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CTreeListHeaderCtrl message handlers
BOOL CTreeListHeaderCtrl::Create()
{
// create sort image
if( !m_imgSort.Create( IDB_TREELIST_SORT, 8, 4, 0xFF00FF ) )
return FALSE;
// create header image
if( !m_imgHeader.Create( IDB_TREELIST_HEADER, 16, 4, 0xFF00FF ) )
return FALSE;
m_pImageList = &m_imgHeader;
return TRUE;
}
BOOL CTreeListHeaderCtrl::Create( DWORD dwStyle, const RECT& rect, CTreeListCtrl* pParentWnd, UINT nID )
{
// create window
ASSERT_VALID( pParentWnd );
m_dwStyle = dwStyle;
m_pTreeListCtrl = pParentWnd;
m_bSubclassFromCreate = TRUE;
dwStyle |= WS_CHILD | WS_VISIBLE | WS_EX_TRANSPARENT;
if( !CWnd::Create( TREELISTHEADERCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID ) )
return FALSE;
if( !Create() )
return FALSE;
return TRUE;
}
void CTreeListHeaderCtrl::SetHeaderFont()
{
// set font
CWnd* pWnd = GetParent();
CTreeListCtrl* pTreeListCtrl = (CTreeListCtrl*)pWnd;
if( pTreeListCtrl != NULL )
{
CFont* pFont = pTreeListCtrl->GetFont();
if( pFont != NULL )
{
LOGFONT lf;
pFont->GetLogFont( &lf );
m_Font.DeleteObject();
m_Font.CreateFontIndirect( &lf );
}
}
}
CFont* CTreeListHeaderCtrl::GetHeaderFont()
{
// get font
return &m_Font;
}
int CTreeListHeaderCtrl::SetHeaderHeight( int nHeight )
{
// set header height
int nOldHeight = m_nHeaderHeight;
if( nHeight == -1 )
{
ASSERT( m_Font.m_hObject != NULL );
LOGFONT lf;
m_Font.GetLogFont( &lf );
if( lf.lfHeight > 0 )
{
m_nHeaderHeight = lf.lfHeight + 6;
}
else if( lf.lfHeight == 0 )
{
m_nHeaderHeight = DEFAULT_HEIGHT;
}
else
{
m_nHeaderHeight = -lf.lfHeight + 6;
}
}
else
{
m_nHeaderHeight = nHeight;
}
return nOldHeight;
}
int CTreeListHeaderCtrl::GetHeaderHeight()
{
// get header height
if( !(GetStyle()&TLHS_SHOWHEAD) )
return 0;
return m_nHeaderHeight;
}
int CTreeListHeaderCtrl::GetHeaderWidth()
{
// get header width
ASSERT( m_pTreeListCtrl != NULL );
return m_pTreeListCtrl->GetWidth();
}
BOOL CTreeListHeaderCtrl::GetHeaderRect( CRect& rcHeader, int iCol )
{
// get header rect
CPtrArray& arColumns = m_pTreeListCtrl->m_arColumns;
CArray<int,int>& arShows = m_pTreeListCtrl->m_arShows;
BOOL bFound = FALSE;
int nPerfix = 0;
for( int iShow=0; iShow<arShows.GetSize(); iShow++ )
{
CTreeListColumnInfo* pColumnInfo;
int iColumn = arShows[iShow];
pColumnInfo = (CTreeListColumnInfo*)arColumns[iColumn];
if( iColumn == iCol )
{
bFound = TRUE;
rcHeader.SetRect( 0, 0, pColumnInfo->m_nWidth, GetHeaderHeight() );
rcHeader.OffsetRect( nPerfix, 0 );
break;
}
nPerfix += pColumnInfo->m_nWidth;
}
return bFound;
}
BOOL CTreeListHeaderCtrl::OnEraseBkgnd(CDC* pDC)
{
// do not erase bkgnd
return TRUE;
}
void CTreeListHeaderCtrl::OnPaint()
{
// paint header control
CPaintDC dc(this);
if( m_bOffScreenBuffer )
{
CTreeListDC TreeListDC( &dc );
DrawCtrl( &TreeListDC );
}
else
{
DrawCtrl( &dc );
}
}
BOOL CTreeListHeaderCtrl::DrawCtrl( CDC* pDC )
{
// draw control
ASSERT_VALID( pDC );
CRect rcClip;
if( pDC->GetClipBox( &rcClip ) == ERROR )
return FALSE;
CRect rcClient;
GetClientRect( &rcClient );
if( m_pTreeListCtrl->GetStyle()&TLC_BKGNDCOLOR )
{
pDC->FillSolidRect( &rcClient, m_cr3DBkgnd );
}
else
{
pDC->FillSolidRect( &rcClient, m_cr3DFace );
pDC->Draw3dRect( &rcClient, m_cr3DLight, m_cr3DShadow );
}
DrawHeaders( pDC );
return TRUE;
}
BOOL CTreeListHeaderCtrl::DrawHeaders( CDC* pDC )
{
// draw every column headers
CPtrArray& Columns = m_pTreeListCtrl->m_arColumns;
CArray<int, int>& Shows = m_pTreeListCtrl->m_arShows;
// no columns or zero size
if( m_pTreeListCtrl->GetWidth() == 0 )
return TRUE;
int nWinPos = GetParent()->GetScrollPos( SB_HORZ );
// get client area
CRect rcClient;
GetClientRect( &rcClient );
// draw background
CRect rcFace;
rcFace.SetRect( 0, rcClient.top, GetHeaderWidth(), rcClient.bottom );
rcFace.OffsetRect( -nWinPos, 0 );
pDC->FillSolidRect( &rcFace, m_cr3DFace );
pDC->Draw3dRect( &rcFace, m_cr3DLight, m_cr3DShadow );
CTreeListColumnInfo* pColumnInfo;
int nHeaderPos = 0;
for( int iShow=0; iShow<Shows.GetSize(); iShow++, nHeaderPos += pColumnInfo->m_nWidth )
{
int iCol;
// do NOT draw zero column
iCol = Shows[iShow]; //*m_pShow[iShow];
pColumnInfo = (CTreeListColumnInfo*)Columns[iCol];
if( pColumnInfo->m_nWidth == 0 )
continue;
CRect rcHeader;
rcHeader.SetRect( 0, 0, pColumnInfo->m_nWidth, GetHeaderHeight() );
rcHeader.OffsetRect( -nWinPos, 0 );
rcHeader.OffsetRect( nHeaderPos, 0 );
// do NOT draw out of screen column
if( rcHeader.right < rcClient.left || rcHeader.left > rcClient.right )
continue;
DrawHeader( pDC, rcHeader, iCol );
}
return TRUE;
}
BOOL CTreeListHeaderCtrl::DrawHeader( CDC* pDC, CRect rcHeader, int iCol )
{
// draw one column header
CPtrArray& Columns = m_pTreeListCtrl->m_arColumns;
CArray<int, int>& Shows = m_pTreeListCtrl->m_arShows;
CArray<int, int>& Sorts = m_pTreeListCtrl->m_arSorts;
CTreeListColumnInfo* pColumn = (CTreeListColumnInfo*)Columns[iCol];
ASSERT( Shows.GetSize() > 0 );
// draw drag of columns
CRect rcBkgnd;
rcBkgnd = rcHeader;
if( rcBkgnd.Height() > 0 )
{
if( m_bDraging && iCol == m_iCol )
pDC->Draw3dRect( rcBkgnd, 0xFF0000, 0xFF0000 );
}
// draw gaps between columns
CRect rcGaps;
rcGaps = rcHeader;
rcGaps.DeflateRect( 0, 2, 0, 2 );
if( rcGaps.Height() > 0 )
{
pDC->IntersectClipRect( rcHeader );
pDC->IntersectClipRect( rcGaps );
if( !m_bDraging || iCol != m_iCol )
{
if( iCol != Shows[0] )
pDC->DrawEdge( rcGaps, BDR_RAISEDINNER, BF_LEFT );
if( iCol != Shows[Shows.GetUpperBound()] )
pDC->DrawEdge( rcGaps, BDR_RAISEDINNER, BF_RIGHT );
}
::ExtSelectClipRgn( pDC->m_hDC, DEFAULT_HRGN, RGN_COPY );
}
if( !m_bDraging || iCol != m_iCol)
rcHeader.DeflateRect( 0, 0, 1, 1 );
else
rcHeader.DeflateRect( 1, 1, 0, 0 );
rcHeader.DeflateRect( 2, 0, 3, 0 );
if( rcHeader.Width() <= 0 || rcHeader.Height() <= 0 )
return TRUE;
// draw sort arrow
int iSort = GetSortIndex( iCol );
if( pColumn->m_dwFormat&TLF_CAPTION_SORT && Sorts.GetSize()>0 )
{
CRect rcSort;
rcSort = rcHeader;
rcSort.left = rcSort.right - TLL_WIDTH/2;
POINT pt;
pt.x = rcSort.left;
pt.y = rcSort.top + ( rcSort.Height() - TLL_HEIGHT)/2;
pDC->IntersectClipRect( rcHeader );
pDC->IntersectClipRect( rcSort );
if( iSort == 0 )
{
// first sort column
ASSERT( pColumn->m_dwFormat&TLF_SORT_MASK );
if( pColumn->m_dwFormat&TLF_SORT_ASC )
m_imgSort.Draw( pDC, TLH_SORT_ASC, pt, ILD_TRANSPARENT );
else
m_imgSort.Draw( pDC, TLH_SORT_DESC, pt, ILD_TRANSPARENT );
}
else if( iSort > 0 )
{
// other sort column
ASSERT( pColumn->m_dwFormat&TLF_SORT_MASK );
if( pColumn->m_dwFormat&TLF_SORT_ASC )
m_imgSort.Draw( pDC, TLH_SORT_ASC2, pt, ILD_TRANSPARENT );
else
m_imgSort.Draw( pDC, TLH_SORT_DESC2, pt, ILD_TRANSPARENT );
}
else
{
// can sort column
ASSERT( !(pColumn->m_dwFormat&TLF_SORT_MASK) );
m_imgSort.Draw( pDC, TLH_SORT_NO, pt, ILD_TRANSPARENT );
}
::ExtSelectClipRgn( pDC->m_hDC, DEFAULT_HRGN, RGN_COPY );
rcHeader.DeflateRect( 0, 0, TLL_WIDTH/2, 0 );
}
if( rcHeader.Width() <= 0 )
return TRUE;
// draw image
if( pColumn->m_dwFormat&TLF_CAPTION_IMAGE && pColumn->m_iImage>=0 )
{
pDC->IntersectClipRect( rcHeader );
CRect rcImage;
if( pColumn->m_dwFormat&TLF_IMAGEALIGN_LEFT )
{
rcImage = rcHeader;
rcImage.right = rcHeader.left + TLL_WIDTH;
rcHeader.left = rcHeader.left + TLL_WIDTH;
}
else if( pColumn->m_dwFormat&TLF_IMAGEALIGN_RIGHT )
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -