scrollparent.cpp

来自「《Visual C++视频技术方案宝典》配套光盘」· C++ 代码 · 共 385 行

CPP
385
字号
// ScrollParent.cpp : implementation file
//

#include "stdafx.h"
#include "CustomScroll.h"
#include "ScrollParent.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
#define CM_MOVE  WM_USER+10
/////////////////////////////////////////////////////////////////////////////
// CScrollParent

BOOL DestroyScrollBar(CWnd *pWnd)
{
	CScrollParent *pPanel=(CScrollParent *)GetWindowLong(pWnd->m_hWnd,GWL_USERDATA);
	if(pPanel) 
	{
		RECT rc;
		CWnd *pParent=pPanel->GetParent();
		pPanel->GetWindowRect(&rc);
		pParent->ScreenToClient(&rc);
		SetWindowLong(pWnd->m_hWnd,GWL_WNDPROC,(LONG)pPanel->m_OldProc);
		SetWindowLong(pWnd->m_hWnd,GWL_USERDATA,0);
		pWnd->SetParent(pParent);
		pWnd->MoveWindow(&rc);
		pPanel->DestroyWindow();
		delete pPanel;
	}
	return TRUE;
}

CScrollParent* SkinScrollBar(CWnd *pWnd)
{
	CScrollParent *pPanel=new CScrollParent;
	pPanel->WindowSkin(pWnd);
	return pPanel;
}

//子类化回调函数
static LRESULT CALLBACK
NewProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
	CScrollParent *pSkin=(CScrollParent*)GetWindowLong(hwnd,GWL_USERDATA);
	if(msg==WM_DESTROY)
	{
		WNDPROC procOld=pSkin->m_OldProc;
		DestroyScrollBar(CWnd::FromHandle(hwnd));
		return ::CallWindowProc(procOld,hwnd,msg,wp,lp);
	}
	//执行原来的回调函数
	LRESULT lr=::CallWindowProc(pSkin->m_OldProc,hwnd,msg,wp,lp);

	if(msg==WM_ERASEBKGND)
	{
			SCROLLINFO si;
			DWORD dwStyle=::GetWindowLong(hwnd,GWL_STYLE);
			if(dwStyle&WS_VSCROLL)
			{
				memset(&si,0,sizeof(si));
				si.cbSize=sizeof(si);
				si.fMask=SIF_ALL;
				//获取滚动条信息
				::GetScrollInfo(hwnd,SB_VERT,&si);
				if(si.nMax!=pSkin->m_VerScroll.m_ScrollInfo.nMax 
					||si.nMin!=pSkin->m_VerScroll.m_ScrollInfo.nMin
					||si.nPos!=pSkin->m_VerScroll.m_ScrollInfo.nPos
					||si.nPage!=pSkin->m_VerScroll.m_ScrollInfo.nPage)
				{
					pSkin->m_VerScroll.SetScrollInfo(&si);
					pSkin->m_VerScroll.m_ScrollInfo = si;

				}
			}
			if(dwStyle&WS_HSCROLL)
			{
				memset(&si,0,sizeof(si));
				si.cbSize=sizeof(si);
				si.fMask=SIF_ALL;
				::GetScrollInfo(hwnd,SB_HORZ,&si);
				if(si.nMax!=pSkin->m_HorScroll.m_ScrollInfo.nMax 
					||si.nMin!=pSkin->m_HorScroll.m_ScrollInfo.nMin
					||si.nPos!=pSkin->m_HorScroll.m_ScrollInfo.nPos
					||si.nPage!=pSkin->m_HorScroll.m_ScrollInfo.nPage)
				{
					pSkin->m_HorScroll.SetScrollInfo(&si);
					pSkin->m_HorScroll.EnableWindow(si.nMax>=si.nPage);
				}
			}
	}
	//应用程序需要显示合法的客户区域
	else if(msg==WM_NCCALCSIZE && wp)
	{

			LPNCCALCSIZE_PARAMS pNcCalcSizeParam=(LPNCCALCSIZE_PARAMS)lp;
			DWORD dwStyle=::GetWindowLong(hwnd,GWL_STYLE);
			DWORD dwExStyle=::GetWindowLong(hwnd,GWL_EXSTYLE);
			BOOL  bLeftScroll=dwExStyle&WS_EX_LEFTSCROLLBAR;

			int nWid=::GetSystemMetrics(SM_CXVSCROLL);

			if(dwStyle&WS_VSCROLL) 
			{
				//垂直滚动条在左边
				if(bLeftScroll)
					//由于图片与滚动条的宽度不一定相同,需要适当调整客户区域大小
					pNcCalcSizeParam->rgrc[0].left-=nWid-pSkin->m_ScrollWidth;
				else
					//由于图片与滚动条的宽度不一定相同,需要适当调整客户区域大小
					pNcCalcSizeParam->rgrc[0].right+=nWid-pSkin->m_ScrollWidth;
			}

			if(dwStyle&WS_HSCROLL)
				pNcCalcSizeParam->rgrc[0].bottom+=nWid-pSkin->m_ScrollWidth;
			
			RECT rcVert,rcHorz;  //记录滚动条的位置
			
			//图片宽度
			nWid=pSkin->m_ScrollWidth;
			if(bLeftScroll)
			{
				int nLeft=pNcCalcSizeParam->rgrc[0].left;
				int nBottom=pNcCalcSizeParam->rgrc[0].bottom;
				rcVert.right=nLeft;
				rcVert.left=nLeft-nWid;
				rcVert.top=0;
				rcVert.bottom=nBottom;
				rcHorz.left=nLeft;
				rcHorz.right=pNcCalcSizeParam->rgrc[0].right;
				rcHorz.top=nBottom;
				rcHorz.bottom=nBottom+nWid;
			}else
			{
				int nRight=pNcCalcSizeParam->rgrc[0].right;
				int nBottom=pNcCalcSizeParam->rgrc[0].bottom;
				rcVert.left=nRight;
				rcVert.right=nRight+nWid;
				rcVert.top=0;
				rcVert.bottom=nBottom;
				rcHorz.left=0;
				rcHorz.right=nRight;
				rcHorz.top=nBottom;
				rcHorz.bottom=nBottom+nWid;
			}
			if(dwStyle&WS_VSCROLL && dwStyle&WS_HSCROLL)
			{
				pSkin->m_Type=bLeftScroll?1:2;
			}else
			{
				pSkin->m_Type=0;
			}
			//显示或隐藏滚动条
			if(dwStyle&WS_VSCROLL)
			{
				pSkin->m_VerScroll.MoveWindow(&rcVert);
				pSkin->m_VerScroll.ShowWindow(SW_SHOW);
			}else
			{
				pSkin->m_VerScroll.ShowWindow(SW_HIDE);
			}
			if(dwStyle&WS_HSCROLL)
			{
				pSkin->m_HorScroll.MoveWindow(&rcHorz);
				pSkin->m_HorScroll.ShowWindow(SW_SHOW);
			}else
			{
				pSkin->m_HorScroll.ShowWindow(SW_HIDE);
			}
			pSkin->PostMessage(CM_MOVE,dwStyle&WS_VSCROLL,bLeftScroll);
	}
	return lr;
}

CScrollParent::CScrollParent()
{
	m_OldProc     = NULL;
	m_ScrollWidth = 0;
}

CScrollParent::~CScrollParent()
{


}


BEGIN_MESSAGE_MAP(CScrollParent, CWnd)
	//{{AFX_MSG_MAP(CScrollParent)
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_TIMER()
	ON_WM_PAINT()
	ON_MESSAGE(CM_MOVE,OnScrollMove)
	//}}AFX_MSG_MAP

END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CScrollParent message handlers

void CScrollParent::OnSize(UINT nType, int cx, int cy) 
{
	CWnd::OnSize(nType, cx, cy);
	if(cx==0 || cy==0) 
		return;
	if(IsWindow( m_ChildWnd.m_hWnd))
	{
		CWnd *pWnd=m_ChildWnd.GetWindow(GW_CHILD);
		pWnd->MoveWindow(0,0,cx,cy);
	}
}

void CScrollParent::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CWnd *pWnd=m_ChildWnd.GetWindow(GW_CHILD);
	pWnd->SendMessage(WM_HSCROLL,MAKELONG(nSBCode,nPos),0);

	if(nSBCode==SB_THUMBTRACK) return;
	SCROLLINFO si={0};
	si.cbSize=sizeof(si);
	si.fMask=SIF_ALL;
	pWnd->GetScrollInfo(SB_HORZ,&si);
	pScrollBar->SetScrollInfo(&si,TRUE);	
	CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CScrollParent::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CWnd *pWnd=m_ChildWnd.GetWindow(GW_CHILD);

	pWnd->SendMessage(WM_VSCROLL,MAKELONG(nSBCode,nPos),0);

	if(nSBCode==SB_THUMBTRACK) return;
	SCROLLINFO si={0};
	si.cbSize=sizeof(si);
	si.fMask=SIF_ALL;
	pWnd->GetScrollInfo(SB_VERT,&si);
	pScrollBar->SetScrollInfo(&si,TRUE);	
	CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}

//当在控件中利用方向键致使滚动块移动时,更新父窗口中的滚动条控件
void CScrollParent::OnTimer(UINT nIDEvent) 
{
	CWnd *pWnd=m_ChildWnd.GetWindow(GW_CHILD);
	SCROLLINFO si1={0};
	si1.cbSize=sizeof(SCROLLINFO);
	si1.fMask=SIF_ALL;
	SCROLLINFO si2={0};
	if(GetWindowLong(m_VerScroll.m_hWnd,GWL_STYLE)&WS_VISIBLE )
	{
		pWnd->GetScrollInfo(SB_VERT,&si1);
		m_VerScroll.SetScrollInfo(&si1);
	}
	if(GetWindowLong(m_HorScroll.m_hWnd,GWL_STYLE)&WS_VISIBLE )
	{
		pWnd->GetScrollInfo(SB_HORZ,&si1);
		m_HorScroll.SetScrollInfo(&si1);
	}	
}

void CScrollParent::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	//绘制交叉矩形
	CDC memdc;
	memdc.CreateCompatibleDC(&dc);
	CBitmap bmp;
	bmp.LoadBitmap(IDB_RECT);
	
	HGDIOBJ hOldBmp=memdc.SelectObject(&bmp);
	RECT rc;
	GetClientRect(&rc);
	if(m_Type==1)
		dc.BitBlt(rc.left,rc.bottom-m_ScrollWidth,m_ScrollWidth,m_ScrollWidth,&memdc,0,0,SRCCOPY);
	else if(m_Type==2)
			dc.BitBlt(rc.right-m_ScrollWidth,rc.bottom-m_ScrollWidth,m_ScrollWidth,m_ScrollWidth,&memdc,0,0,SRCCOPY);
	::SelectObject(memdc,hOldBmp);
}

LRESULT CScrollParent::OnScrollMove(WPARAM wParam, LPARAM lParam)
{
	BOOL bVScroll=wParam;
	BOOL bLeftScroll=lParam;
	RECT rcClient;
	GetClientRect(&rcClient);
	RECT rcLimit,rcWnd;
	rcWnd=rcClient;
	rcLimit=rcClient;

	if(GetWindowLong(m_HorScroll.m_hWnd,GWL_STYLE)&WS_VISIBLE)
		rcLimit.bottom-=m_ScrollWidth;

	if(bLeftScroll)
	{
		if(bVScroll)
		{
			rcLimit.left+=m_ScrollWidth;
			OffsetRect(&rcWnd,-m_ScrollWidth,0);
		}
	}else
	{
		if(bVScroll) 
			rcLimit.right-=m_ScrollWidth;
	}
	m_ChildWnd.MoveWindow(&rcLimit);
	m_ChildWnd.GetWindow(GW_CHILD)->SetWindowPos(NULL,rcWnd.left,0,0,0,SWP_NOSIZE|SWP_NOZORDER);
	return 0;
}

BOOL CScrollParent::WindowSkin(CWnd *pWnd)
{
	ASSERT(m_hWnd==NULL);

	CBitmap bmp;
	bmp.LoadBitmap(IDB_LEFTARROW);
	BITMAP bm;
	bmp.GetBitmap(&bm);

	//滚动条的宽度
	m_ScrollWidth=bm.bmWidth-1;
	//获取对话框
	CWnd *pParent=pWnd->GetParent();

	ASSERT(pParent);
	RECT rcFrm,rcWnd;
	pWnd->GetWindowRect(&rcFrm);
	//rcFrm为控件在窗口中的位置
	pParent->ScreenToClient(&rcFrm);
	rcWnd=rcFrm;
	//rcFrm记录当前控件的位置,将在该位置创建一个父控件
	//移动区域左上角被移动到0,0处,使其处于父控件内
	OffsetRect(&rcWnd,-rcWnd.left,-rcWnd.top);

	UINT uID=pWnd->GetDlgCtrlID();
	DWORD dwStyle=pWnd->GetStyle();
	DWORD dwExStyle=pWnd->GetExStyle();
	DWORD dwFrmStyle=WS_CHILD|SS_NOTIFY;
	DWORD dwFrmStyleEx=0;
	if(dwExStyle & WS_EX_TOOLWINDOW)
	{
		dwFrmStyleEx|=WS_EX_TOOLWINDOW;
		dwFrmStyleEx |=WS_EX_TOPMOST;
	}
	if(dwStyle&WS_VISIBLE) dwFrmStyle|=WS_VISIBLE;

	if(dwStyle&WS_BORDER)
	{
		dwFrmStyle|=WS_BORDER;
		//移除控件的边框
		pWnd->ModifyStyle(WS_BORDER,0);

		int nBorder=::GetSystemMetrics(SM_CXBORDER);
		//将rcWnd区域扣除边框
		rcWnd.right-=nBorder*2;
		rcWnd.bottom-=nBorder*2;
	}
	if(dwExStyle&WS_EX_CLIENTEDGE)
	{
		pWnd->ModifyStyleEx(WS_EX_CLIENTEDGE,0);
		int nBorder   =::GetSystemMetrics(SM_CXEDGE);
		rcWnd.right-=nBorder*2;
		rcWnd.bottom-=nBorder*2;
		dwFrmStyleEx|=WS_EX_CLIENTEDGE;
	}
	//以原控件风格创建一个父控件
	CreateEx(dwFrmStyleEx,AfxRegisterWndClass(NULL),"ScrollBarContainer",dwFrmStyle,rcFrm,pParent,uID);

	m_ChildWnd.Create(NULL,"CHILDWND",WS_CHILD|WS_VISIBLE,CRect(0,0,0,0),this,200);
	m_HorScroll.Create(WS_CHILD|SBS_HORZ,CRect(0,0,0,0),this,100);
	m_VerScroll.Create(WS_CHILD|SBS_VERT,CRect(0,0,0,0),this,101);

	pWnd->SetParent(&m_ChildWnd);
	SetWindowLong(pWnd->m_hWnd,GWL_USERDATA,(LONG)this);
	m_OldProc=(WNDPROC)SetWindowLong(pWnd->m_hWnd,GWL_WNDPROC,(LONG)NewProc);

	pWnd->MoveWindow(&rcWnd);
	SetTimer(1,500,NULL);
	return TRUE;
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?