📄 admmscrollview.cpp
字号:
/********************************************************************************
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 + -