⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 admmscrollview.cpp

📁 此程序实现类似于windows画图工具的源代码。有铅笔
💻 CPP
📖 第 1 页 / 共 3 页
字号:
/********************************************************************************
Application-Defined Mapping Mode ScrollView 
由MFC的CScrollView改造而成 -----by msz
*********************************************************************************/

#include "stdafx.h"
#include "ADMMScrollview.h"

#ifdef AFX_CORE2_SEG
#pragma code_seg(AFX_CORE2_SEG)
#endif


#define AFX_CX_ANCHOR_BITMAP	32
#define AFX_CY_ANCHOR_BITMAP	32

#ifndef SM_MOUSEWHEELPRESENT
#define SM_MOUSEWHEELPRESENT 75
#endif

#ifndef SPI_GETWHEELSCROLLLINES
#define SPI_GETWHEELSCROLLLINES  104
#endif

/////////////////////////////////////////////////////////////////////////////
// CADMMScrollView

///////////////////////////////////msz//////////////////////////////////////////
#define CX_BORDER   1
#define CY_BORDER   1
#define WM_RECALCPARENT     0x0368

const int c_cxVScroll = GetSystemMetrics(SM_CXVSCROLL) + CX_BORDER;
const int c_cyHScroll = GetSystemMetrics(SM_CYHSCROLL) + CY_BORDER;
///*extern*/ BOOL _afxGotScrollLines; // defined in wincore.cpp
/////////////////////////////////////////////////////////////////////////////

BEGIN_MESSAGE_MAP(CADMMScrollView, CView)
	//{{AFX_MSG_MAP(CADMMScrollView)
	ON_WM_SIZE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_MOUSEWHEEL()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_MBUTTONDOWN, HandleMButtonDown)
END_MESSAGE_MAP()

// Special mapping modes just for CADMMScrollView implementation
#define MM_NONE             0
#define MM_SCALETOFIT       (-1)
	// standard GDI mapping modes are > 0

/*extern*/ BOOL _afxGotScrollLines; // defined in wincore.cpp

UINT PASCAL _AfxGetMouseScrollLines()
{
	static UINT uCachedScrollLines;

	// if we've already got it and we're not refreshing,
	// return what we've already got

	if (_afxGotScrollLines)
		return uCachedScrollLines;

	// see if we can find the mouse window

	_afxGotScrollLines = TRUE;

	static UINT msgGetScrollLines;
	static WORD nRegisteredMessage;

	//if (afxData.bWin95)
	//{
	//	if (nRegisteredMessage == 0)
	//	{
	//		msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
	//		if (msgGetScrollLines == 0)
	//			nRegisteredMessage = 1;     // couldn't register!  never try again
	//		else
	//			nRegisteredMessage = 2;     // it worked: use it
	//	}

	//	if (nRegisteredMessage == 2)
	//	{
	//		HWND hwMouseWheel = NULL;
	//		hwMouseWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
	//		if (hwMouseWheel && msgGetScrollLines)
	//		{
	//			uCachedScrollLines = (UINT)
	//				::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
	//		}
	//	}
	//}
	//else
	{
		// couldn't use the window -- try system settings
		uCachedScrollLines = 3; // reasonable default
		//if (!afxData.bWin95)
			::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
		}

	return uCachedScrollLines;
}

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

#define ID_TIMER_TRACKING	0xE000

class _AFX_MOUSEANCHORWND : public CWnd
{
private:
   using CWnd::Create;

public:
	_AFX_MOUSEANCHORWND(CPoint& ptAnchor);
	~_AFX_MOUSEANCHORWND();

	BOOL Create(CADMMScrollView* pParent);
	void SetBitmap(UINT nID);

	CRect m_rectDrag;
	CPoint m_ptAnchor;
	BOOL m_bQuitTracking;
	UINT m_nAnchorID;
	HCURSOR m_hAnchorCursor;

	virtual BOOL PreTranslateMessage(MSG* pMsg);

	afx_msg void OnPaint();
	afx_msg void OnTimer(UINT_PTR nIDEvent);
	DECLARE_MESSAGE_MAP()
};

BEGIN_MESSAGE_MAP(_AFX_MOUSEANCHORWND, CWnd)
	ON_WM_PAINT()
	ON_WM_TIMER()
END_MESSAGE_MAP()

_AFX_MOUSEANCHORWND::_AFX_MOUSEANCHORWND(CPoint& ptAnchor)
: m_ptAnchor(ptAnchor), m_bQuitTracking(FALSE)
{
}

_AFX_MOUSEANCHORWND::~_AFX_MOUSEANCHORWND()
{
}

BOOL _AFX_MOUSEANCHORWND::PreTranslateMessage(MSG* pMsg)
{
	BOOL bRetVal = FALSE;

	switch (pMsg->message)
	{
	// any of these messages cause us to quit scrolling
	case WM_MOUSEWHEEL:
	case WM_KEYDOWN:
	case WM_CHAR:
	case WM_KEYUP:
	case WM_SYSKEYDOWN:
	case WM_SYSKEYUP:
	case WM_LBUTTONDOWN:
	case WM_LBUTTONUP:
	case WM_RBUTTONDOWN:
	case WM_RBUTTONUP:
	case WM_MBUTTONDOWN:
		m_bQuitTracking = TRUE;
		bRetVal = TRUE;
		break;

	// Button up message depend on the position of cursor
	// This enables the user to click and drag for a quick pan.
	case WM_MBUTTONUP:
		{
			CPoint pt(pMsg->lParam);
			ClientToScreen(&pt);
			if (!PtInRect(&m_rectDrag, pt))
				m_bQuitTracking = TRUE;
			bRetVal = TRUE;
		}
		break;
	}

	return bRetVal;
}

void _AFX_MOUSEANCHORWND::OnTimer(UINT_PTR nIDEvent)
{
	ASSERT(nIDEvent == ID_TIMER_TRACKING);
	UNUSED(nIDEvent);

	int nCursor = -1;

	CPoint ptNow;
	GetCursorPos(&ptNow);

	CRect rectClient;
	GetWindowRect(&rectClient);

	// decide where the relative position of the cursor is
	// pick a cursor that points where we're going
	nCursor = 0;

	// if vertical scrolling allowed, consider vertical
	// directions for the cursor we'll show
	if (m_nAnchorID == AFX_IDC_MOUSE_ORG_HV || m_nAnchorID == AFX_IDC_MOUSE_ORG_VERT)
	{
		if (ptNow.y < rectClient.top)
			nCursor = AFX_IDC_MOUSE_PAN_N;
		else if (ptNow.y > rectClient.bottom)
			nCursor = AFX_IDC_MOUSE_PAN_S;
	}

	// if horizontal scrolling allowed, cosider horizontal
	// directions for the cursor, too. Only consider diagonal
	// if we can scroll both ways.
	if (m_nAnchorID == AFX_IDC_MOUSE_ORG_HV || m_nAnchorID == AFX_IDC_MOUSE_ORG_HORZ)
	{
		if (ptNow.x < rectClient.left)
		{
			if (nCursor == 0)
				nCursor = AFX_IDC_MOUSE_PAN_W;
			else if (m_nAnchorID == AFX_IDC_MOUSE_ORG_HV)
				nCursor--;
		}
		else if (ptNow.x > rectClient.right)
		{
			if (nCursor == 0)
				nCursor = AFX_IDC_MOUSE_PAN_E;
			else if (m_nAnchorID == AFX_IDC_MOUSE_ORG_HV)
				nCursor++;
		}
	}

	if (m_bQuitTracking)
	{
		// Someone knows we should stop playing with the mouse
		// kill the timer, quit capturing the mouse, clear the cursor,
		// destroy the window, and make sure that CADMMScrollView knows the
		// window isn't valid anymore.

		KillTimer(ID_TIMER_TRACKING);
		ReleaseCapture();
		SetCursor(NULL);
		CADMMScrollView* pView = (CADMMScrollView*) GetOwner();
		DestroyWindow();
		delete pView->m_pAnchorWindow;
		pView->m_pAnchorWindow = NULL;
	}
	else if (nCursor == 0)
	{
		// The cursor is over the anchor window; use a cursor that
		// looks like the anchor bitmap.
		SetCursor(m_hAnchorCursor);
	}
	else
	{
		// We're still actively tracking, so we need to find a cursor and
		// set it up.

		HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nCursor),
			RT_GROUP_CURSOR);
		HICON hCursor = ::LoadCursor(hInst, MAKEINTRESOURCE(nCursor));
		ASSERT(hCursor != NULL);
		SetCursor(hCursor);

		// ask the view how much to scroll this time
		CSize sizeDistance; // = ptNow - rectClient.CenterPoint();

		if (ptNow.x > rectClient.right)
			sizeDistance.cx = ptNow.x - rectClient.right;
		else if (ptNow.x < rectClient.left)
			sizeDistance.cx = ptNow.x - rectClient.left;
		else
			sizeDistance.cx = 0;

		if (ptNow.y > rectClient.bottom)
			sizeDistance.cy = ptNow.y - rectClient.bottom;
		else if (ptNow.y < rectClient.top)
			sizeDistance.cy = ptNow.y - rectClient.top;
		else
			sizeDistance.cy = 0;

		CADMMScrollView* pView = (CADMMScrollView*) GetOwner();

		CSize sizeToScroll = pView->GetWheelScrollDistance(sizeDistance,
			m_nAnchorID == AFX_IDC_MOUSE_ORG_HV || m_nAnchorID == AFX_IDC_MOUSE_ORG_HORZ,
			m_nAnchorID == AFX_IDC_MOUSE_ORG_HV || m_nAnchorID == AFX_IDC_MOUSE_ORG_VERT );

		// hide ourselves to minimize flicker
		ShowWindow(SW_HIDE);

		CWnd* pViewParent = pView->GetParent();
		CSplitterWnd* pSplitter = DYNAMIC_DOWNCAST(CSplitterWnd, pViewParent);

		// if it is in a splitter, then we need to handle it accordingly
		if (pSplitter == NULL)
		{
			// scroll the view
			pView->OnScrollBy(sizeToScroll, TRUE);
		}
		else
		{
			// ask the splitter to scroll
			pSplitter->DoScrollBy(pView, sizeToScroll, TRUE);
		}	

		// restore ourselves and repaint
		// SetFocus();
		UpdateWindow();

		// move ourselves back (since we're a child, we scroll too!)
		SetWindowPos(&CWnd::wndTop,
			m_ptAnchor.x - AFX_CX_ANCHOR_BITMAP/2,
			m_ptAnchor.y - AFX_CY_ANCHOR_BITMAP/2, 0, 0,
			SWP_NOACTIVATE | SWP_NOSIZE | SWP_SHOWWINDOW);
	}
}

void _AFX_MOUSEANCHORWND::SetBitmap(UINT nID)
{
	HINSTANCE hInst = AfxFindResourceHandle(MAKEINTRESOURCE(nID), RT_GROUP_CURSOR);
	ASSERT(hInst != NULL);
	m_hAnchorCursor = ::LoadCursor(hInst, MAKEINTRESOURCE(nID));
	m_nAnchorID = nID;
}

BOOL _AFX_MOUSEANCHORWND::Create(CADMMScrollView* pParent)
{
	ASSERT(pParent != NULL);
	ASSERT_KINDOF(CADMMScrollView, pParent);

	pParent->ClientToScreen(&m_ptAnchor);

	m_rectDrag.top = m_ptAnchor.y - GetSystemMetrics(SM_CYDOUBLECLK);
	m_rectDrag.bottom = m_ptAnchor.y + GetSystemMetrics(SM_CYDOUBLECLK);
	m_rectDrag.left = m_ptAnchor.x - GetSystemMetrics(SM_CXDOUBLECLK);
	m_rectDrag.right = m_ptAnchor.x + GetSystemMetrics(SM_CXDOUBLECLK);

	BOOL bRetVal = 
		CreateEx(WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
			AfxRegisterWndClass(CS_SAVEBITS),
			NULL,
			WS_POPUP,
			m_ptAnchor.x - AFX_CX_ANCHOR_BITMAP/2,
			m_ptAnchor.y - AFX_CY_ANCHOR_BITMAP/2,
			AFX_CX_ANCHOR_BITMAP, AFX_CY_ANCHOR_BITMAP,
			NULL, NULL);
	SetOwner(pParent);

	if (bRetVal)
	{
		// set window's region for round effect
		CRgn rgn;
		rgn.CreateEllipticRgn(0, 0, AFX_CX_ANCHOR_BITMAP, AFX_CY_ANCHOR_BITMAP);
		SetWindowRgn(rgn, TRUE);

		// fire timer ever 50ms
		SetCapture();
		SetTimer(ID_TIMER_TRACKING, 50, NULL);
	}
#ifdef _DEBUG
	else
	{
		DWORD dwLastError = GetLastError();
		TRACE(traceAppMsg, 0, "Failed to create mouse anchor window! Last error is 0x%8.8X\n",
			dwLastError);
	}
#endif

	return bRetVal;
}

void _AFX_MOUSEANCHORWND::OnPaint()
{
	CPaintDC dc(this);
	CRect rect;
	GetClientRect(&rect);

	// shrink a pixel in every dimension for border
	rect.DeflateRect(1, 1, 1, 1);
	dc.Ellipse(rect);

	// draw anchor shape
	dc.DrawIcon(0, 0, m_hAnchorCursor);
}

/////////////////////////////////////////////////////////////////////////////
// CADMMScrollView construction/destruction

CADMMScrollView::CADMMScrollView()
{
	// Init everything to zero
	AFX_ZERO_INIT_OBJECT(CView);

	m_pAnchorWindow = NULL;
	m_nMapMode = MM_NONE;

	///分别以mm和pix获取屏幕的宽度和高度 以设置映射模式用 ///msz/////////////////
	HDC hDC = ::GetDC(NULL);
	m_XLogMm = GetDeviceCaps(hDC, HORZSIZE);
	m_YLogMm = GetDeviceCaps(hDC, VERTSIZE);
	m_XLogPix = GetDeviceCaps(hDC, HORZRES);
	m_YLogPix = GetDeviceCaps(hDC, VERTRES);
	::ReleaseDC(NULL,hDC);
	///////////////////////
}

CADMMScrollView::~CADMMScrollView()
{
	if (m_pAnchorWindow != NULL)
		m_pAnchorWindow->DestroyWindow();
	delete m_pAnchorWindow;
}

/////////////////////////////////////////////////////////////////////////////
// CADMMScrollView painting

void CADMMScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
{
	ASSERT_VALID(pDC);

#ifdef _DEBUG
	if (m_nMapMode == MM_NONE)
	{
		TRACE(traceAppMsg, 0, "Error: must call SetScrollSizes() or SetScaleToFitSize()");
		TRACE(traceAppMsg, 0, "\tbefore painting scroll view.\n");
		ASSERT(FALSE);
		return;
	}
#endif //_DEBUG
	ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
	switch (m_nMapMode)
	{
	case MM_SCALETOFIT:
		pDC->SetMapMode(MM_ANISOTROPIC);
		pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates
		pDC->SetViewportExt(m_totalDev);
		if (m_totalDev.cx == 0 || m_totalDev.cy == 0)
			TRACE(traceAppMsg, 0, "Warning: CADMMScrollView scaled to nothing.\n");
		break;

	default:
		ASSERT(m_nMapMode > 0);
		//pDC->SetMapMode(m_nMapMode);
		SetISOMapMode(pDC); //msz
		break;
	}

	CPoint ptVpOrg(0, 0);       // assume no shift for printing
	if (!pDC->IsPrinting())
	{
		ASSERT(pDC->GetWindowOrg() == CPoint(0,0));

		// by default shift viewport origin in negative direction of scroll
		ptVpOrg = -GetDeviceScrollPosition();

		if (m_bCenter)
		{
			CRect rect;
			GetClientRect(&rect);

			// if client area is larger than total device size,
			// override scroll positions to place origin such that
			// output is centered in the window
			if (m_totalDev.cx < rect.Width())
				ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
			if (m_totalDev.cy < rect.Height())
				ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
		}
	}
	pDC->SetViewportOrg(ptVpOrg);

	CView::OnPrepareDC(pDC, pInfo);     // For default Printing behavior
}

/////////////////////////////////////////////////////////////////////////////
// Set mode and scaling/scrolling sizes

void CADMMScrollView::SetScaleToFitSize(SIZE sizeTotal)
{
	// Note: It is possible to set sizeTotal members to negative values to
	//  effectively invert either the X or Y axis.

	ASSERT(m_hWnd != NULL);
	m_nMapMode = MM_SCALETOFIT;     // special internal value
	m_totalLog = sizeTotal;

	// reset and turn any scroll bars off
	if (m_hWnd != NULL && (GetStyle() & (WS_HSCROLL|WS_VSCROLL)))
	{
		SetScrollPos(SB_HORZ, 0);
		SetScrollPos(SB_VERT, 0);
		EnableScrollBarCtrl(SB_BOTH, FALSE);
		ASSERT((GetStyle() & (WS_HSCROLL|WS_VSCROLL)) == 0);

⌨️ 快捷键说明

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