概述

本程序软件的主要实现垃圾文件清理的功能,即对指定的文件格式的临时文件或垃圾文件进行遍历、扫描、显示、删除清理等功能。在程序界面设计方面,对默认对话框重新自定义绘制,主要包括标题栏的重绘、对话框边框的重绘、对话框背景重绘、以及最小化按钮、最大化按钮和关闭按钮等的重绘实现。经过界面的设计和功能的实现开发,从而开发出一款具有实用意义的垃圾清理工具。

详细

一、简要概述

先来上个图吧:

下面就是详细介绍开发这个小程序的大体方法和步骤吧。程序是基于VC++程序设计与开发为背景,着重分析了垃圾文件清理原理和对话框程序界面的设计与开发原理,首先简要介绍VC++程序设计开发的基本方法;然后说明垃圾文件清理的原理和以绘制位图技术为背景的对话框绘制界面技术,最后重点介绍了垃圾清理程序的设计与实现。

1:概述:

本程序的主要实现垃圾文件清理的功能,即对指定的文件格式的临时文件或垃圾文件进行遍历、扫描、显示、删除清理等功能。在程序界面设计方面,对默认对话框重新自定义绘制,主要包括标题栏的重绘、对话框边框的重绘、对话框背景重绘、以及最小化按钮、最大化按钮和关闭按钮等的重绘实现。经过界面的设计和功能的实现开发,从而开发出一款具有实用意义的垃圾清理工具。

2:开发环境:

程序开发平台是基于Microsoft Visual Studio 2008 集成开发环境,编程技术采用Visual C++(MFC) 编程技术,以及相关的开发软件如Photoshop CS5等。

3:需求分析:

本程序的设计与开发主要分为两大模块,功能的设计开发和应用程序界面的设计开发。

功能的分析与设计:垃圾清理功能主要包括文件遍历扫描、显示已扫描到的文件以及垃圾文件的删除清理等。用户需要一边进行文件扫描,另一边可以对已经扫描到的垃圾文件进行清理操作。文件扫描通常会占用大量的时间,为了提高垃圾清理的可靠性和效率,应该使用多线程开发技术,即将文件扫描的任务放置在一个单独的线程中即可。

应用程序界面设计:在对话框重绘中,使用的主要技术有两个,一个是绘制对话框的背景位图,在对话框大小改变时能够输出位图,使位图能够适应对话框的大小。另一个是在对话框的指定区域输出位图。

二、核心功能设计、开发和实现

下面我们就是开始代码实现了,下面先开始实现功能部分,即垃圾文件的扫描、显示和清理。

功能的分析与设计:垃圾清理功能主要包括文件遍历扫描、显示已扫描到的文件以及垃圾文件的删除清理等。用户需要一边进行文件扫描,另一边可以对已经扫描到的垃圾文件进行清理操作。文件扫描通常会占用大量的时间,为了提高垃圾清理的可靠性和效率,应该使用多线程开发技术,即将文件扫描的任务放置在一个单独的线程中即可

(1)创建一个基于对话框的工程,工程名称为“ClearTmpFile”。

(2)向对话框中添加静态文本框、按钮、组合框、列表框、进度条等控件,效果如下:

控件布局图

(3)在对话框类CClearTmpFileDlg中添加共有的主要数据成员,各成员功能见注释部分:

  1. CList<CString, CString> m_fileExtList;//记录需要查找临时文件扩展名
  2. bool m_bThreadExit;//线程是否退出
  3. bool m_bFinding;//是否查找进行中
  4. HANDLE m_hThread;//查找文件的线程句柄
  5. HANDLE m_hThread2;//bmp旋转线程句柄
  6. CString m_szCurDisk;//查找的磁盘
  7. HANDLE m_hEvent;//事件对象,在对话框关闭时将提前结束查找
  8. bool m_bContinue;//判断暂停或继续按钮操作
  9. DWORD GetDiskSize(char* strPath);//获取磁盘容量(已使用的)
  10. DWORD m_dwDiskVol;//磁盘总容量大小,单位为KB
  11. DWORD m_dwScanedVol;//已扫描的文件的容量
  12. DWORD m_dwScanedTmpFileVol;//扫描到的临时文件的容量大小
  13. DWORD m_dwScanedTmpFileNum;//扫描到的临时文件的容量大小

(4)向对话框类中添加ResearchFile方法,判读指定的目录,将指定的垃圾文件类型显示在扫描结果列表中。

  1. void CClearTmpFileDlg::ResearchFile(char * pszPath)
  2. {
  3. char szTmp[MAX_PATH]={0};//定义一个临时字符数组 strcpy(szTmp,pszPath); if(szTmp[strlen(szTmp)-1]!='\\')//将目录以“\\*.*”形式结尾 {
  4. strcat(szTmp,"\\*.*");//连接字符串 } else
  5. {
  6. strcat(szTmp,"*.*");//连接字符串 }
  7. WIN32_FIND_DATA findData;//定义一个文件查找数据结构
  8. memset(&findData,0,sizeof(WIN32_FIND_DATA));
  9. HANDLE hFind = FindFirstFile(szTmp,&findData);//开始查找文件 //由于查找是在线程中进行的,这里判读用户是否退出线程,如果是则提前结束线程函数 if(m_bThreadExit) {
  10. FindClose(hFind);//关闭查找句柄
  11. SetEvent(m_hEvent);//设置事件为有信号
  12. return;
  13. } if(hFind != INVALID_HANDLE_VALUE)//文件查找成功 { while(FindNextFile(hFind,&findData)==TRUE)//查找下一个文件
  14. {//由于查找是在线程中进行的,这里判读用户是否退出线程,如果是则提前结束线程函数
  15. if (m_bThreadExit)
  16. {
  17. FindClose(hFind);//关闭查找句柄
  18. SetEvent(m_hEvent);//设置事件为有信号
  19. return;
  20. } //如果文件不是一个目录
  21. if(!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
  22. {
  23. DWORD dwFileSize = (findData.nFileSizeHigh* (MAXDWORD+1) + findData.nFileSizeLow)/(1024);//获取文件大小,单位为KB
  24. m_dwScanedVol += dwFileSize;//累计已扫描文件的容量大小,单位为KB //m_dwScanedVol = m_dwScanedVol/1024;//单位转换为:MB //设置进度条进度
  25. m_progressCtl.SetPos((m_dwScanedVol/1024)); char szFileName[MAX_PATH] = {0};//定义字符数组,存储完整的文件名
  26. strcpy(szFileName,pszPath);//获取完整文件名
  27. if(szFileName[strlen(szFileName)-1] != '\\')
  28. {
  29. strcat(szFileName,"\\");
  30. }
  31. strcat(szFileName,(char *)findData.cFileName);
  32. if(IsTmpFile(szFileName))//判断szFileName是否是临时文件 {
  33. m_dwScanedTmpFileVol += dwFileSize;//累计扫描到的临时文件容量大小,单位为KB
  34. m_dwScanedTmpFileNum ++;//累计扫描到的临时文件的数目 m_listBoxResults.AddString((LPCTSTR)szFileName);
  35. }
  36. } else//如果文件是一个目录,则递归遍历该目录 { if((strcmp((const char *)&findData.cFileName,"...")!=0) &&
  37. (strcmp((const char *)&findData.cFileName,"..")!=0)&&
  38. (strcmp((const char *)&findData.cFileName,".")!=0))
  39. { char szFileName[MAX_PATH]={0};
  40. strcpy(szFileName,pszPath);//获取完整文件名
  41. if(szFileName[strlen(szFileName)-1]!='\\')
  42. {
  43. strcat(szFileName,"\\");
  44. }
  45. strcat(szFileName,(char *)findData.cFileName); //由于查找是在线程中进行的,这里判读用户是否退出线程,如果是则提前结束线程函数
  46. if(m_bThreadExit)
  47. {
  48. FindClose(hFind);//关闭查找句柄
  49. SetEvent(m_hEvent);//设置事件为有信号
  50. return;
  51. }
  52. ResearchFile(szFileName);//递归调用 }
  53. }
  54. }
  55. }
  56. FindClose(hFind);//关闭文件查找句柄}

(5)定义线程函数,用来单独执行扫描查找垃圾文件任务:

  1. DWORD _stdcall FindTmpFile(LPVOID lpParameter)
  2. {
  3. CClearTmpFileDlg* pDlg = (CClearTmpFileDlg*) lpParameter;//获取线程参数
  4. WaitForSingleObject(pDlg->m_hEvent,INFINITE);//等待事件有信号
  5. CString dir = pDlg->m_szCurDisk.GetBuffer();//根据当前盘符目录磁盘目录
  6. char *s = (LPSTR)(LPCTSTR)dir;
  7. pDlg->ResearchFile(s);
  8. pDlg->Restore();
  9. pDlg->ShowResultText();//显示扫描临时文件的数目和大小
  10. //恢复数据为初始状态
  11. pDlg->m_dwScanedTmpFileVol = 0;
  12. pDlg->m_dwScanedTmpFileNum = 0;
  13. pDlg->m_fileExtList.RemoveAll(); return 0;
  14. }

(6)处理“立即扫描”或“开始”按钮的单击事件,创建一个新的线程执行扫描文件的任务:

  1. //如果查找没有结束,则不允许开始新的文件查找
  2. GetDlgItem(IDC_BEGIN)->ShowWindow(SW_HIDE); if(!m_bFinding && GetTmpExtName())//获取文件扩展名 {
  3. GetDlgItem(IDC_PROGRESS1)->ShowWindow(TRUE);//显示进度条
  4. GetDlgItem(IDC_LIST1)->ShowWindow(SW_SHOW);
  5. m_bThreadExit = FALSE;
  6. m_bFinding = TRUE;
  7. m_combox.GetWindowText(m_szCurDisk);//获取当前盘符
  8. // 初始化进度条相关数据
  9. m_dwDiskVol =GetDiskSize((LPSTR)(LPCTSTR)m_szCurDisk);//获取当前磁盘的容量大小(已使用的) CString str;
  10. str.Format(_T("%d"),m_dwDiskVol/(1024)); double iSize = atoi(str);
  11. m_progressCtl.SetRange32(0,m_dwDiskVol/1024);//初始化进度条,设置进度条的范围,范围为MB的数量
  12. if(m_hEvent!=NULL)
  13. {
  14. CloseHandle(m_hEvent);//关闭事件对象
  15. m_hEvent = NULL;
  16. }
  17. m_listBoxResults.ResetContent();//清空查找结果列表
  18. m_hEvent = CreateEvent(NULL,FALSE,TRUE,_T("Event"));//创建事件对象 //创建一个线程,开始执行线程函数
  19. m_hThread = CreateThread(NULL,0,FindTmpFile,this,0,NULL);
  20. m_hThread2 = CreateThread(NULL,0,RotatingImg,this,0,NULL);
  21. UpdateData(FALSE);

(7)清理已扫描到的垃圾文件,即采用删除文件策略,使用DeleteFile()方法:

  1. void CClearTmpFileDlg::OnBnClickedDelall()
  2. {//删除已扫描到的垃圾文件 CString strDel;
  3. CFile file; for(int i=0;i<m_listBoxResults.GetCount();i ++)
  4. {
  5.  
  6. m_listBoxResults.GetText(i,strDel);
  7. GetDlgItem(IDC_TEST)->SetWindowText(strDel);
  8. DeleteFile(strDel);//删除指定路径的文件 }
  9. m_listBoxResults.ResetContent();
  10. GetDlgItem(IDC_TEST)->SetWindowText(_T("清理完毕!"));
  11. GetDlgItem(IDC_LIST1)->ShowWindow(SW_HIDE);
  12. GetDlgItem(IDC_BEGIN)->ShowWindow(SW_SHOW);
  13. GetDlgItem(IDC_BEGIN)->SetWindowText(_T("重新扫描"));
  14. }

好了,到此差不多软件的主要功能部分都已经开发完毕,大家已经看出来了,功能部分很简单,就是对指定的文件格式进行扫描、显示和清理。下面将进行对软件界面的设计与开发。

三、程序软件的UI界面设计与实现

对应用程序界面的设计包括两部分,一部分是对话框自身的重设计,二是对话框控件的重绘,本程序主要对按钮控件进行重绘设计。

1. 绘制对话框的背景位图

绘制对话框背景位图本文采用的是处理对话框的WM_PAINT消息,该消息初始化时候对对话框进行绘制,从而绘制背景位图。绘制背景位图的主要代码如下:

  1. CRect rect;
  2. CPaintDC dc(this);
  3. GetClientRect(&rect); //获取客户区
  4. //设置对话框背景颜色 dc.FillSolidRect(rect,RGB(14,94,157)); //设置为窗口背景

2. 在指定的区域中输出位图

为了能够在指定的区域中输出位图,需要使用设备上下文CDC类的StretchBlt方法。由于我们需要在窗口的非客户区域绘制位图,因此需要使用CWindowDC类的StretchBlt方法, CWindowDC类派生与CDC类,它提供了在窗口非客户区域绘制位图的功能。该方法数从源矩形中复制一个位图到目标矩形,必要时按目前目标设备设置的模式进行图像的拉伸或压缩。输出位图的主要实现代码如下:

  1. CRect winRC;
  2. CDC* pDC=GetWindowDC();//获取窗口设备上下文 CDC memDC;
  3. memDC.CreateCompatibleDC(pDC);//创建兼容内存位图 BITMAPINFO bmpInfo;
  4. CBitmap bmp; //定义位图对象
  5. GetWindowRect(&winRC);
  6. bmp.LoadBitmap(nID);//加载位图
  7. bmp.GetObject(sizeof(BITMAPINFO),&bmpInfo);//获取位图信息
  8. int nBmpCX = bmpInfo.bmiHeader.biWidth;//获取位图宽度
  9. int nBmpCY = bmpInfo.bmiHeader.biHeight;//获取位图高度
  10. memDC.SelectObject(bmp);//选中位图对象
  11. pDC->StretchBlt(x,y,w,h, &memDC,0,0,nBmpCX,nBmpCY,SRCCOPY);//在窗口中绘制位图
  12. bmp.DeleteObject();//释放位图对象ReleaseDC(pDC);//释放DC

3. 对话框界面设计与绘制的实现:

在对话框重绘的设计与实现过程中,一般需要绘制的对话框区域主要有标题部分、边框部分和客户区部分。具体的区域划分如下图所示。

既然要对多个区域进行位图显示输出,所以我们先封装一个bmp位图显示输出函数如下:

  1. void CClearTmpFileDlg::DisplayBmp(int x,int y,int w,int h,int nID)
  2. {//nID 表示位图资源的ID CRect winRC;
  3. CDC* pDC=GetWindowDC();
  4. CDC memDC;
  5. memDC.CreateCompatibleDC(pDC);
  6. BITMAPINFO bmpInfo;
  7. CBitmap bmp;
  8. GetWindowRect(&winRC);
  9. bmp.LoadBitmap(nID);
  10. bmp.GetObject(sizeof(BITMAPINFO),&bmpInfo); int nBmpCX = bmpInfo.bmiHeader.biWidth; int nBmpCY = bmpInfo.bmiHeader.biHeight;
  11. memDC.SelectObject(bmp);
  12. pDC->StretchBlt(x,y,w,h, &memDC,0,0,nBmpCX,nBmpCY,SRCCOPY);//在窗口中绘制位图 bmp.DeleteObject();
  13. ReleaseDC(pDC);
  14. }

然后就是对各个区域进行位图输出重绘。由于标题栏以及边框主要都是非客户区域绘制,因此应该在WM_NCPAINT 消息中绘制。当然得先通过添加资源的方式将所用到的bmp位图资源导入到项目中。

在 WM_NCPAINT消息对于的 方法OnNcPaint()中调用对话框绘制方法DrawDialog()。该方法的功能就是绘制对话框各个区域的位图。主要代码如下:

  1. void CClearTmpFileDlg::DrawDialog()
  2. {//重绘对话框标题栏、边框、最小化按钮、最大化按钮和关闭按钮等界面
  3. m_nFrameCY = GetSystemMetrics(SM_CYFIXEDFRAME);//获取对话框边框的高度
  4. m_nFrameCX = GetSystemMetrics(SM_CXDLGFRAME);//获取对话边框的宽度
  5. if(GetStyle()&WS_BORDER)//获取对话框是否有边框 {
  6. m_nBorderCY = GetSystemMetrics(SM_CYBORDER) + m_nFrameCY;
  7. m_nBorderCX = GetSystemMetrics(SM_CXBORDER) +m_nFrameCX;
  8. } else
  9. {
  10. m_nBorderCY = m_nFrameCY;
  11. m_nBorderCX = m_nFrameCX;
  12. }
  13. m_nTitleBarCY = GetSystemMetrics(SM_CYCAPTION) + m_nBorderCY;//计算标题栏高度
  14. m_nTitleBarCX =m_nBorderCX;
  15.  
  16. CRect winRect,factRect;
  17. GetWindowRect(&winRect);
  18. factRect.CopyRect(CRect(0,0,winRect.Width(),winRect.Height()));
  19. CWindowDC windowsDC(this);//获取窗口设备上下文 //获取整个MFC窗口的高度和宽度
  20. m_nWinWidth = winRect.Width();//=781
  21. m_nWinHeight = winRect.Height();//=459 //绘制对话框左标题栏位图
  22. DisplayBmp(0,0,100,m_nTitleBarCY,IDB_LEFTTITLE); //绘制对话框标题栏左端的logo图标
  23. DisplayBmp(3,0,26,m_nTitleBarCY,IDB_APPICON); //绘制对话框右标题栏位图
  24. DisplayBmp(m_nWinWidth-100,0,100,m_nTitleBarCY,IDB_RIGHTTITLE); //绘制对话框中标题栏位图
  25. DisplayBmp(100,0,m_nWinWidth-200,m_nTitleBarCY,IDB_MIDTITLE); //绘制对话框左边框位图
  26. DisplayBmp(0,m_nTitleBarCY,m_nBorderCX,m_nWinHeight-m_nBorderCY,IDB_LEFTBAR); //绘制对话框底边框位图
  27. DisplayBmp(m_nBorderCX,m_nWinHeight-m_nBorderCX,m_nWinWidth-2*m_nBorderCX,m_nBorderCX,IDB_BOTTOMBAR); //绘制对话框左边框位图
  28. DisplayBmp(m_nWinWidth-m_nBorderCX,m_nTitleBarCY,m_nBorderCX,m_nWinHeight-m_nBorderCY,IDB_RIGHTBAR); //给对话框绘制最小化按钮
  29. DisplayBmp(m_nWinWidth-26*3-5,0,26,26,IDB_MINBTN1); //给对话框绘制最大化按钮
  30. DisplayBmp(m_nWinWidth-26*2-5,0,26,26,IDB_MAXBTN1); //给对话框绘制关闭按钮
  31. DisplayBmp(m_nWinWidth-26-5,0,26,26,IDB_CLOSEBTN1);
  32.  
  33. ReleaseDC(&windowsDC); //ReleaseDC(&memDC);
  34. DrawTitleBarText();//输出标题栏文本}

上面代码中最后的绘制对话框标题文本的方法DrawTitleBarText(),主要是用来显示标题栏的文本,其主要代码如下:

  1. CString strTitle ="小蔡垃圾清理器3.0";
  2. CDC* pDC= GetWindowDC();
  3. pDC->SetBkMode(TRANSPARENT);
  4. pDC->SetTextColor(RGB(255,255,255));
  5. pDC->SetTextAlign(TA_CENTER);
  6. CRect rect;
  7. GetClientRect(&rect);
  8. CSize szText = pDC->GetTextExtent(strTitle);
  9. CFont* font,*fOldFont;
  10. font = new CFont;
  11. font->CreateFont(12,0,0,0,FW_BOLD,FALSE,FALSE,0,ANSI_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_SWISS,_T("宋体"));
  12. fOldFont = pDC->SelectObject(font);
  13. pDC->TextOut(100,6.5,strTitle,18);
  14. pDC->SelectObject(fOldFont);
  15. ReleaseDC(pDC);

在完成对话框相应区域的位图后,并没有完成任务,还需要处理标题栏按钮的热点效果,以及按钮的单击事件。首先得处理鼠标在非客户区域移动时的事件,即WM_NCMOUSEMOVE消息,在其消息处理函数中判断当前的鼠标点是否位于标题栏的按钮区域,如果是则设置按钮的热点效果,并且记录当前的按钮状态,及鼠标点在哪个按钮上。同样的,处理对话框非客户区域的单击事件,即WM_NCLBUTTONDOWN消息,在其消息处理函数中完成单击事件操作。这部分的代码比较简单,在此不予显示。

4.按钮控件UI界面设计与实现

在MFC下编程,很多时候对于标准的按钮控件不是很满意,想要弄的美观些。这就需要按钮重绘。重绘按钮一般的实现方法就是重写CButton类。

首先给工程添加一个自绘按钮类MyDrawButton,基类为CButton。要想让按钮具备自绘功能,就要为按钮添加BS_OWNERDRAW属性。为类CButton重载PreSubclassWindow虚函数。在该函数中添加如下一行代码:

SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW);

当按钮控件具有了自绘功能之后,每次控件状态改变都会触发DrawItem函数,在该函数中来绘制按钮的形态外观,所以第二步就要重载DrawItem虚函数。在这个函数中就可以自由发挥了,比如绘制背景,底色,按钮标题,绘制文本字体样式等等。

一般都会为按钮定义几种不同状态时的外观,比如光标滑过时的状态,按钮按下时的状态,按钮禁用时的状态,以及按钮的正常状态等等。这就要为新的按钮添加几种重要的消息响应。比如WM_MOUSELEAVE消息,WM_MOUSEHOVER消息和WM_MOUSEMOVE消息等等,值得一提的是前两个消息的响应函数需要自己手动添加,微软提供了一个TrackMouseEvent函数在光标离开一个窗口时投递WM_MOUSELEAVE消息,光标滑过窗口时投递WM_MOUSEHOVER消息。一般来说可以在WM_MOUSEMOVE消息响应函数中调用TrackMouseEvent函数来投递WM_MOUSELEAVE消息和WM_MOUSEHOVER消息。然后在WM_MOUSELEAVE消息的响应函数中标记“光标已经离开按钮”,然后调用InvalidateRect函数让按钮重绘。在WM_MOUSEHOVER消息的响应函数中标记“光标正在按钮上方”,并调用InvalidateRect函数让按钮重绘。

在本文中,重绘按钮分为3个部分。

(1)绘制按钮背景样式,即绘制背景bmp位图,使得按钮具有自定义的样式,同时在绘制按钮背景的输出位图时采用TransparentBlt()函数,该函数的作用是使窗体上显示位图的背景与窗体背景色融为一体,不仅可以显示按钮bmp位图样式,而且还可以使背景透明。

(2)就是绘制按钮上的文本。主要绘制按钮上文本的样式,包括字体大小,字体样式,字体颜色等属性。

(3)实现不同状态下的按钮的外观样式,主要包括WM_MOUSEMOVE和WM_MOUSELEAVE两个消息的消息处理函数。分别实现鼠标在按钮区域上和不在按钮区域上的状态。为了标记鼠标移动到按钮区域内停留,需要用到一个定时器来标记鼠标是否还在按钮区域内停留。在WM_MOUSEMOVE内启动定时器,触发WM_MOUSELEAVE消息时结束定时器即销毁定时器。定时器的主要代码如下:

  1. void MyDrawButton::OnTimer(UINT_PTR nIDEvent)
  2. { // TODO: 在此添加消息处理程序代码和/或调用默认值
  3. if(nIDEvent != 24) return;
  4. CPoint point;
  5. CRect rect;
  6. GetWindowRect(&rect);
  7. GetCursorPos(&point); // 如果鼠标离开按钮区域,重绘按钮
  8. if (!rect.PtInRect(point) && m_bMove)
  9. {
  10. KillTimer (24);
  11. m_DrawState=ST_MOVEOUT;
  12. m_bMove=FALSE;
  13. Draw();
  14. }
  15. CButton::OnTimer(nIDEvent);
  16. }

重绘按钮类MyDrawButton的主要实现代码如下:

定义的一些重绘用到的变量:

  1. #define ST_MOVEIN 0//绘制状态—在按钮区域上#define ST_MOVEOUT 1 //绘制状态—不在按钮区域上int m_DrawState;//绘制状态
  2. int m_nBmpID;//当前显示的背景bmp位图的资源ID
  3. bool m_bMove;//鼠标是否进入按钮区域
  4. COLORREF m_clText;//当前文本颜色
  5. COLORREF m_clActiveText;//鼠标进入按钮区域时文本颜色
  6. COLORREF m_clNormalText;//鼠标离开按钮区域时文本颜色

消息处理函数和定义的函数以及实现:

  1. void MyDrawButton::PreSubclassWindow()
  2. {
  3. SetButtonStyle(GetButtonStyle() | BS_OWNERDRAW);
  4. }void MyDrawButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
  5. {
  6. Draw();//绘制按钮}void MyDrawButton::Draw()//绘制按钮{
  7. DrawBackground();//绘制按钮bmp位图,并使背景透明化
  8. DrawText();//绘制按钮上的文本}void MyDrawButton::DrawText()
  9. {//绘制按钮上的文本的字体大小、样式等 CString itemString;
  10. CRect clientRect;
  11. CClientDC dc(this);
  12. GetClientRect(&clientRect);
  13. GetWindowText(itemString); if(itemString)
  14. {
  15. CSize size=dc.GetTextExtent (itemString);//获得所选字体中指定字符串的高度和宽度
  16. int rectwidth=clientRect.Width(); int rectheight=clientRect.Height(); int textwidth=size.cx ; int textheight=size.cy ;
  17. int x,y; // 文本的位置 // 计算文本的输出位置
  18. x=(rectwidth-textwidth)/2;//水平居中
  19. y=(rectheight-textheight)/2;//垂直居中
  20. switch(m_DrawState)
  21. { case ST_MOVEIN://鼠标进入按钮区域
  22. m_clText=m_clActiveText; break; case ST_MOVEOUT://鼠标离开按钮区域
  23. m_clText=m_clNormalText; break; default:
  24. m_clText=m_clNormalText; break;
  25. }
  26. dc.SetTextColor(m_clText);
  27. dc.SetBkMode(TRANSPARENT);
  28. CFont *font ;
  29. font =new CFont(); int fontSize = 14; font->CreateFont(fontSize,0,0,0,FW_BOLD,FALSE,FALSE,0,ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,FF_SWISS,_T("宋体"));
  30. dc.SelectObject(font);
  31. dc.TextOut (x,y,itemString);
  32. }
  33. }void MyDrawButton::SetBkBmp(int nBmpID)
  34. {//设置按钮bmp位图样式
  35. m_nBmpID = nBmpID;
  36. }void MyDrawButton::DrawBackground()
  37. {//绘制按钮bmp位图,并使背景透明化 CRect winRC;
  38. CDC* pDC=GetWindowDC();
  39. CDC memDC;
  40. memDC.CreateCompatibleDC(pDC);
  41. BITMAPINFO bmpInfo;
  42. CBitmap bmp;
  43. GetWindowRect(&winRC);
  44.  
  45. bmp.LoadBitmap(m_nBmpID);
  46. bmp.GetObject(sizeof(BITMAPINFO),&bmpInfo); int nBmpCX = bmpInfo.bmiHeader.biWidth; int nBmpCY = bmpInfo.bmiHeader.biHeight;
  47. memDC.SelectObject(bmp);
  48. pDC->TransparentBlt(0,0,nBmpCX,nBmpCY,&memDC,0,0,
  49. nBmpCX,nBmpCY,RGB(14,94,157));//在窗口中绘制位图,RGB(14,94,157)是透明色 bmp.DeleteObject();
  50. ReleaseDC(pDC);
  51. }

到此,按钮的自定义重绘完成了,接下来就可以使用自己重绘的按钮类MyDrawButton了。首先往对话框中添加一个按钮控件(以立即扫描按钮为例),假设它的ID值为IDC_TEST。进入类向导(Class Wizard)的成员变量属性页,为IDC_ BEGIN添加一个变量m_btnBegin。如下:

MyDrawButton m_btnBegin;

然后就可以调用MyDrawButton的方法来设置按钮的样式了。如下:

m_btnBegin.SetBkBmp(IDB_BTN210x95,IDB_BTN210x95_3);//IDB_BTN210x95,IDB_BTN210x95分别为默认位图和鼠标在按钮区域时的位图。

到现在为止,按钮类的重绘完成了,可以随意定义自己喜欢的样式的按钮了。现在相对完善成形的一个垃圾清理工具软件就开发完了。

三、运行效果

最后软件的主要成果界面如下:

软件打开准备就绪界面

正在运行截面图

扫描完成界面图:

清理完成界面图

四、项目结构图

这里补上,项目代码结构图

项目结构图

注:本文著作权归作者,由demo大师发表,拒绝转载,转载需要作者授权

Windows 开发之VC++垃圾清理程序软件的更多相关文章

  1. Windows开发之VC++仿QQ迷你首页(迷你资讯)

    技术:VC++,MFC,WTL,,C++,Windows   概述 之前由于需求和兴趣,需要实现类似QQ迷你资讯首页的东西,看起来很酷,于是就写了个实现方案,主要还是基于WIndows C++ 和MF ...

  2. Liferay7 BPM门户开发之25: Liferay7应用程序配置(APPLICATION CONFIGURATION)

    首先有几个概念需要明确.1.第一个概念是这里的应用程序配置不是写XML之类的配置文件,是类似字典的类型化配置这意味着应用程序配置不只是一个字符串键值对的列表.值还可以有类型,如整数列表,字符串列表,一 ...

  3. Liferay7 BPM门户开发之24: Liferay7应用程序安全

    整理中...... Resources, Roles, and PermissionsPortal Access Control List (PACL) Custom SSO Providers Au ...

  4. 10款 Mac 系统优化清理工具软件推荐和下载

    本文内容及图片来源[风云社区 SCOEE] 在Windows上有各种安全卫士.系统助手等系统优化和清理工具,比如360安全卫士.腾讯安全管家等,同样MacOS系统也有很多好用的系统优化清理工具,体验比 ...

  5. 制作一个windows垃圾清理小程序

    制作一个windows垃圾清理小程序: 把下列代码保存为.bat文件(如垃圾清理.bat) 双击它就能很快地清理垃圾文件,大约一分钟不到. 就是下面的文字(这行不用复制)=============== ...

  6. Windows 7系统垃圾清理自写程序

    系统清理.bat @echo off color 0a title windows7系统垃圾清理--- echo ★☆ ★☆ ★☆ ★☆ ★☆★☆★☆ ★☆ ★☆ ★☆ ★☆★ echo ★☆ ★☆ ...

  7. android软件开发之webView.addJavascriptInterface循环渐进【一】

    本篇文章由:http://www.sollyu.com/android-software-development-webview-addjavascriptinterface-cycle-of-gra ...

  8. [Windows][VC]开机自动启动程序的几种方法

    原文:[Windows][VC]开机自动启动程序的几种方法 很多监控软件要求软件能够在系统重新启动后不用用户去点击图标启动项目,而是直接能够启动运行,方法是写注册表Software\\Microsof ...

  9. ios开发之OC基础-oc小程序

    本系列的文章主要来自于个人在学习前锋教育-欧阳坚老师的iOS开发教程之OC语言教学视频所做的笔记,边看视频,边记录课程知识点.建议大家先过一遍视频,在看视频的过程中记录知识点关键字,把把握重点,然后再 ...

随机推荐

  1. [转]Intent和IntentFilter详解

        Intent   Android中提供了Intent机制来协助应用间的交互与通讯,Intent负责对应用中一次操作的动作.动作涉及数据.附加数据进行描述,Android则根据此Intent的描 ...

  2. sybase数据库技术 :游标可更新与for read only/for update

    在定义游标时不指定for update 或 for read only,ASE会检查以了解游标是否可更新: 如果游标查询语句中包含order by子句,则ASE会将游标定义为只读:其它情况下定义为可更 ...

  3. Chrome无法播放m3u8格式的直播视频流的问题解决

    出国,然后安装这个插件即可:Native HLS Playback https://chrome.google.com/webstore/detail/native-hls-playback/emnp ...

  4. python核心模块之pickle和cPickle解说

    pickle模块使用的数据格式是python专用的,而且不同版本号不向后兼容,同一时候也不能被其它语言说识别.要和其它语言交互,能够使用内置的json包使用pickle模块你能够把Python对象直接 ...

  5. Wix使用整理(二)

    1)         安装卸载时进行日志记录 Wix 制作的 Installer 的调试很麻烦,没有直接的 Bug 工具,可以通过记录安装日志的方式进行间接调试.命令为 msiexec /i pack ...

  6. 工作流引擎activiti入门

    眼下最新的版本号是5.17 1.下载:activiti-5.17.0.zip http://activiti.org/download.html 2.解压activiti-5.17.0.zip 3.打 ...

  7. 我的一些简单的shell脚本实例

    1.模拟linnux登录shell #/bin/bashecho -n "login:" read nameecho -n "password:"read pa ...

  8. gitignore不起作用解决的方法

    前面有文章介绍了使用gitignore文件的方法,该文件表示过滤规则,可是对已经增加版本号库的文件不能生效,因此须要利用命令将想要忽略的文件从版本号库中删除,比方说.我们对androidproject ...

  9. vim多行注释与取消

    神操作 在vim中编写代码,常常会遇到多行注释和取消注释的情况,在VS中我们可以用默认的快捷键或者在设置中自定义快捷键来解决这个问题. vim既然这么强大,必然也是有快捷键来完成的.下面给出具体步骤: ...

  10. jQuery 对象和 DOM 对象

    jQuery(DOM对象) 或者 $(DOM对象) 此函数的作用是将DOM对象,转换为jQuery的对象 DOM对象其实就是javascript的函数对象,可以用来操作所有HTML元素.比如: a标签 ...