OnMouseHover事件获取坐标信息

本文详细介绍了在C# WinForm中如何通过`Control.MousePosition`和`Cursor.Position`获取鼠标所在屏幕坐标,并通过`PointToClient`转换为工作区坐标的方法。适合开发人员学习。

C# winform 中, OnMouseHover事件没有 坐标信息,如何获取坐标信息呢?
可以通过  Control.MousePosition   或 Cursor.Position 得到鼠标所在的屏幕坐标信息,然后通过 PointToClient 转换成工作区的坐标信息

请根据我提供的滚动条控件源码,重构一个更高效的控件给我 #ifndef _SCROLL_BAR_H_ #define _SCROLL_BAR_H_ #include "BaseWnd/CBaseWnd.h" class ScrollBar : public MFC::CBaseWnd { public: ScrollBar(); ~ScrollBar(); BOOL Create(const int _iBar, const CRect& _Rect, CWnd* _pParent, const int _iArrowFlags = ESB_ENABLE_BOTH, const int _iSpace = 3, const int _iMinSlider = 10); BOOL SetScrollInfo(SCROLLINFO& _refScrollInfo, BOOL _bRedraw = TRUE); BOOL SetScrollPos(int _iPos, BOOL _bRedraw = TRUE); void SetTarget(CWnd* _pTargetWnd); private: int m_iBar; //此滚动条的风格: SB_HORZ = 水平横向滚动条, SB_VERT = 垂直纵向滚动条 int m_iSpace; //滚动条滑块通道两边的空白间隔 int m_iMinSlider; //滑块的最小宽度,不可能无限小吧,滑块过小了肉眼都难看到了 int m_iArrowFlags; //两边是否开启箭头 float m_fRatio; //比率: 如: 滚动条滚动 1pixl, 目标控件该移动多少 pix? 或者反过来,目标控件移动了10pix , 那么滚动条应该移动多少pix? CRect m_rcLTUP; //滚动条(左边/顶部)的箭头范围 3个范围组成完整的滚动条 CRect m_rcScroll; //滚动条通道的范围 3个范围组成完整的滚动条 CRect m_rcRTDN; //滚动条(右边/底部)的箭头范围 3个范围组成完整的滚动条 SCROLLINFO m_infoScroll; //滚动条的信息 这2个info是相互关联依赖 SCROLLBARINFO m_infoScrollBar; //滚动条的滑块信息 这2个info是相互关联依赖 //以下解释2个info的关联性 /* typedef struct tagSCROLLINFO { UINT cbSize; //size of(SCROLLINFO) UINT fMask; //SIF_ALL 即nMin, nMax, nPage, nPos, nTrackPos 5个变量值都得到更改 int nMin; //一般置 0 int nMax; //目标控件的最大可见内容, 比如我的目标控件宽度: 666 pix, 控件内有一行文字内容,此行文字占:977 pix, 那么此行内容就有: 977-666 pix内容是看不到了,那么最大可见内容nMax=977 UINT nPage; //目标控件的宽度: 666 pix, 一般一行文字的最前面和最后面都有一个占1pix的光标,正如我们打字那个光标一样, 666-2pix = 664, 那么nPag = 664 int nPos; //这里我预设为: 29, 最下面会给出这个29的计算方法 int nTrackPos; //这个值是以前旧nPos, 等更新完成后,也会变成29 } SCROLLINFO, FAR* LPSCROLLINFO; */ /* typedef struct tagSCROLLBARINFO { DWORD cbSize; //size of(SCROLLBARINFO) RECT rcScrollBar; //滚动条的全部范围: 我预设此滚动条是: 666*17 pix, 水平横向滚动条,两头带17 pix的箭头按钮 int dxyLineButton; //滚动条2头的箭头宽度: 17pix int xyThumbTop; //滑块左边位于滚动条的位置, 这里是36 pix 这个36 pix和上面的nPos 29pix是有关联性的 int xyThumbBottom; //滑块右边位于滚动条的位置, 这里是465 pix, 那么这个滚动条中间滑块的宽度就是: 465-36 int reserved; //windows预留位置,不用管 DWORD rgstate[CCHILDREN_SCROLLBAR + 1]; //当滚动可见,这里全部为0, 可视状态开关 } SCROLLBARINFO, * PSCROLLBARINFO, * LPSCROLLBARINFO; */ /*  * xyThumbTop = 36 计算出 nPos = 29 : * xyThumbTop-17 = 36-17 = 19pix, 先去除左边箭头的宽度得到真实: 当前滚动条已经滚动的距离 * 计算比率: 滚动条的长度/目标控件的最大可见内容 = (666-(17*2))/977 = 0.6468781 (17*2)是去掉2个箭头距离 * xyThumbTop / 比率 = 19/0.6468781 = 29.37183991 = (int)29 = nPos = 29 * nPos逆向计算xyThumbTop = 29*0.6468781 = 19 * 总结: SCROLLBARINFO信息控制滚动条内部信息,SCROLLINFO控制外部目标控件的信息 */ CRect m_rcSlider; //滚动条内滑块的范围 COLORREF m_clrSlider; //滑块的状态颜色 COLORREF m_clrSlider_Def; //滑块无操作状态下的颜色 COLORREF m_clrSlider_Hover; //鼠标悬停在滑块上面的颜色 COLORREF m_clrSlider_Click; //鼠标左键按下滑块的颜色 BOOL m_bIsTrack; //鼠标触发WM_MOUSEMOVE一次就触发一次鼠标悬停?明显太浪费了,所以这个bIsTrack控制,确保已经触发完成鼠标悬停事件再重置bIsTrack BOOL m_bIsCaptrue; //监视这个控件是不是正在 捕获焦点 中 CPoint m_ptMouseLastPoint; //鼠标移动: 从A点移动到B点, m_ptMouseLastPoint代表A点(存储), B点在WM_MOUSEMOVE事件能得到 int m_iLTUPBtn; //(左边/顶部)箭头的(宽度/长度) int m_iRTDNBtn; //(右边/底部)箭头的(宽度/长度) CRgn m_rgnLTUPBtn; //(左边/顶部)三角形箭头的绘画路径 CRgn m_rgnRTDNBtn; //(右边/底部)三角形箭头的绘画路径 COLORREF m_clrArrow; //箭头的状态颜色 COLORREF m_clrArrow_Def; //箭头无操作状态颜色 COLORREF m_clrArrow_Hover; //鼠标悬停在箭头上的颜色 COLORREF m_clrArrow_Click; //鼠标左键按下箭头的颜色 BOOL m_bIsEnd; //当前滚动条已经达到尽头 CWnd* m_pTargetWnd; //关联的目标控件 float m_fCorrectionLT; //补正(左箭头/顶部箭头)移动距离 float m_fCorrectionRD; //补正(右箭头/底部箭头)移动距离 public: DECLARE_MESSAGE_MAP() afx_msg void OnPaint(); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnMouseHover(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); afx_msg void OnLButtonDown(UINT nFlags, CPoint point); afx_msg void OnLButtonUp(UINT nFlags, CPoint point); afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); afx_msg void OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); virtual void OnMouseLeave(const CPoint& _point); virtual void OnDragSlider(const CPoint& _point); virtual void OnClickLTUPBtn();//点击了(左箭头/顶部箭头) virtual void OnClickRTDNBtn();//点击了(右箭头/底部箭头) }; #endif#include "ScrollBar.h" ScrollBar::ScrollBar(): m_iBar(0), m_iSpace(0), m_iMinSlider(0), m_iArrowFlags(ESB_ENABLE_BOTH), m_fRatio(0.0f), m_bIsTrack(FALSE), m_bIsCaptrue(FALSE), m_iLTUPBtn(0), m_iRTDNBtn(0), m_bIsEnd(FALSE), m_pTargetWnd(NULL), m_fCorrectionLT(0.0f), m_fCorrectionRD(0.0f) { //初始化一些基本结构 m_rcLTUP = { 0, 0, 0, 0 }; m_rcScroll = {0, 0, 0, 0}; m_rcRTDN = {0, 0, 0, 0}; memset(&m_infoScroll, 0, sizeof m_infoScroll); m_infoScroll.cbSize = sizeof m_infoScroll; memset(&m_infoScrollBar, 0, sizeof m_infoScrollBar); m_infoScrollBar.cbSize = sizeof m_infoScrollBar; m_rcSlider = { 0,0,0,0 }; m_clrSlider_Def = RGB(104, 104, 104); m_clrSlider_Hover = RGB(158, 158, 158); m_clrSlider_Click = RGB(239, 235, 239); m_clrSlider = m_clrSlider_Def; m_ptMouseLastPoint = { 0,0 }; m_clrArrow_Def = RGB(104, 104, 104); m_clrArrow_Hover = RGB(158, 158, 158); m_clrArrow_Click = RGB(239, 235, 239); m_clrArrow = m_clrArrow_Def; } ScrollBar::~ScrollBar() { //箭头路径销毁: windwos要求释放资源 m_rgnLTUPBtn.DeleteObject(); m_rgnRTDNBtn.DeleteObject(); } BOOL ScrollBar::Create(const int _iBar, const CRect& _Rect, CWnd* _pParent, const int _iArrowFlags, const int _iSpace, const int _iMinSlider) { //准备滚动条数据 m_iBar = _iBar; //存储滚动条风格: SB_HORZ=水平横向滚动条; SB_VERT=垂直纵向滚动条 m_iSpace = _iSpace; //存储滚动条滑块两边空白间隔 m_iArrowFlags = _iArrowFlags; //存储滚动条的箭头开关值: 0=两个都开启; 1=(左边/顶部)的箭头关闭; 2=(右边/底部)的箭头关闭; 3=两个都关闭 m_iMinSlider = _iMinSlider; //存储滚动条滑块的最小(宽度/长度),不可能无限短,太短肉眼都看不见了 CRect recWnd = { 0, 0, 0,0 }; if (CBaseWnd::Create("scroll bar", _Rect, _pParent, NULL, WS_CHILD | WS_VISIBLE))//创建控件 { //控件创建成功 m_infoScrollBar.rcScrollBar = {0, 0, _Rect.Width(), _Rect.Height()};//设置滚动条所占此控件的范围,一般是全部 recWnd = m_infoScrollBar.rcScrollBar; switch (_iBar) { case SB_HORZ: m_infoScrollBar.dxyLineButton = _Rect.Height();//如果是水平滚动条, 箭头按钮长度就是控件的宽度 break; case SB_VERT: m_infoScrollBar.dxyLineButton = _Rect.Width();//如果是垂直滚动条, 箭头按钮的宽度就是控件的长度 break; } switch (_iArrowFlags) { case ESB_ENABLE_BOTH://2个箭头都开启 m_iLTUPBtn = m_infoScrollBar.dxyLineButton; m_iRTDNBtn = m_infoScrollBar.dxyLineButton; break; case ESB_DISABLE_LTUP://关闭(左边/顶部)的箭头 m_iLTUPBtn = 0; m_iRTDNBtn = m_infoScrollBar.dxyLineButton; break; case ESB_DISABLE_RTDN://关闭(右边/底部)的箭头 m_iLTUPBtn = m_infoScrollBar.dxyLineButton; m_iRTDNBtn = 0; break; case ESB_DISABLE_BOTH://2个箭头都关闭 m_iLTUPBtn = 0; m_iRTDNBtn = 0; break; } switch (_iBar) { case SB_HORZ: { m_infoScroll.nMax = _Rect.Width();//初始化目标控件里面的内容最大可视范围 m_infoScroll.nPage = _Rect.Width();//初始化目标控件的最大范围 m_rcSlider = { recWnd.left + m_iLTUPBtn, recWnd.top + m_iSpace, recWnd.right - m_iRTDNBtn, recWnd.bottom - m_iSpace };//初始化滑块坐标范围 m_infoScrollBar.xyThumbTop = m_rcSlider.left;//滑块的左边坐标 m_infoScrollBar.xyThumbBottom = m_rcSlider.right;//滑块的右边坐标 CPoint vecPoint[3]; //绘画左边箭头三角形 vecPoint[0] = { m_iSpace+1, m_infoScrollBar.dxyLineButton / 2 }; vecPoint[1] = { m_infoScrollBar.dxyLineButton - m_iSpace*2, m_infoScrollBar.dxyLineButton - m_iSpace }; vecPoint[2] = { m_infoScrollBar.dxyLineButton - m_iSpace*2 , m_iSpace-1 }; m_rgnLTUPBtn.CreatePolygonRgn(vecPoint, 3, WINDING); //绘画右边箭头三角形 vecPoint[0] = {recWnd.Width()-(m_iSpace + 1), m_infoScrollBar.dxyLineButton / 2 }; vecPoint[1] = {recWnd.Width()- (m_infoScrollBar.dxyLineButton - m_iSpace * 2), m_infoScrollBar.dxyLineButton - m_iSpace }; vecPoint[2] = {recWnd.Width() - (m_infoScrollBar.dxyLineButton - m_iSpace * 2), m_iSpace-1 }; m_rgnRTDNBtn.CreatePolygonRgn(vecPoint, 3, WINDING); //分配范围 m_rcLTUP = { recWnd.left, recWnd.top, recWnd.left + m_iLTUPBtn, recWnd.bottom };//左箭头范围 m_rcRTDN = { recWnd.right - m_iRTDNBtn, recWnd.top, recWnd.right, recWnd.bottom };//右箭头范围 m_rcScroll = {recWnd.left+m_iLTUPBtn, recWnd.top, recWnd.right-m_iRTDNBtn, recWnd.bottom};//中间滚动条通道 m_rcSlider = {m_rcScroll.left, m_rcScroll.top+m_iSpace, m_rcScroll.right, m_rcScroll.bottom-m_iSpace}; break; } case SB_VERT: { m_infoScroll.nMax = recWnd.Height();//初始化目标控件里面的内容最大可视范围 m_infoScroll.nPage = recWnd.Height();//初始化目标控件的最大范围 m_rcSlider = {recWnd.left+m_iSpace, recWnd.top+m_iLTUPBtn, recWnd.right-m_iSpace, recWnd.bottom-m_iRTDNBtn};//初始化滑块坐标范围 m_infoScrollBar.xyThumbTop = m_rcSlider.top;//滑块顶部的坐标 m_infoScrollBar.xyThumbBottom = m_rcSlider.bottom;//滑块底部的坐标 CPoint vecPoint[3]; //绘画顶部箭头的三角形 vecPoint[0] = { m_infoScrollBar.dxyLineButton / 2 , m_iSpace }; vecPoint[1] = { m_iSpace-1, m_infoScrollBar.dxyLineButton - m_iSpace * 2 }; vecPoint[2] = { m_infoScrollBar.dxyLineButton - m_iSpace, m_infoScrollBar.dxyLineButton - m_iSpace*2 }; m_rgnLTUPBtn.CreatePolygonRgn(vecPoint, 3, WINDING); //绘画底部箭头的三角形 vecPoint[0] = { m_infoScrollBar.dxyLineButton / 2 , recWnd.Height() - m_iSpace - 1 }; vecPoint[1] = { m_iSpace , recWnd.Height() - m_infoScrollBar.dxyLineButton + m_iSpace * 2 }; vecPoint[2] = { m_infoScrollBar.dxyLineButton - m_iSpace, recWnd.Height() - m_infoScrollBar.dxyLineButton + m_iSpace * 2 }; m_rgnRTDNBtn.CreatePolygonRgn(vecPoint, 3, WINDING); //分配范围 m_rcLTUP = { recWnd.left, recWnd.top, recWnd.right, recWnd.top+m_iLTUPBtn };//上箭头范围 m_rcRTDN = { recWnd.left, recWnd.bottom - m_iRTDNBtn, recWnd.right, recWnd.bottom };//下箭头范围 m_rcScroll = { recWnd.left, recWnd.top + m_iLTUPBtn, recWnd.right, recWnd.bottom - m_iRTDNBtn };//中间滚动条通道 m_rcSlider = {m_rcScroll.left+m_iSpace, m_rcScroll.top, m_rcScroll.right-m_iSpace, m_rcScroll.bottom}; break; } } return TRUE; } return FALSE; } BEGIN_MESSAGE_MAP(ScrollBar, MFC::CBaseWnd) ON_WM_PAINT() ON_WM_MOUSEMOVE() ON_WM_MOUSEHOVER() ON_WM_MOUSELEAVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_HSCROLL() ON_WM_VSCROLL() END_MESSAGE_MAP() void ScrollBar::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: 在此处添加消息处理程序代码 // 不为绘图消息调用 CBaseWnd::OnPaint() CBrush brush; brush.CreateSolidBrush(m_clrArrow); m_MemDC.FillSolidRect(m_rcWnd, RGB(62, 62, 66));//背景色 m_MemDC.FillSolidRect(m_rcSlider, m_clrSlider);//滑块色 if(m_iLTUPBtn) m_MemDC.FillRgn(&m_rgnLTUPBtn, &brush); if(m_iRTDNBtn) m_MemDC.FillRgn(&m_rgnRTDNBtn, &brush); brush.DeleteObject(); dc.BitBlt(0, 0, m_rcWnd.Width(), m_rcWnd.Height(), &m_MemDC, 0, 0, SRCCOPY); //更新scroll bar info数据 switch (m_iBar) { case SB_HORZ: m_infoScrollBar.xyThumbTop = m_rcSlider.left; m_infoScrollBar.xyThumbBottom = m_rcSlider.right; break; case SB_VERT: m_infoScrollBar.xyThumbTop = m_rcSlider.top; m_infoScrollBar.xyThumbBottom = m_rcSlider.bottom; break; } } void ScrollBar::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (!m_bIsTrack && !m_bIsCaptrue) { m_bIsTrack = TRUE; TRACKMOUSEEVENT tme; tme.cbSize = sizeof(tme); tme.hwndTrack = m_hWnd; tme.dwFlags = TME_LEAVE | TME_HOVER; tme.dwHoverTime = 1;// 鼠标在按钮上停留超过 1ms ,才认为成功 _TrackMouseEvent(&tme); } if (m_bIsCaptrue) { OnDragSlider(point); m_ptMouseLastPoint = point; } CBaseWnd::OnMouseMove(nFlags, point); } void ScrollBar::OnMouseHover(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 OnMouseLeave(m_ptMouseLastPoint); if (PtInRect(m_rcLTUP, point)) { //鼠标悬停在(左边/顶部)箭头上面 m_clrArrow = m_clrArrow_Hover; InvalidateRect(m_rcLTUP); } else if (PtInRect(m_rcRTDN, point)) { //鼠标悬停在(右边/底部)箭头上面 m_clrArrow = m_clrArrow_Hover; InvalidateRect(m_rcRTDN); } else if (PtInRect(m_rcSlider, point)) { //鼠标悬停在滑块上面 m_clrSlider = m_clrSlider_Hover; InvalidateRect(m_rcSlider); } m_ptMouseLastPoint = point; m_bIsTrack = FALSE; CBaseWnd::OnMouseHover(nFlags, point); } void ScrollBar::OnMouseLeave(const CPoint& _point) { if (PtInRect(m_rcLTUP, _point)) { //鼠标离开(左边/顶部)箭头 m_clrArrow = m_clrArrow_Def; InvalidateRect(m_rcLTUP); } else if (PtInRect(m_rcRTDN, _point)) { //鼠标离开(右边/底部)箭头 m_clrArrow = m_clrArrow_Def; InvalidateRect(m_rcRTDN); } else if (PtInRect(m_rcSlider, _point)) { //鼠标离开滑块 m_clrSlider = m_clrSlider_Def; InvalidateRect(m_rcSlider); } } void ScrollBar::OnMouseLeave() { // TODO: 在此添加消息处理程序代码和/或调用默认值 //鼠标离开控件 m_bIsTrack = FALSE; m_clrSlider = m_clrSlider_Def; m_clrArrow = m_clrArrow_Def; Invalidate(); if (m_bIsCaptrue) { ReleaseCapture(); m_bIsCaptrue = FALSE; } CBaseWnd::OnMouseLeave(); } void ScrollBar::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (PtInRect(m_rcLTUP, point)) { //鼠标左键点击(左边/顶部)箭头 m_clrArrow = m_clrArrow_Click; InvalidateRect(m_rcLTUP); OnClickLTUPBtn(); } else if (PtInRect(m_rcRTDN, point)) { //鼠标左键点击(右边/底部)箭头 m_clrArrow = m_clrArrow_Click; InvalidateRect(m_rcRTDN); OnClickRTDNBtn(); } else if (PtInRect(m_rcSlider, point)) { //鼠标左键点击滑块 m_clrSlider = m_clrSlider_Click; InvalidateRect(m_rcSlider); SetCapture(); m_bIsCaptrue = TRUE; } CBaseWnd::OnLButtonDown(nFlags, point); } void ScrollBar::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (PtInRect(m_rcLTUP, point)) { //鼠标左键点击(左边/顶部)箭头 后 鼠标弹起 m_clrArrow = m_clrArrow_Hover; InvalidateRect(m_rcLTUP); } else if (PtInRect(m_rcRTDN, point)) { //鼠标左键点击(右边/底部)箭头 后 鼠标弹起 m_clrArrow = m_clrArrow_Hover; InvalidateRect(m_rcRTDN); } else if (PtInRect(m_rcSlider, point)) { //鼠标左键点击滑块 后 鼠标弹起 m_clrSlider = m_clrSlider_Hover; InvalidateRect(m_rcSlider); ReleaseCapture(); m_bIsCaptrue = FALSE; if (m_infoScroll.nTrackPos != m_infoScroll.nPos)//用nPos和nTrackPos比较是否滑块滑动过,nTrackPos在拖滑块中会更新 { switch (m_iBar) { case SB_HORZ: SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_rcSlider.left), NULL); break; case SB_VERT: SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_rcSlider.top), NULL); break; } } } if (m_bIsCaptrue) { ReleaseCapture(); m_bIsCaptrue = FALSE; if (m_infoScroll.nTrackPos != m_infoScroll.nPos)//用nPos和nTrackPos比较是否滑块滑动过,nTrackPos在拖滑块中会更新 { switch (m_iBar) { case SB_HORZ: SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_rcSlider.left), NULL); break; case SB_VERT: SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_rcSlider.top), NULL); break; } } } m_bIsEnd = FALSE; CBaseWnd::OnLButtonUp(nFlags, point); } void ScrollBar::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (pScrollBar == NULL)//NULL说明内部发送过来信息 { switch (nSBCode) { case SB_ENDSCROLL: { //结束滚动 //_output_debug_("水平滚动结束x:%d", nPos); if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_THUMBTRACK: { //正在拖动滑块 m_infoScroll.nTrackPos = int((float)nPos / m_fRatio);//使用滑块的距离逆向比率得到目标的xPos if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, m_infoScroll.nTrackPos), (LPARAM)this); } break; } case SB_THUMBPOSITION: { //用户已拖动滚动框(拇指)并松开鼠标按钮 //_output_debug_("水平滚动条鼠标松开滑动,目标xPos:%d", m_infoScroll.nTrackPos); m_infoScroll.nPos = m_infoScroll.nTrackPos;//最终更新用户数据 SendMessage(WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, m_rcSlider.left-m_iLTUPBtn), NULL); break; } case SB_LINELEFT: { //向左滚动一个单位 点击左箭头 //_output_debug_("水平滚动向左滚动一个单位:%d", nPos); m_fCorrectionLT += (float)nPos / m_fRatio;//计算目标控件的滚动距离 int pos = (int)m_fCorrectionLT; m_fCorrectionLT -= (float)pos; m_infoScroll.nPos -= pos; m_infoScroll.nPos = m_infoScroll.nPos < m_infoScroll.nMin ? m_infoScroll.nMin : m_infoScroll.nPos; m_infoScroll.nTrackPos = m_infoScroll.nPos; if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_LINERIGHT: { //向右滚动一个单位 点击右箭头 //_output_debug_("水平滚动向右滚动一个单位:%d", nPos); m_fCorrectionRD += (float)nPos / m_fRatio; int pos = (int)m_fCorrectionRD; m_fCorrectionRD -= (float)pos;//把小数位单独出来留给后面的补正 m_infoScroll.nPos += pos;//使用滑块的距离逆向比率得到目标的xPos m_infoScroll.nPos = m_infoScroll.nPos > m_infoScroll.nMax ? m_infoScroll.nMax : m_infoScroll.nPos; m_infoScroll.nTrackPos = m_infoScroll.nPos; if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_LEFT: { //滚动到左边末尾 //_output_debug_("已经滚动到左边尽头."); //if (m_pTargetWnd) m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_LEFT, 0), (LPARAM)this); break; } case SB_RIGHT: { //滚动到右边末尾 //_output_debug_("已经滚动到右边尽头."); //if (m_pTargetWnd) m_pTargetWnd->SendMessage(WM_HSCROLL, MAKEWPARAM(SB_RIGHT, m_infoScroll.nMax), (LPARAM)this); break; } } } CBaseWnd::OnHScroll(nSBCode, nPos, pScrollBar); } void ScrollBar::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (pScrollBar == NULL)//NULL说明内部发送过来信息 { switch (nSBCode) { case SB_ENDSCROLL: { //结束滚动 //_output_debug_("垂直滚动结束y:%d", nPos); if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_ENDSCROLL, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_THUMBTRACK: { //正在拖动滑块 m_infoScroll.nTrackPos = int((float)nPos / m_fRatio);//使用滑块的距离逆向比率得到目标的xPos if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, m_infoScroll.nTrackPos), (LPARAM)this); } break; } case SB_THUMBPOSITION: { //用户已拖动滚动框(拇指)并松开鼠标按钮 //_output_debug_("垂直滚动条鼠标松开滑动,目标yPos: %d", m_infoScroll.nTrackPos); m_infoScroll.nPos = m_infoScroll.nTrackPos;//最终更新用户数据 SendMessage(WM_VSCROLL, MAKEWPARAM(SB_ENDSCROLL, m_rcSlider.top-m_iLTUPBtn), NULL); break; } case SB_LINEUP: { //向上滚动了一个单位 点击顶箭头 m_fCorrectionLT += int((float)nPos / m_fRatio);//使用滑块的距离逆向比率得到目标的xPos int pos = (int)m_fCorrectionLT; m_fCorrectionLT -= (float)pos; m_infoScroll.nPos -= pos; m_infoScroll.nPos = m_infoScroll.nPos < m_infoScroll.nMin ? m_infoScroll.nMin : m_infoScroll.nPos; m_infoScroll.nTrackPos = m_infoScroll.nPos; if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_LINEDOWN: { //向下滚动了一个单位 点击底箭头 m_fCorrectionRD += (float)nPos / m_fRatio; int pos = (int)m_fCorrectionRD; m_fCorrectionRD -= (float)pos;//把小数位单独出来留给后面的补正 m_infoScroll.nPos += pos;//使用滑块的距离逆向比率得到目标的xPos m_infoScroll.nPos = m_infoScroll.nPos > m_infoScroll.nMax ? m_infoScroll.nMax : m_infoScroll.nPos; m_infoScroll.nTrackPos = m_infoScroll.nPos; if (m_pTargetWnd) { m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBPOSITION, m_infoScroll.nPos), (LPARAM)this); } break; } case SB_TOP: { //滚动到顶部 //_output_debug_("已经滚动到顶部尽头."); //if (m_pTargetWnd) m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_TOP, 0), (LPARAM)this); break; } case SB_BOTTOM: { //滚动到底部 //_output_debug_("已经滚动到底部尽头."); //if (m_pTargetWnd) m_pTargetWnd->SendMessage(WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, 0), (LPARAM)this); break; } } } CBaseWnd::OnVScroll(nSBCode, nPos, pScrollBar); } void ScrollBar::OnDragSlider(const CPoint& _point) { CPoint point = {0, 0}; CRect rect = m_rcSlider; switch (m_iBar) { case SB_HORZ: { point.x = _point.x - m_ptMouseLastPoint.x; rect.OffsetRect(point); if (rect.left >= m_rcScroll.left && rect.right <= m_rcScroll.right) { //合法拖动滑块 m_rcSlider.left = rect.left;//更新滑块左边坐标 m_rcSlider.right = rect.right;//更新滑块右边坐标 InvalidateRect(m_rcScroll);//刷新通道 SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBTRACK, m_rcSlider.left-m_iLTUPBtn), NULL); m_bIsEnd = FALSE; } else { //拖动滑块不合法: 超出左边 或者 右边 if (!m_bIsEnd && rect.left < m_rcScroll.left) { //超出左边 m_bIsEnd = TRUE; SendMessage(WM_HSCROLL, MAKEWPARAM(SB_LEFT, m_rcScroll.left), NULL); } else if(!m_bIsEnd && rect.right > m_rcScroll.right) { //超出右边 m_bIsEnd = TRUE; SendMessage(WM_HSCROLL, MAKEWPARAM(SB_RIGHT, m_rcScroll.right), NULL); } } break; } case SB_VERT: { point.y = _point.y - m_ptMouseLastPoint.y; rect.OffsetRect(point); if (rect.top >= m_rcScroll.top && rect.bottom <= m_rcScroll.bottom) { //合法拖动滑块 m_rcSlider.top = rect.top;//更新滑块顶部坐标 m_rcSlider.bottom = rect.bottom;//更新滑块底部坐标 InvalidateRect(m_rcScroll);//刷新通道 SendMessage(WM_VSCROLL, MAKEWPARAM(SB_THUMBTRACK, m_rcSlider.top-m_iLTUPBtn), NULL); m_bIsEnd = FALSE; } else { //拖动滑块不合法: 超出顶部 或者 底部 if (!m_bIsEnd && rect.top < m_rcScroll.top) { //超出顶部 m_bIsEnd = TRUE; SendMessage(WM_VSCROLL, MAKEWPARAM(SB_TOP, m_rcScroll.top), NULL); } else if(!m_bIsEnd && rect.bottom > m_rcScroll.bottom) { //超出底部 m_bIsEnd = TRUE; SendMessage(WM_VSCROLL, MAKEWPARAM(SB_BOTTOM, m_rcScroll.bottom), NULL); } } break; } } } void ScrollBar::OnClickLTUPBtn()//点击了(左箭头/顶部箭头) { int iSpace = 0; int iPage = 0; switch (m_iBar) { case SB_HORZ: { //_output_debug_("点击了左箭头"); iSpace = m_rcScroll.Width() - m_rcSlider.Width();//计算出滑块能滑动的最大距离 iPage = int((float)iSpace / ((float)iSpace / 10.0f));//点击一次箭头 滑块移动的距离 if (m_rcSlider.left - iPage >= m_rcScroll.left) { //合法滑动 } else { //滑动可能超出左边 iPage = m_rcSlider.left-m_rcScroll.left;//重置到尽头 } if (iPage) { m_rcSlider.OffsetRect(-iPage, 0); InvalidateRect(m_rcScroll); SendMessage(WM_HSCROLL, MAKEWPARAM(SB_LINELEFT, iPage), NULL); } break; } case SB_VERT: { //_output_debug_("点击了顶部箭头"); iSpace = m_rcScroll.Height() - m_rcSlider.Height();//计算出滑块能滑动的最大距离 iPage = int((float)iSpace / ((float)iSpace / 10.0f));//点击一次箭头 滑块移动的距离 if (m_rcSlider.top - iPage >= m_rcScroll.top) { //合法滑动 } else { //滑动可能超出顶部 iPage = m_rcSlider.top - m_rcScroll.top;//重置到尽头 } if (iPage) { m_rcSlider.OffsetRect(0, -iPage); InvalidateRect(m_rcScroll); SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEUP, iPage), NULL); } break; } } } void ScrollBar::OnClickRTDNBtn()//点击了(右箭头/底部箭头) { int iSpace = 0; int iPage = 0; switch (m_iBar) { case SB_HORZ: { //_output_debug_("点击了右箭头"); iSpace = m_rcScroll.Width() - m_rcSlider.Width();//计算出滑块能滑动的最大距离 iPage = int((float)iSpace / ((float)iSpace / 10.0f));//点击一次箭头 滑块移动的距离 if (m_rcSlider.right + iPage <= m_rcScroll.right) { //合法滑动 } else { //滑动可能超出右边 iPage = m_rcScroll.right - m_rcSlider.right;//重置到尽头 } if (iPage) { m_rcSlider.OffsetRect(iPage, 0); InvalidateRect(m_rcScroll); SendMessage(WM_HSCROLL, MAKEWPARAM(SB_LINERIGHT, iPage), NULL); } break; } case SB_VERT: { //_output_debug_("点击了底部箭头"); iSpace = m_rcScroll.Height() - m_rcSlider.Height();//计算出滑块能滑动的最大距离 iPage = int((float)iSpace / ((float)iSpace / 10.0f));//点击一次箭头 滑块移动的距离 if (m_rcSlider.bottom + iPage <= m_rcScroll.bottom) { //合法滑动 } else { //滑动可能超出底部 iPage = m_rcScroll.bottom - m_rcSlider.bottom;//重置到尽头 } if (iPage) { m_rcSlider.OffsetRect(0, iPage); InvalidateRect(m_rcScroll); SendMessage(WM_VSCROLL, MAKEWPARAM(SB_LINEDOWN, iPage), NULL); } break; } } } void ScrollBar::SetTarget(CWnd* _pTargetWnd) { m_pTargetWnd = _pTargetWnd; } BOOL ScrollBar::SetScrollInfo(SCROLLINFO& _refScrollInfo, BOOL _bRedraw) { if (_refScrollInfo.nMax > (int)_refScrollInfo.nPage) { CRect rect = m_infoScrollBar.rcScrollBar;//出滚动条的范围 float fRatio = 0.0f;//比率 int iSliderLen = 0;//滑块(长度/宽度) int iPos = 0; int iLTUP = 0; int iRTDN = 0; bool bIsValid = false; if ((_refScrollInfo.fMask & (SIF_RANGE | SIF_PAGE | SIF_POS)) == false)//提供的fMask权限不足 { return false; } switch (m_iBar) { case SB_HORZ: { fRatio = (float)(rect.Width() - (m_iLTUPBtn + m_iRTDNBtn)) / (float)_refScrollInfo.nMax;//计算比率: (总长度-2个箭头) / 目标控件内容最大可视范围 iSliderLen = (int)((float)rect.Width() * fRatio);//计算滑块的(长度) 水平滚动条 if (iSliderLen < m_iMinSlider)//如果滑块太短了 { iSliderLen = m_iMinSlider;//使用最小滑块长度 fRatio = (float)(rect.Width() - (m_iLTUPBtn + m_iRTDNBtn + m_iMinSlider)) / (float)_refScrollInfo.nMax;//重新计算比率: (总长度-2个箭头-最小滑块长度) / 目标控件内容最大可视范围 } iPos = (int)((float)_refScrollInfo.nPos * fRatio);//根据提供的nPos算出应该滚动的距离 iLTUP = iPos + m_iLTUPBtn;//算出滑块左边的坐标值 iRTDN = iLTUP + iSliderLen;//算出滑块右边的坐标值 if (iLTUP >= m_rcScroll.left && iRTDN <= m_rcScroll.right)//如果滑块左右两边都位于滚动条通道内,提供的nPos合法 { m_rcSlider.left = iLTUP; m_rcSlider.right = iRTDN; if (_bRedraw) InvalidateRect(m_rcScroll);//更新通道内容 bIsValid = true;//操作合法 m_fRatio = fRatio;//更新比率 } else { //提供的nPos不合法 return FALSE; } break; } case SB_VERT: { fRatio = (float)(rect.Height() - (m_iLTUPBtn + m_iRTDNBtn)) / (float)_refScrollInfo.nMax;//计算比率: (总宽度-2个箭头) / 目标控件内容最大可视范围 iSliderLen = (int)((float)rect.Height() * fRatio);//计算滑块的(宽度) 垂直滚动条 if (iSliderLen < m_iMinSlider)//如果滑块太短了 { iSliderLen = m_iMinSlider;//使用最小滑块宽度 fRatio = (float)(rect.Height() - (m_iLTUPBtn + m_iRTDNBtn + m_iMinSlider)) / (float)_refScrollInfo.nMax;//重新计算比率: (总宽度-2个箭头-最小滑块宽度) / 目标控件内容最大可视范围 } iPos = (int)((float)_refScrollInfo.nPos * fRatio);//根据提供的nPos算出应该滚动的距离 iLTUP = iPos + m_iLTUPBtn;//算出滑块顶部的坐标值 iRTDN = iLTUP + iSliderLen;//算出滑块底部的坐标值 if (iLTUP >= m_rcScroll.top && iRTDN <= m_rcScroll.bottom)//如果滑块上下两边都位于滚动条通道内,提供的nPos合法 { m_rcSlider.top = iLTUP; m_rcSlider.bottom = iRTDN; if (_bRedraw) InvalidateRect(m_rcScroll);//更新通道内容 bIsValid = true;//操作合法 m_fRatio = fRatio;//更新比率 } else { //提供的nPos不合法 return FALSE; } break; } } //更新scroll info 数据 if (bIsValid && _refScrollInfo.fMask & SIF_ALL) { m_infoScroll = _refScrollInfo;//全部数据复制给内部info m_infoScroll.cbSize = sizeof SCROLLINFO;//系统性修正数据-避免提供的数据有问题 m_infoScroll.fMask = SIF_ALL;//系统性修正数据-避免提供的数据有问题 return TRUE; } else if (bIsValid) { if (_refScrollInfo.fMask & SIF_RANGE) { m_infoScroll.nMin = _refScrollInfo.nMin; m_infoScroll.nMax = _refScrollInfo.nMax; } if (_refScrollInfo.fMask & SIF_PAGE) { m_infoScroll.nPage = _refScrollInfo.nPage; } if (_refScrollInfo.fMask & SIF_POS) { m_infoScroll.nPos = _refScrollInfo.nPos; } //SIF_DISABLENOSCROLL //不处理 //SIF_TRACKPOS //系统内部处理 return TRUE; } } return FALSE; } BOOL ScrollBar::SetScrollPos(int _iPos, BOOL _bRedraw) { int iPos = (int)roundf((float)_iPos * m_fRatio);//根据提供的nPos算出应该滚动的距离 CRect rect; if (_iPos > -1) { switch (m_iBar) { case SB_HORZ: { iPos += m_iLTUPBtn; rect = m_rcSlider; rect.OffsetRect(iPos, 0); if (rect.right <= m_rcScroll.right) { m_rcSlider = rect; if(_bRedraw)InvalidateRect(m_rcScroll); m_infoScroll.nPos = _iPos; m_infoScroll.nTrackPos = _iPos; return TRUE; } else { m_rcSlider.right = m_rcScroll.right; m_rcSlider.left = m_rcSlider.right - rect.Width(); if (_bRedraw)InvalidateRect(m_rcScroll); m_infoScroll.nPos = _iPos; m_infoScroll.nTrackPos = _iPos; } break; } case SB_VERT: { iPos += m_iLTUPBtn; rect = m_rcSlider; rect.OffsetRect(0, iPos); if (rect.bottom <= m_rcScroll.bottom) { m_rcSlider = rect; if (_bRedraw)InvalidateRect(m_rcScroll); m_infoScroll.nPos = _iPos; m_infoScroll.nTrackPos = _iPos; return TRUE; } else { m_rcSlider.bottom = m_rcScroll.bottom; m_rcSlider.top = m_rcScroll.bottom - rect.Height(); if (_bRedraw)InvalidateRect(m_rcScroll); m_infoScroll.nPos = _iPos; m_infoScroll.nTrackPos = _iPos; } break; } } } return FALSE; }
07-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值