如图所示,上方图片显示利用了重绘的CButton控件,下方List利用了CListCtrl,比较麻烦的地方在于图片缩放和移动的控制,实现的功能有:
1.鼠标左键点击上方图片有效区(非黑色区域)的任一点,保存该点在图片中的逻辑坐标,在图片中以绿色点标注该点,同时在下方List中显示坐标
2.鼠标右键点击图片任一点,则将最近保存的点删除,消除显示的标注点和坐标
3.鼠标左键点击下方List的任一行,该行被高亮激活,图上同时对应的标注点变为红色
4.鼠标右键点击下方List中被高亮激活的行时,会出现右键菜单,鼠标左键点击菜单中Delete时,对应保存的点被删除,同时消除显示的标注点和坐标。
5.图片和列表的大小和布局会随着对话框大小改变而改变。
6.当鼠标位置位于图片范围内是,鼠标滚轮滚动可以缩放图片。缩放中心根据鼠标位置自动调整,图片缩放的过程中能够在保持宽高比的情况下尽量填充满整个窗口,而且能够避免缩放过程中图片越界出现黑边。按下鼠标滚轮,拖动一段距离后松开,可以达到拖动图片的目的。
在图片上框取一部分区域来显示,StretchDIBits(dcMem, m_rect.left, m_rect.top, m_rect.Width(), m_rect.Height(),m_nLeft,m_nBottom, m_rect.Width()*m_dZoomScale, m_rect.Height()*m_dZoomScale, m_pData, (BITMAPINFO*)m_pHeader, DIB_RGB_COLORS, SRCCOPY);
其中m_rect为Button的大小,m_rect*m_dZoomScale为框取的大小,m_nLeft,m_nBottom分别为选取框的最左边和最下边,以图像坐标系为参考,图片左下角为初始点(0,0)。
详细代码查看 http://download.csdn.net/detail/qq_26973095/9881516
响应滚轮缩放:
BOOL CButtonPic::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt) { // TODO: Add your message handler code here and/or call default if (m_pHeader == NULL || m_pData == NULL) return FALSE; CPoint point; GetCursorPos(&point); ScreenToClient(&point); if (zDelta == 120) { if (m_dZoomScale > m_dZoomStep) //m_dZoomStep滚轮改变的缩放比例 { m_dZoomScale -= m_dZoomStep; int tmpLeft = m_nLeft + point.x*m_dZoomStep; int tmpBottom = m_nBottom + (m_rect.Height() - point.y)*m_dZoomStep; //以鼠标所在位置为中心放大图片 if (tmpLeft < 0 || (m_pHeader->biWidth - tmpLeft) < m_dZoomScale*m_rect.Width())//如果放大后的图片在宽度上不能完全覆盖rect的宽度 { //则将放大中心的纵坐标设置在rect的半高处;下面同理 m_nLeft = m_nLeft + m_rect.Width() *m_dZoomStep / 2; } else { m_nLeft = tmpLeft; } if (tmpBottom < 0 || (m_pHeader->biHeight - tmpBottom) < m_dZoomScale*m_rect.Height()) //m_pHeader为位图的信息头 { m_nBottom = m_nBottom + m_rect.Height()*m_dZoomStep / 2 //m_rect为Button的大小,m_rect*m_dZoomScale为框取的大小 } else { m_nBottom = tmpBottom; } } } else if (zDelta == -120) { if (m_dZoomScale < m_dInitialZScale) //m_dInitialZScale为初始时的缩放比例,此时图像最小,恰好塞满整个rect { m_dZoomScale += m_dZoomStep; int tmpLeft = m_nLeft - point.x*m_dZoomStep; int tmpBottom = m_nBottom - (m_rect.Height() - point.y)*m_dZoomStep; if (tmpLeft < 0) //如果放大后选取的框在图像最左边的左边,即左边出现黑 { //则将选取框往右移 m_nLeft = 0; } else if ((m_pHeader->biWidth - tmpLeft) < m_dZoomScale*m_rect.Width()) //不能让图片缩小后出现黑边 { //则将选取框往左移 m_nLeft = m_pHeader->biWidth - m_dZoomScale*m_rect.Width(); } else { m_nLeft = tmpLeft; } if (tmpBottom < 0) { m_nBottom = 0; } else if ((m_pHeader->biHeight - tmpBottom) < m_dZoomScale*m_rect.Height()) //不能让图片缩小后出现黑边 { m_nBottom = m_pHeader->biHeight - m_dZoomScale*m_rect.Height(); } else { m_nBottom = tmpBottom; } if (m_dZoomScale*m_rect.Height() > m_pHeader->biHeight) //不能让图片缩小后出现黑边 { m_nBottom = (m_pHeader->biHeight - m_rect.Height()*m_dZoomScale) / 2; } if (m_dZoomScale*m_rect.Width() > m_pHeader->biWidth) //不能让图片缩小后出现黑边 { m_nLeft = (m_pHeader->biWidth - m_rect.Width()*m_dZoomScale) / 2; } } } Invalidate(); return CButton::OnMouseWheel(nFlags, zDelta, pt); }