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

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

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

    一开始我想的是直接调用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_FILE
static char THIS_FILE[] = __FILE__;
#endif




/
// CCoverDlg dialog


CCoverDlg::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_MAP
END_MESSAGE_MAP()

/
// CCoverDlg message handlers

void 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 default
	
	startPoint = 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 default
	
	endPoint = 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 default
	
	endPoint = point;

	CDialog::OnMouseMove(nFlags, point);
}


/************************************************************************/
/* 计时器函数                                                           */
/************************************************************************/
void CCoverDlg::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	
	if (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 default
	
	IsRBtnUp = 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_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CCustom_CutScreenDlg dialog

CCustom_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_INIT
	m_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_MAP
END_MESSAGE_MAP()

/
// CCustom_CutScreenDlg message handlers

BOOL CCustom_CutScreenDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	
	return 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 painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int 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 icon
		dc.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 here
	
	CCoverDlg 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
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值