paint_rect.cpp

本文介绍了一个简单的Windows应用程序实例,包括窗口类注册、消息处理及基本绘图功能。通过使用Windows API函数,展示了如何创建窗口、响应用户操作并进行简单图形绘制。

  name="google_ads_frame" marginwidth="0" marginheight="0" src="http://pagead2.googlesyndication.com/pagead/ads?client=ca-pub-5572165936844014&dt=1194442938015&lmt=1194190197&format=336x280_as&output=html&correlator=1194442937843&url=file%3A%2F%2F%2FC%3A%2FDocuments%2520and%2520Settings%2Flhh1%2F%E6%A1%8C%E9%9D%A2%2FCLanguage.htm&color_bg=FFFFFF&color_text=000000&color_link=000000&color_url=FFFFFF&color_border=FFFFFF&ad_type=text&ga_vid=583001034.1194442938&ga_sid=1194442938&ga_hid=1942779085&flash=9&u_h=768&u_w=1024&u_ah=740&u_aw=1024&u_cd=32&u_tz=480&u_java=true" frameborder="0" width="336" scrolling="no" height="280" allowtransparency="allowtransparency"> 
#include <windows.h> 
#include "Paint_Rect.h"


#if defined (WIN32)
 #define IS_WIN32 TRUE
#else
 #define IS_WIN32 FALSE
#endif

#define IS_NT      IS_WIN32 && (BOOL)(GetVersion() < 0x80000000)
#define IS_WIN32S  IS_WIN32 && (BOOL)(!(IS_NT) && (LOBYTE(LOWORD(GetVersion()))<4))
#define IS_WIN95   (BOOL)(!(IS_NT) && !(IS_WIN32S)) && IS_WIN32

HINSTANCE hInst;   // current instance

LPCTSTR lpszAppName  = "MyApp";
LPCTSTR lpszTitle    = "My Application";

BOOL RegisterWin95( CONST WNDCLASS* lpwc );

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance,
                      LPTSTR lpCmdLine, int nCmdShow)
{
   MSG      msg;
   HWND     hWnd;
   WNDCLASS wc;

   // Register the main application window class.
   //............................................
   wc.style         = CS_HREDRAW | CS_VREDRAW;
   wc.lpfnWndProc   = (WNDPROC)WndProc;      
   wc.cbClsExtra    = 0;                     
   wc.cbWndExtra    = 0;                     
   wc.hInstance     = hInstance;             
   wc.hIcon         = LoadIcon( hInstance, lpszAppName );
   wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
   wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
   wc.lpszMenuName  = lpszAppName;             
   wc.lpszClassName = lpszAppName;             

   if ( IS_WIN95 )
   {
      if ( !RegisterWin95( &wc ) )
         return( FALSE );
   }
   else if ( !RegisterClass( &wc ) )
      return( FALSE );

   hInst = hInstance;

   // Create the main application window.
   //....................................
   hWnd = CreateWindow( lpszAppName,
                        lpszTitle,   
                        WS_OVERLAPPEDWINDOW,
                        CW_USEDEFAULT, 0,
                        CW_USEDEFAULT, 0, 
                        NULL,             
                        NULL,             
                        hInstance,        
                        NULL              
                      );

   if ( !hWnd )
      return( FALSE );

   ShowWindow( hWnd, nCmdShow );
   UpdateWindow( hWnd );        

   while( GetMessage( &msg, NULL, 0, 0) )  
   {
      TranslateMessage( &msg );
      DispatchMessage( &msg ); 
   }

   return( msg.wParam );
}


BOOL RegisterWin95( CONST WNDCLASS* lpwc )
{
   WNDCLASSEX wcex;

   wcex.style         = lpwc->style;
   wcex.lpfnWndProc   = lpwc->lpfnWndProc;
   wcex.cbClsExtra    = lpwc->cbClsExtra;
   wcex.cbWndExtra    = lpwc->cbWndExtra;
   wcex.hInstance     = lpwc->hInstance;
   wcex.hIcon         = lpwc->hIcon;
   wcex.hCursor       = lpwc->hCursor;
   wcex.hbrBackground = lpwc->hbrBackground;
   wcex.lpszMenuName  = lpwc->lpszMenuName;
   wcex.lpszClassName = lpwc->lpszClassName;

   // Added elements for Windows 95.
   //...............................
   wcex.cbSize = sizeof(WNDCLASSEX);
   wcex.hIconSm = LoadImage(wcex.hInstance, lpwc->lpszClassName,
                            IMAGE_ICON, 16, 16,
                            LR_DEFAULTCOLOR );
   
   return RegisterClassEx( &wcex );
}

LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
   switch( uMsg )
   {
      case WM_COMMAND :
              switch( LOWORD( wParam ) )
              {
                 case IDM_TEST :
                        {
                           HDC     hDC;
                           HBRUSH  hOldBrush;
                           RECT    rect;

                           GetClientRect( hWnd, &rect );

                           hDC = GetDC( hWnd );

                           // Paint gray box.
                           //................
                           hOldBrush = SelectObject( hDC,
                                            GetStockObject( LTGRAY_BRUSH ) );
                           PatBlt( hDC, 5, 5, 60, 40, PATCOPY );

                           // Paint 3D border.
                           //.................
                           SelectObject( hDC, GetStockObject( GRAY_BRUSH ) );
                           PatBlt( hDC, 10, 40, 52, 2, PATCOPY );
                           PatBlt( hDC, 60,  8, 2, 32, PATCOPY );

                           SelectObject( hDC, GetStockObject( WHITE_BRUSH ) );
                           PatBlt( hDC, 8,  8, 52,  2, PATCOPY );
                           PatBlt( hDC, 8, 10,  2, 32, PATCOPY );

                           SelectObject( hDC, hOldBrush );
                           ReleaseDC( hWnd, hDC );
                        }
                        break;

                 case IDM_ABOUT :
                        DialogBox( hInst, "AboutBox", hWnd, (DLGPROC)About );
                        break;

                 case IDM_EXIT :
                        DestroyWindow( hWnd );
                        break;
              }
              break;
     
      case WM_DESTROY :
              PostQuitMessage(0);
              break;

      default :
            return( DefWindowProc( hWnd, uMsg, wParam, lParam ) );
   }

   return( 0L );
}


LRESULT CALLBACK About( HWND hDlg,          
                        UINT message,       
                        WPARAM wParam,      
                        LPARAM lParam)
{
   switch (message)
   {
       case WM_INITDIALOG:
               return (TRUE);

       case WM_COMMAND:                             
               if (   LOWORD(wParam) == IDOK        
                   || LOWORD(wParam) == IDCANCEL)   
               {
                       EndDialog(hDlg, TRUE);       
                       return (TRUE);
               }
               break;
   }

   return (FALSE);
}

请根据我提供的滚动条控件源码,重构一个更高效的控件给我 #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
// GradientProgressCtrl.cpp : implementation file // #include "stdafx.h" #include "VProgressCtrl.h" //#include "MemDC.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif class CMemDC : public CDC { public: CMemDC(CDC* pDC); CMemDC* operator->(){return this;} operator CMemDC*(){return this;} virtual ~CMemDC(); private: CBitmap m_bitmap; CBitmap* m_pOldBitmap; CDC* m_pDC; CRect m_rect; BOOL m_bMemDC; }; CMemDC::CMemDC(CDC* pDC):CDC() { ASSERT(pDC!=NULL); m_pDC=pDC; m_pOldBitmap=NULL; m_bMemDC=!pDC->IsPrinting(); // if(m_bMemDC) { pDC->GetClipBox(&m_rect); CreateCompatibleDC(pDC); m_bitmap.CreateCompatibleBitmap(pDC,m_rect.Width(),m_rect.Height()); m_pOldBitmap=SelectObject(&m_bitmap); SetWindowOrg(m_rect.left,m_rect.top); } else //为相关的现有设备准备打印 { m_bPrinting=pDC->m_bPrinting; m_hDC=pDC->m_hDC; m_hAttribDC=pDC->m_hAttribDC; } } CMemDC::~CMemDC() { if(m_bMemDC) { m_pDC->BitBlt(m_rect.left,m_rect.top,m_rect.Width(),m_rect.Height(), this,m_rect.left,m_rect.top,SRCCOPY); SelectObject(m_pOldBitmap); } else { m_hDC=m_hAttribDC=NULL; } } ///////////////////////////////////////////////////////////////////////////// // CVProgressCtrl CVProgressCtrl::CVProgressCtrl() : m_nTextType(TextCustom) , m_strFormat(_T("%s")) , m_nLower(0) , m_nUpper(100) , m_nCurrentPosition(0) , m_nStep(1) , m_clrStart(RGB(255,0,0)) , m_clrEnd(RGB(0,0,255)) , m_clrBkGround(GetSysColor(COLOR_3DFACE)) , m_clrText(RGB(255,255,255)) { m_nLower=0; m_nUpper=100; m_nCurrentPosition=0; m_nStep=10; } CVProgressCtrl::~CVProgressCtrl() { } BEGIN_MESSAGE_MAP(CVProgressCtrl, CProgressCtrl) //{{AFX_MSG_MAP(CVProgressCtrl) ON_WM_ERASEBKGND() ON_WM_PAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CVProgressCtrl message handlers void CVProgressCtrl::SetRange(int nLower,int nUpper) { //This Function is to Set Range of the progress m_nLower=nLower; m_nUpper=nUpper; m_nCurrentPosition=nLower; CProgressCtrl::SetRange(nLower,nUpper); } int CVProgressCtrl::SetStep(int nStep) { m_nStep=nStep; return (CProgressCtrl::SetStep(nStep)); } BOOL CVProgressCtrl::OnEraseBkgnd(CDC* pDC) { // TODO: Add your message handler code here and/or call default return TRUE;//CProgressCtrl::OnEraseBkgnd(pDC); } void CVProgressCtrl::DrawGradient(CPaintDC *pDC, const RECT &rectClient, const int &nMaxWidth) { RECT rectFill; //显示区域 float fStep; //每一步的幅宽 CBrush brush; //显示的颜色画刷 CMemDC memDC(pDC); int r,g,b; float rStep,gStep,bStep; //得到不同颜色并相减,返回颜色之间的最大差值 r=(GetRValue(m_clrEnd)-GetRValue(m_clrStart)); g=(GetGValue(m_clrEnd)-GetGValue(m_clrStart)); b=(GetBValue(m_clrEnd)-GetBValue(m_clrStart)); //使进程条显示的总数 等于最大的颜色差值 int nSteps=max(abs(r),max(abs(g),abs(b))); //确定每一颜色填充多大的矩形区域 fStep=(float)rectClient.right/(float)nSteps; //设置每一颜色填充的步数 rStep=r/(float)nSteps; gStep=g/(float)nSteps; bStep=b/(float)nSteps; r=GetRValue(m_clrStart); g=GetGValue(m_clrStart); b=GetBValue(m_clrStart); //绘制颜色渐变的进程条 for(int iOnBand=0;iOnBand<nSteps;iOnBand++) { ::SetRect(&rectFill, //以下为填充矩形区域的左上角x,y和右下角x,y (int)(iOnBand*fStep), 0, (int)((iOnBand+1)*fStep), rectClient.bottom+1); VERIFY(brush.CreateSolidBrush(RGB(r+rStep*iOnBand,g+gStep*iOnBand,b+bStep*iOnBand))); memDC.FillRect(&rectFill,&brush); VERIFY(brush.DeleteObject()); //在结束绘制之前,使用背景色填充乘下的的客户区域 if(rectFill.right>nMaxWidth) { ::SetRect(&rectFill,rectFill.right,0,rectClient.right,rectClient.bottom); VERIFY(brush.CreateSolidBrush(m_clrBkGround)); memDC.FillRect(&rectFill,&brush); VERIFY(brush.DeleteObject()); return; } } } void CVProgressCtrl::DrawProgressText(CPaintDC& dc,RECT& rectClient) { //根据文本类型,设置显示的文本 switch(m_nTextType) { case TextPercent: m_strText.Format(m_strFormat,(int)(100*(float)m_nCurrentPosition/m_nUpper)); break; case TextPos: m_strText.Format(m_strFormat,m_nCurrentPosition); break; default://TextCustom break; } //设置文本颜色 dc.SetTextColor(m_clrText); dc.SetBkMode(TRANSPARENT); //绘制文本 dc.DrawText(m_strText,&rectClient,DT_VCENTER|DT_CENTER|DT_SINGLELINE); } void CVProgressCtrl::OnPaint() { CPaintDC dc(this); // device context for painting // TODO: Add your message handler code here if(m_nCurrentPosition<=m_nLower||m_nCurrentPosition>=m_nUpper) { CRect rect; GetClientRect(rect); CBrush brush; brush.CreateSolidBrush(::GetSysColor(COLOR_3DFACE)); dc.FillRect(&rect,&brush); VERIFY(brush.DeleteObject()); return; } CRect rectClient; GetClientRect(rectClient); float maxWidth((float)m_nCurrentPosition/(float)m_nUpper*(float)rectClient.right); //绘制进度条 DrawGradient(&dc,rectClient,(int)maxWidth); //绘制进度条文本 DrawProgressText(dc,rectClient); // Do not call CProgressCtrl::OnPaint() for painting messages } int CVProgressCtrl::SetPos(int nPos) { //Set the Position of the Progress m_nCurrentPosition = nPos; return (CProgressCtrl::SetPos(nPos)); } void CVProgressCtrl::SetText(LPCTSTR lpcszText) { m_strText.Format(m_strFormat,lpcszText); this->Invalidate(); } void CVProgressCtrl::SetTextType(int nTextType,LPCTSTR lpszFormat) { m_nTextType = nTextType;//文本类型 m_strFormat = lpszFormat;//文本格式化 int nIndex;//内容在格式化中的位置 if (m_strFormat.GetLength() == 0) { nIndex = 0; } else { int nTemp = m_strFormat.Find(_T("%s")); if (nTemp == -1) { nIndex = m_strFormat.GetLength(); } else { nIndex = nTemp; m_strFormat.Delete(nTemp,2); while ((nTemp = m_strFormat.Find(_T("%"),nTemp)) > -1) { m_strFormat.Insert(nTemp,_T("%")); nTemp += 2; } } } //根据文本类型不同,设置格式化字符串 switch(m_nTextType) { case TextPercent: m_strFormat.Insert(nIndex,_T("%d%%")); break; case TextPos: m_strFormat.Insert(nIndex,_T("%d")); break; default: m_strFormat.Insert(nIndex,_T("%s")); break; } } 这个代码中为什么进度条到达100%后会重置为0
06-04
// MFCPaintView.cpp: CMFCPaintView 类的实现 // #include "pch.h" #include "framework.h" // SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的 // ATL 项目中进行定义,并允许与该项目共享文档代码。 #ifndef SHARED_HANDLERS #include "MFCPaint.h" #endif #include "MFCPaintDoc.h" #include "MFCPaintView.h" #include "CMy_Global.h" #ifdef _DEBUG #define new DEBUG_NEW #endif // CMFCPaintView IMPLEMENT_DYNCREATE(CMFCPaintView, CView) BEGIN_MESSAGE_MAP(CMFCPaintView, CView) // 标准打印命令 ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint) ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CView::OnFilePrintPreview) ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_MOUSEMOVE() END_MESSAGE_MAP() // CMFCPaintView 构造/析构 CMFCPaintView::CMFCPaintView() noexcept { // TODO: 在此处添加构造代码 isPainting = false; isLoading = false; isWriting = false; } CMFCPaintView::~CMFCPaintView() { } BOOL CMFCPaintView::PreCreateWindow(CREATESTRUCT& cs) { // TODO: 在此处通过修改 // CREATESTRUCT cs 来修改窗口类或样式 return CView::PreCreateWindow(cs); } // CMFCPaintView 绘图 void CMFCPaintView::OnDraw(CDC* /*pDC*/) { CMFCPaintDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 } // CMFCPaintView 打印 BOOL CMFCPaintView::OnPreparePrinting(CPrintInfo* pInfo) { // 默认准备 return DoPreparePrinting(pInfo); } void CMFCPaintView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: 添加额外的打印前进行的初始化过程 } void CMFCPaintView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/) { // TODO: 添加打印后进行的清理过程 } // CMFCPaintView 诊断 #ifdef _DEBUG void CMFCPaintView::AssertValid() const { CView::AssertValid(); } void CMFCPaintView::Dump(CDumpContext& dc) const { CView::Dump(dc); } CMFCPaintDoc* CMFCPaintView::GetDocument() const // 非调试版本是内联的 { ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCPaintDoc))); return (CMFCPaintDoc*)m_pDocument; } #endif //_DEBUG // CMFCPaintView 消息处理程序 void CMFCPaintView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 P_Start = point; isPainting = true; CView::OnLButtonDown(nFlags, point); } void CMFCPaintView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (isWriting) { CDC* pdc = GetDC(); CFont new_font; //创建字体宋体格式 100为字高 VERIFY(new_font.CreatePointFont(250, _T("宋体"), pdc)); //选择该字体进入PDC CFont* default_font = pdc->SelectObject(&new_font); //设置字体颜色 pdc->SetTextColor(Line_Color); pdc->TextOut(point.x, point.y, Text); isWriting = false; isPainting = false; return; } if (isLoading) { isLoading = false; return; } if (Shape_Type == 6) { isPainting = false; return; } P_End = point; CPen* pNewPen; CPen* pOldPen; CBrush* pNewBrush1; CBrush* pOldBrush1; CDC* pdc = GetDC(); if (Shape_Type == 4) { pNewPen = new CPen; pNewPen->CreatePen(Line_Type, Line_Width, Line_Color); pOldPen = pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 //画矩形 pdc->Ellipse(P_Start.x, P_Start.y, P_End.x, P_End.y); //恢复原有的笔 pdc->SelectObject(pOldPen); delete pNewPen; if (isfill) { pNewBrush1 = new CBrush; pNewBrush1->CreateSolidBrush(Fill_Color); //选择新画刷 pOldBrush1 = pdc->SelectObject(pNewBrush1); //绘制圆 pdc->Ellipse(P_Start.x, P_Start.y, P_End.x, P_End.y); //恢复原有画刷 pdc->SelectObject(pOldBrush1); delete pNewBrush1; } } else if (Shape_Type == 2) { pNewPen = new CPen; pNewPen->CreatePen(Line_Type, Line_Width, Line_Color); pOldPen = pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 //画矩形 pdc->Rectangle(P_Start.x, P_Start.y, P_End.x, P_End.y); //恢复原有的笔 pdc->SelectObject(pOldPen); delete pNewPen; if (isfill) { pNewBrush1 = new CBrush; pNewBrush1->CreateSolidBrush(Fill_Color); //选择新画刷 pOldBrush1 = pdc->SelectObject(pNewBrush1); //绘制矩形 pdc->Rectangle(P_Start.x, P_Start.y, P_End.x, P_End.y); //恢复原有画刷 pdc->SelectObject(pOldBrush1); delete pNewBrush1; } } else if (Shape_Type == 1) { pNewPen = new CPen; pNewPen->CreatePen(Line_Type, Line_Width, Line_Color); pOldPen = pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 //画直线 pdc->MoveTo(P_Start.x, P_Start.y); pdc->LineTo(P_End.x, P_End.y); //恢复原有的笔 pdc->SelectObject(pOldPen); delete pNewPen; } else if (Shape_Type == 3) { pNewPen = new CPen; pNewPen->CreatePen(Line_Type, Line_Width, Line_Color); pOldPen = pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 //画矩形 int d = P_End.x - P_Start.x; pdc->Ellipse(P_Start.x, P_Start.y, P_Start.x + d, P_Start.y + d); //恢复原有的笔 pdc->SelectObject(pOldPen); delete pNewPen; if (isfill) { pNewBrush1 = new CBrush; pNewBrush1->CreateSolidBrush(Fill_Color); //选择新画刷 pOldBrush1 = pdc->SelectObject(pNewBrush1); //绘制圆 pdc->Ellipse(P_Start.x, P_Start.y, P_Start.x + d, P_Start.y + d); //恢复原有画刷 pdc->SelectObject(pOldBrush1); delete pNewBrush1; } } else if (Shape_Type == 5) { pNewPen = new CPen; pNewPen->CreatePen(Line_Type, Line_Width, Line_Color); pOldPen = pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 // 定义一个矩形,用于确定弧线的边界 CRect rect(P_Start.x, P_Start.y, P_End.x, P_End.y); // 绘制一条从point1到point2的弧线 pdc->Arc(rect, P_Start, P_End); //恢复原有的笔 pdc->SelectObject(pOldPen); delete pNewPen; } isPainting = false; CView::OnLButtonUp(nFlags, point); } void CMFCPaintView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (Shape_Type == 6 && isPainting) { CPen* pNewPen; CDC* pdc = GetDC(); pNewPen = new CPen; pNewPen->CreatePen(0, Line_Width, Line_Color); pdc->SelectObject(pNewPen); //选择新笔,并保存旧笔 pdc->MoveTo(P_Start); pdc->LineTo(point); P_Start = point; delete pNewPen; } CView::OnMouseMove(nFlags, point); } void CMFCPaintView::ClearDrawing() { // 示例代码:将绘图缓冲区清空为白色背景 CClientDC dc(this); CRect rect; GetClientRect(&rect); dc.FillSolidRect(rect, RGB(255, 255, 255)); } void CMFCPaintView::LoadMyImage() { CFileDialog fileDlg(TRUE, _T("png"), NULL, 0, _T("image Files(*.bmp; *.jpeg;*.jpg;*.png)|*.JPG;*.PNG;*.BMP|All Files (*.*) |*.*|"), this); fileDlg.DoModal(); CString StrFilePath = fileDlg.GetPathName(); if (StrFilePath == _T("")) { return; } CDC* pdc = GetDC(); CRect rect; GetClientRect(&rect); CImage image; image.Load(StrFilePath); image.BitBlt(*pdc, 40, 40, rect.Width(), rect.Height(), 0, 0); image.Destroy(); //没有Destroy()会有内存泄漏。Detach();不行的。 isLoading = true; } void CMFCPaintView::SavePainting() { CClientDC dc(this); CRect rect; //BOOL showMsgTag; //是否要弹出”图像保存成功对话框" GetClientRect(&rect); //获取画布大小 HBITMAP hbitmap = CreateCompatibleBitmap(dc, rect.right - rect.left, rect.bottom - rect.top); //创建兼容位图 HDC hdc = CreateCompatibleDC(dc); //创建兼容DC,以便将图像保存为不同的格式 HBITMAP hOldMap = (HBITMAP)SelectObject(hdc, hbitmap); //将位图选入DC,并保存返回值 BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dc, 0, 0, SRCCOPY); //将屏幕DC的图像复制到内存DC中 CImage image; image.Attach(hbitmap); //将位图转化为一般图像 CString strFilter = _T("位图文件(*.bmp)|*.bmp|JPEG 图像文件|*.jpg|GIF图像文件 | *.gif | PNG图像文件 | *.png |其他格式(*.*) | *.* || "); CFileDialog dlg(FALSE, _T("bmp"), _T("iPaint1.bmp"), NULL, strFilter); if (dlg.DoModal() != IDOK) return; CString strFileName; //如果用户没有指定文件扩展名,则为其添加一个 CString strExtension; strFileName = dlg.m_ofn.lpstrFile; if (dlg.m_ofn.nFileExtension == 0) //扩展名项目为0 { switch (dlg.m_ofn.nFilterIndex) { case 1: strExtension = "bmp"; break; case 2: strExtension = "jpg"; break; case 3: strExtension = "gif"; break; case 4: strExtension = "png"; break; default: break; } strFileName = strFileName + "." + strExtension; } saveFilePath = strFileName; //saveFilePath为视类中的全局变量,类型为CString HRESULT hResult = image.Save(saveFilePath); //保存图像 if (FAILED(hResult)) { MessageBox(_T("保存图像文件失败!")); } else { MessageBox(_T("文件保存成功!")); } image.Detach(); SelectObject(hdc, hOldMap); } 帮我改成项目名为202402172226lgqsx
06-20
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值