MFC截图程序的实现(十一)

来源:互联网 发布:警告本网站域名在美国 编辑:程序博客网 时间:2024/05/29 04:04

    前面介绍了一些自定义截图的实现问题,现在接着上篇文章继续介绍如何实现自定义截图。

前面讲了,为了确定截图范围,要让用户画矩形。这里再讲细一点,问题就出来了:“这个矩形要画在哪里?”

    一开始我想的是直接调用GetDesktopWindow()和GetWindowDC()直接在桌面环境上绘图,但是实际操作后,效果并不理想,主要是刷新的问题。矩形框画不出来或是一画出来就消失了。当然,在不刷新的窗口画出来的矩形很完整,基本达到了预期的目的。但是,我们不能期待截图时所有的窗口都不刷新。

    所以,我采用了另一种方法,即将矩形画到对话框上,这个对话框有以下几个要求:(1)无标题栏、无边框;(2)最大化显示;(3)置顶显示(即在所有窗口之上);(4)最重要的是透明。

另外,说明一点:这个对话框的作用只是为了提供一个用户画矩形的载体,而用户画矩形的目的是为了得到截图的矩形区域,所以在确定了这个矩形范围之后,这个对话框(在调用截图函数之前)会马上关闭。


下面是具体的实现过程:

1、新建一个基于基本对话框的MFC工程,名为Custom_CutScreen。


2、关于最大化的透明对话框,决定采用模态对话框,因为该窗口只在画矩形时出现。


3、打开ResourceView页,插入一个ID为IDD_DIALOG_COVER的新对话框,通过ClassWizard为其添加一个新类CCoverDlg。


4、打开ClassWizard为CCoverDlg类添加以下几个消息的响应函数:WM_INITDIALOG、WM_LBUTTONDOWN、WM_LBUTTONUP、WM_MOUSEMOXE、WM_PAINT 和 WM_TIMER。


6.设置窗口透明用到了一个函数:SetLayeredWindowAttributes。

BOOL SetLayeredWindowAttributes(
HWND hwnd,               // 指定分层窗口句柄
COLORREF crKey,     // 指定需要透明的背景颜色值,可用RGB()宏
BYTE bAlpha,             // 设置透明度,0表示完全透明,255表示不透明
DWORD dwFlags       // 透明方式
);
其中,dwFlags参数可取以下值:
LWA_ALPHA时:crKey参数无效,bAlpha参数有效;
LWA_COLORKEY:窗体中的所有颜色为crKey的地方将变为透明,bAlpha参数无效。
LWA_ALPHA | LWA_COLORKEY:crKey的地方将变为全透明,而其它地方根据bAlpha参数确定透明度。

注:此函数在VC6.0中没有声明,需要自定义后在user32.dll后动态获取地址后调用。在VC9.0(VS2008)及其之后版本中可以直接调用。


7、下面贴出代码:

CoverDlg.cpp

// CoverDlg.cpp : implementation file//#include "stdafx.h"#include "Custom_CutScreen.h"#include "CoverDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CCoverDlg dialogCCoverDlg::CCoverDlg(CWnd* pParent /*=NULL*/): CDialog(CCoverDlg::IDD, pParent){//{{AFX_DATA_INIT(CCoverDlg)// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INIT}void CCoverDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CCoverDlg)// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CCoverDlg, CDialog)//{{AFX_MSG_MAP(CCoverDlg)ON_WM_PAINT()ON_WM_LBUTTONDOWN()ON_WM_LBUTTONUP()ON_WM_MOUSEMOVE()ON_WM_TIMER()ON_WM_RBUTTONUP()//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CCoverDlg message handlersvoid CCoverDlg::OnPaint() {CPaintDC dc(this); // device context for painting// TODO: Add your message handler code here//绘制背景  CRect rect;  GetClientRect(&rect);  CBrush bruDB(GetSysColor(COLOR_3DFACE));//背景颜色  dc.FillRect(&rect, &bruDB); //绘制拖动矩形  if (IsLBtnDown)  {  CPen pen(PS_SOLID,6,RGB(234,23,53));CPen *pOldPen=dc.SelectObject(&pen);CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));CBrush *pOldBrush=dc.SelectObject(pBrush);dc.Rectangle(CRect(startPoint, endPoint));dc.SelectObject(pOldPen);dc.SelectObject(pOldBrush);}// Do not call CDialog::OnPaint() for painting messages}/************************************************************************//* 鼠标左键按下的响应函数                                               *//************************************************************************/void CCoverDlg::OnLButtonDown(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultstartPoint = point;endPoint = point;IsLBtnDown = true;CDialog::OnLButtonDown(nFlags, point);}/************************************************************************//* 鼠标左键弹起的响应函数                                               *//************************************************************************/void CCoverDlg::OnLButtonUp(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultendPoint = point;IsLBtnDown = false;IsLBtnUp = true;CDialog::OnLButtonUp(nFlags, point);}/************************************************************************//* 鼠标移动的响应函数                                                   *//************************************************************************/void CCoverDlg::OnMouseMove(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultendPoint = point;CDialog::OnMouseMove(nFlags, point);}/************************************************************************//* 计时器函数                                                           *//************************************************************************/void CCoverDlg::OnTimer(UINT nIDEvent) {// TODO: Add your message handler code here and/or call defaultif (nIDEvent == 1){// 如果鼠标左键弹起,则关闭对话框if (IsLBtnUp) {SendMessage(WM_CLOSE);KillTimer(1);}// 如果鼠标右键弹起(用户取消了截图),关闭对话框if (IsRBtnUp) {SendMessage(WM_CLOSE);KillTimer(1);}Invalidate(FALSE);//更新界面  }CDialog::OnTimer(nIDEvent);}/************************************************************************//* 对话框的初始化函数                                                   *//************************************************************************/BOOL CCoverDlg::OnInitDialog() {CDialog::OnInitDialog();// TODO: Add extra initialization here// 变量初始化IsLBtnUp = false;IsLBtnDown = false;IsRBtnUp = false;ShowWindow(SW_MAXIMIZE);  // 窗口最大化SetWindowPos(&wndTopMost,0,0,0,0, SWP_NOMOVE | SWP_NOSIZE); // 窗口置顶// 设置窗体透明COLORREF maskColor = GetSysColor(COLOR_3DFACE); // 获取窗体颜色SetWindowLong(GetSafeHwnd(),GWL_EXSTYLE,GetWindowLong(GetSafeHwnd(),GWL_EXSTYLE)|0x00080000);  HINSTANCE hInst = LoadLibrary(_T("User32.dll"));    if (hInst)      {         typedef BOOL (WINAPI *MyFun)(HWND,COLORREF,BYTE,DWORD);          MyFun myfun = NULL;        myfun = (MyFun)GetProcAddress(hInst, "SetLayeredWindowAttributes");         if (myfun) myfun(GetSafeHwnd(),maskColor,100,2);  // 100是透明度(范围0-255)      FreeLibrary(hInst);      }  // 设置计时器SetTimer(1, 100, NULL);return TRUE;  // return TRUE unless you set the focus to a control              // EXCEPTION: OCX Property Pages should return FALSE}/************************************************************************//* 鼠标右键弹起的响应函数                                               *//************************************************************************/void CCoverDlg::OnRButtonUp(UINT nFlags, CPoint point) {// TODO: Add your message handler code here and/or call defaultIsRBtnUp = true;CDialog::OnRButtonUp(nFlags, point);}POINT CCoverDlg::GetStartPoint(){return startPoint;}POINT CCoverDlg::GetEndPoint(){return endPoint;}bool CCoverDlg::GetWhetherCancel(){return IsRBtnUp;}

Custom_CutScreenDlg.cpp

// Custom_CutScreenDlg.cpp : implementation file//#include "stdafx.h"#include "Custom_CutScreen.h"#include "Custom_CutScreenDlg.h"#include "CoverDlg.h"#ifdef _DEBUG#define new DEBUG_NEW#undef THIS_FILEstatic char THIS_FILE[] = __FILE__;#endif/////////////////////////////////////////////////////////////////////////////// CCustom_CutScreenDlg dialogCCustom_CutScreenDlg::CCustom_CutScreenDlg(CWnd* pParent /*=NULL*/): CDialog(CCustom_CutScreenDlg::IDD, pParent){//{{AFX_DATA_INIT(CCustom_CutScreenDlg)// NOTE: the ClassWizard will add member initialization here//}}AFX_DATA_INITm_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);}void CCustom_CutScreenDlg::DoDataExchange(CDataExchange* pDX){CDialog::DoDataExchange(pDX);//{{AFX_DATA_MAP(CCustom_CutScreenDlg)// NOTE: the ClassWizard will add DDX and DDV calls here//}}AFX_DATA_MAP}BEGIN_MESSAGE_MAP(CCustom_CutScreenDlg, CDialog)//{{AFX_MSG_MAP(CCustom_CutScreenDlg)ON_WM_PAINT()ON_WM_QUERYDRAGICON()ON_BN_CLICKED(IDC_BTN_CUT, OnBtnCut)//}}AFX_MSG_MAPEND_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////// CCustom_CutScreenDlg message handlersBOOL CCustom_CutScreenDlg::OnInitDialog(){CDialog::OnInitDialog();SetIcon(m_hIcon, TRUE);// Set big iconSetIcon(m_hIcon, FALSE);// Set small icon// TODO: Add extra initialization herereturn TRUE;  // return TRUE  unless you set the focus to a control}// If you add a minimize button to your dialog, you will need the code below//  to draw the icon.  For MFC applications using the document/view model,//  this is automatically done for you by the framework.void CCustom_CutScreenDlg::OnPaint() {if (IsIconic()){CPaintDC dc(this); // device context for paintingSendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);// Center icon in client rectangleint cxIcon = GetSystemMetrics(SM_CXICON);int cyIcon = GetSystemMetrics(SM_CYICON);CRect rect;GetClientRect(&rect);int x = (rect.Width() - cxIcon + 1) / 2;int y = (rect.Height() - cyIcon + 1) / 2;// Draw the icondc.DrawIcon(x, y, m_hIcon);}else{CDialog::OnPaint();}}HCURSOR CCustom_CutScreenDlg::OnQueryDragIcon(){return (HCURSOR) m_hIcon;}void CCustom_CutScreenDlg::OnBtnCut() {// TODO: Add your control notification handler code hereCCoverDlg dlg;if(IDCANCEL == dlg.DoModal()){if (!dlg.GetWhetherCancel()){POINT startPoint = dlg.GetStartPoint();POINT endPoint = dlg.GetEndPoint();CRect rect;rect.left = startPoint.x;rect.right = endPoint.x;rect.bottom = endPoint.y;rect.top = startPoint.y;HBITMAP hb = CopyScreenToBitmap((LPRECT)&rect);CString path = _T("C:\\test.bmp");SaveBitmapToFile(hb, path);}}}/************************************************************************//* 将屏幕指定区域存成图片                                               *//************************************************************************/HBITMAP CCustom_CutScreenDlg::CopyScreenToBitmap(LPRECT lpRect){HDC hScrDC, hMemDC;      // 屏幕和内存设备描述表HBITMAP hBitmap,hOldBitmap;   // 位图句柄int       nX, nY, nX2, nY2;      // 选定区域坐标int       nWidth, nHeight;      // 位图宽度和高度int       xScrn, yScrn;         // 屏幕分辨率// 确保选定区域不为空矩形if (IsRectEmpty(lpRect))return NULL;//为屏幕创建设备描述表hScrDC = CreateDC("DISPLAY", NULL, NULL, NULL);//为屏幕设备描述表创建兼容的内存设备描述表hMemDC = CreateCompatibleDC(hScrDC);// 获得选定区域坐标nX = lpRect->left;nY = lpRect->top;nX2 = lpRect->right;nY2 = lpRect->bottom;// 获得屏幕分辨率xScrn = GetDeviceCaps(hScrDC, HORZRES);yScrn = GetDeviceCaps(hScrDC, VERTRES);//确保选定区域是可见的if (nX < 0)nX = 0;if (nY < 0)nY = 0;if (nX2 > xScrn)nX2 = xScrn;if (nY2 > yScrn)nY2 = yScrn;nWidth = nX2 - nX;nHeight = nY2 - nY;// 创建一个与屏幕设备描述表兼容的位图hBitmap=CreateCompatibleBitmap(hScrDC,nWidth,nHeight);// 把新位图选到内存设备描述表中hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);// 把屏幕设备描述表拷贝到内存设备描述表中BitBlt(hMemDC,0,0, nWidth,nHeight,hScrDC, nX, nY, SRCCOPY);//得到屏幕位图的句柄hBitmap=(HBITMAP)SelectObject(hMemDC,hOldBitmap);//清除 DeleteDC(hScrDC);DeleteDC(hMemDC);// 返回位图句柄return hBitmap;}/************************************************************************//* 将内容保存成文件                                                     *//************************************************************************/BOOL CCustom_CutScreenDlg::SaveBitmapToFile(HBITMAP hBitmap, LPCSTR lpFileName){HDC hDC; //设备描述表 int iBits; //当前显示分辨率下每个像素所占字节数 WORD wBitCount; //位图中每个像素所占字节数 DWORD dwPaletteSize=0, //定义调色板大小, 位图中像素字节大小 ,位图文件大小 , 写入文件字节数 dwBmBitsSize, dwDIBSize, dwWritten; BITMAP Bitmap; //位图属性结构 BITMAPFILEHEADER bmfHdr; //位图文件头结构 BITMAPINFOHEADER bi; //位图信息头结构 LPBITMAPINFOHEADER lpbi; //指向位图信息头结构 HANDLE fh, hDib, hPal,hOldPal=NULL; //定义文件,分配内存句柄,调色板句柄 //计算位图文件每个像素所占字节数 HDC hWndDC = CreateDC(_T("DISPLAY"),NULL,NULL,NULL); hDC = ::CreateCompatibleDC( hWndDC ) ; iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES); DeleteDC(hDC); if (iBits <= 1) wBitCount = 1; else if (iBits <= 4) wBitCount = 4; else if (iBits <= 8) wBitCount = 8; else if (iBits <= 24) wBitCount = 24; else wBitCount = 24 ; //计算调色板大小 if (wBitCount <= 8) dwPaletteSize = (1 << wBitCount) * sizeof(RGBQUAD); //设置位图信息头结构 GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = Bitmap.bmWidth; bi.biHeight = Bitmap.bmHeight; bi.biPlanes = 1; bi.biBitCount = wBitCount; bi.biCompression = BI_RGB; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+31)/32) * 4 * Bitmap.bmHeight ; //为位图内容分配内存 hDib = GlobalAlloc(GHND,dwBmBitsSize+dwPaletteSize+sizeof(BITMAPINFOHEADER)); lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib); *lpbi = bi; // 处理调色板 hPal = GetStockObject(DEFAULT_PALETTE); if (hPal) { hDC = ::GetDC(NULL); hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE); RealizePalette(hDC); } // 获取该调色板下新的像素值 GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight, (LPSTR)lpbi + sizeof(BITMAPINFOHEADER) +dwPaletteSize, (LPBITMAPINFO ) lpbi, DIB_RGB_COLORS); //恢复调色板 if (hOldPal) { SelectPalette(hDC, (HPALETTE)hOldPal, TRUE); RealizePalette(hDC); ::ReleaseDC(NULL, hDC); } //创建位图文件 fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); if (fh == INVALID_HANDLE_VALUE) return FALSE; // 设置位图文件头 bmfHdr.bfType = 0x4D42; // "BM" dwDIBSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwPaletteSize + dwBmBitsSize; bmfHdr.bfSize = dwDIBSize; bmfHdr.bfReserved1 = 0; bmfHdr.bfReserved2 = 0; bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER) + dwPaletteSize; // 写入位图文件头 WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); // 写入位图文件其余内容 WriteFile(fh, (LPSTR)lpbi, dwDIBSize, &dwWritten, NULL); //清除 GlobalUnlock(hDib); GlobalFree(hDib); CloseHandle(fh); return TRUE;}

8、完整源代码(免积分):http://download.csdn.net/detail/wwkaven/7502599


0 0
原创粉丝点击