看到QQ這樣的截圖實在忍心不住想,是怎以實現的?想了許久想到一個實現法子,下面就讓我給大家展示一下,模擬QQ靜態模擬截圖,我寫的代碼比較亂,是想到哪寫到哪,我想肯實還有比這更簡單的辦法!!程序實現思路,程序是基於對話框,無標題欄,系統菜單,最小化框,最大化框,無邊框....,程序初始化時,把整個桌面屏幕截圖,保存下來,然後把對話框設置全屏頂層窗口,然後把保存下來的位圖,在OnEraseBkgnd中把整個位圖貼到對話框上,然後用像皮筋類選擇截取范圍,看起來就像操作屏幕一樣 。
圖一 示例
下面說說實現細節:
一、初始化程序,在CCatchScreenDlg構造函數中 初始化像皮筋類和保存全屏位圖,
//初始化像皮筋類
m_rectTracker.m_nStyle=CRectTracker::resizeInside|CRectTracker::solidLine;
m_rectTracker.m_rect.SetRect(-1,-1,-1,-1);
m_hCursor=AfxGetApp()->LoadCursor(IDC_CURSOR1);
m_bDraw=FALSE;
m_bFirstDraw=FALSE;
m_bQuit=FALSE;
m_bShowMsg=FALSE;
m_startPt=0;
//獲取屏幕分辯率
m_xScreen = GetSystemMetrics(SM_CXSCREEN);
m_yScreen = GetSystemMetrics(SM_CYSCREEN);
//截取屏幕到位圖中
CRect rect(0, 0,m_xScreen,m_yScreen);
m_pBitmap=CBitmap::FromHandle(CopyScreenToBitmap(&rect));
//一定要初始化m_rgn,
m_rgn.CreateRectRgn(0,0,50,50);
然後在CCatchScreenDlg::OnInitDialog()中設置對話框成頂層窗口。在 CCatchScreenDlg::OnEraseBkgnd中 用整個桌面位圖填充全屏對話框背景
二、從 CRectTracker中派生了一個CTrack 類在類中重載了DrawTrackerRect函數,在函數中直接 更新窗口,消除拖動和改變大小時的虛線框可能還有更簡單的方法,本人能力有限想不出更簡的!
三、從Edit類中派生一個CMyEdit類,用該類的實例對像顯示操作提示信息,在 CMyEdit::OnEraseBkgnd中,用一位圖填充背景,類中響應了WM_MOUSEMOVE消息,在CMyEdit::OnMouseMove(UINT nFlags, CPoint point) 中移動窗口在左上角和右上角之間來回移動.
CRect rect;
GetWindowRect(&rect);
int xScreen = GetSystemMetrics(SM_CXSCREEN);
//int ySCreen = GetSystemMetrics(SM_CYSCREEN);
if(m_bMove)
{
//移動到左上角
MoveWindow(10,10,rect.Width(),rect.Height());
m_bMove=FALSE;
}
else
{
//移動到右上角
MoveWindow(xScreen-180,10,rect.Width(),rect.Height());
m_bMove=TRUE;
}
在主對話框上放置編緝框,然後關聯一個CMyEdit的變量,在主對話顯示時移動到左上角
//把對化框設置成全屏頂層窗口
SetWindowPos(&wndTopMost,0,0,m_xScreen,m_yScreen,SWP_SHOWWINDOW);
//移動操作提示窗口
CRect rect;
m_tipEdit.GetWindowRect(&rect);
m_tipEdit.MoveWindow(10,10,rect.Width(),rect.Height());
//顯示操作提示窗口文字
DrawTip();
//捕獲按鍵消息窗口,將對話框的句柄傳遞到CCatchScreenApp中
((CCatchScreenApp *)AfxGetApp())->m_hwndDlg=m_hWnd;
四、程序中有兩個重要成員函數,一個是畫截取矩形時的信息顯示在鼠標右上角。
//顯示截取矩形信息
void CCatchScreenDlg::DrawMessage(CRect &inRect)
{
//截取矩形大小信息離鼠標間隔
const int space=3;
//設置字體顏色大小
CClientDC dc(this);
CPoint pt;
CPen pen(PS_SOLID,1,RGB(147,147,147));
dc.SetTextColor(RGB(147,147,147));
CFont font;
font.CreatePointFont(90,"宋體");
dc.SelectObject(&font);
//得到字體寬度和高度
GetCursorPos(&pt);
dc.SetBkMode(TRANSPARENT);
TEXTMETRIC tm;
int charHeight;
CSize size;
int lineLength;
dc.GetTextMetrics(&tm);
charHeight = tm.tmHeight+tm.tmExternalLeading;
size=dc.GetTextExtent("頂點位置 ",strlen("頂點位置 "));
lineLength=size.cx;
//初始化矩形, 以保證寫下六行文字
CRect rect(pt.x+space,pt.y-charHeight*6-space,pt.x+lineLength+space,pt.y-space);
int x = GetDeviceCaps(dc, HORZRES);
int y = GetDeviceCaps(dc, VERTRES);
//創建臨時矩形
CRect rectTemp;
//當矩形到達桌面邊緣時調整方向和大小
if((pt.x+rect.Width())>=x)
{
//桌面上方顯示不下矩形
rectTemp=rect;
rectTemp.left=rect.left-rect.Width()-space*2;
rectTemp.right=rect.right-rect.Width()-space*2;;
rect=rectTemp;
}
if((pt.y-rect.Height())<=0)
{
//桌面右方顯示不下矩形
rectTemp=rect;
rectTemp.top=rect.top+rect.Height()+space*2;;
rectTemp.bottom=rect.bottom+rect.Height()+space*2;;
rect=rectTemp;
}
//創建空畫刷畫矩形
dc.SelectObject((HBRUSH)GetStockObject(NULL_BRUSH));
dc.Rectangle(rect);
//在矩形中顯示文字
CString string(" 頂點位置 ");
dc.TextOut(rect.left,rect.top,string);
string.Format(" (%d,%d)",inRect.left,inRect.top);
dc.TextOut(rect.left,rect.top+charHeight,string);
string=" 矩形大小 ";
dc.TextOut(rect.left,rect.top+charHeight*2,string);
string.Format(" (%d,%d)",inRect.Width(),inRect.Height());
dc.TextOut(rect.left,rect.top+charHeight*3,string);
string=" 光標坐標 ";
dc.TextOut(rect.left,rect.top+charHeight*4,string);
string.Format(" (%d,%d)",pt.x,pt.y);
dc.TextOut(rect.left,rect.top+charHeight*5,string);
}
根據鼠標的位置和要顯示的字的寬度各高度在鼠標左上角位置處構造一個CRect對像,在CRect中顯示矩形信息,同時根據鼠標當前的位置,在左邊和上邊不能正常顯示信息時動態度反轉矩形,還有一個類是DrawTip()在鼠標按下、松下是顯示相應的操作提示
//顯示操作提示信息 void CCatchScreenDlg::DrawTip() { //得當前坐標像素, CPoint pt; GetCursorPos(&pt); //當到當前R,G,B,各像素值 COLORREF color; CClientDC dc(this); color=dc.GetPixel(pt); BYTE rValue,gValue,bValue; rValue=GetRValue(color); gValue=GetGValue(color); bValue=GetGValue(color); //按格式排放字符串 CString string; CString strTemp; string.Format("\r\n\r\n\r\n ·當前像素RGB (%d,%d,%d)\r\n",rValue,gValue,bValue); if(!m_bDraw&&!m_bFirstDraw) { strTemp="\r\n ·按下鼠標左鍵不放選擇截取\r\n 范圍\r\n\r\n ·按ESC鍵或鼠標右鍵退出"; } else if(m_bDraw&&m_bFirstDraw) { strTemp="\r\n ·松開鼠標左鍵確定截取范圍\r\n\r\n ·按ESC鍵退出"; } else if(m_bFirstDraw) { strTemp="\r\n ·用鼠標左鍵調整截取范圍的\r\n 大小和位置\r\n\r\n·截取范圍內雙擊鼠標左鍵保存\r\n 圖像, 結束操作\r\n\r\n·點擊鼠標右鍵重新選擇"; } string+=strTemp; //顯示到編緝框中,操作提示窗口 m_tipEdit.SetWindowText(string); }
程序有點亂,文字都是硬編碼寫上去的,整個字符串顯示在一對話框的編輯出框中,用空格和回車換行來控制擺放格式。
五、由於對話框中有一個編輯框,並且背景是一張位圖,由於程截圖時要經常刷新窗口,如果刷新整個窗口的話,編輯框會有很大的閃爍,
所以只能更新編輯框以外的區域,函數PaintWindow()計算更新區域,並更新窗口
void CCatchScreenDlg::PaintWindow()
六、當然不能忘了方向鍵來微調截取矩形大小和位置,由於是基於對話框的程序,按鍵消息,被Windows內部的對話框過程處理了(即在基類中完成了處理,讀者可以查看MFC的源代碼),或者被發送給子控件進行處理,所以在對話框類中可能利用
{
//獲取當全屏對話框窗口大小
CRect rect1;
GetWindowRect(rect1);
//獲取編輯框窗口大小
CRect rect2;
m_tipEdit.GetWindowRect(rect2);
CRgn rgn1,rgn2;
rgn1.CreateRectRgnIndirect(rect1);
rgn2.CreateRectRgnIndirect(rect2);
//獲取更新區域,就是除了編輯框窗口不更新
m_rgn.CombineRgn(&rgn1,&rgn2,RGN_DIFF);
InvalidateRgn(&m_rgn);
}
BOOLProcessMessageFilter(int code, LPMSG lpMsg)這個虛函數來過濾或響應菜單和對話框的特定Windows消息在頭文件中增加一個類型為HWND,Public成員變量名m_hwndDlg,在構造函數中初始化為NULL;在 CCatchScreenDlg::OnInitDialog()中加入((CWinSunApp*)AfxGetApp())->m_hwndDlg=m_hWnd;
將對話框的句柄傳遞到CWinSunApp類中
//********************************************************************************
#define SHIFTED 0x8000
//********************************************************************************
BOOL CCatchScreenApp::ProcessMessageFilter(int code, LPMSG lpMsg)
{
// TODO: Add your specialized code here and/or call the base class
if(m_hwndDlg!=NULL)
{ //判斷消息,如果消息是從對話框發出的或者其子控件發出的,就進行處理
if((lpMsg->hwnd==m_hwndDlg) || ::IsChild(m_hwndDlg,lpMsg->hwnd))
{
//如果消息是WM_KEYDOWN
//用方向鍵調整位置
if(lpMsg->message==WM_KEYDOWN)
{
CRect rect(0,0,0,0);
CCatchScreenDlg * pDlg=(CCatchScreenDlg *)AfxGetMainWnd();
rect=pDlg->m_rectTracker.m_rect;
if(pDlg->m_bFirstDraw)
{
//如果Shift鍵按下則方向鍵調整大小
BOOL isShifeDowm=FALSE;
int nVirtKey;
nVirtKey = GetKeyState(VK_SHIFT);
if (nVirtKey & SHIFTED)
isShifeDowm=TRUE;
switch(lpMsg->wParam)
{
case VK_UP:
//如果按下Shift,則只調整一邊
if(!isShifeDowm)
rect.top-=1;
rect.bottom-=1;
pDlg->m_rectTracker.m_rect=rect;
pDlg->PaintWindow();
break;
case VK_DOWN:
rect.top+=1;
if(!isShifeDowm)
rect.bottom+=1;
pDlg->m_rectTracker.m_rect=rect;
pDlg->PaintWindow();
break;
case VK_LEFT:
if(!isShifeDowm)
rect.left-=1;
rect.right-=1;
pDlg->m_rectTracker.m_rect=rect;
pDlg->PaintWindow();
break;
case VK_RIGHT:
rect.left+=1;
if(!isShifeDowm)
rect.right+=1;
pDlg->m_rectTracker.m_rect=rect;
pDlg->PaintWindow();
break;
}
}
}
}
}
return CWinApp::ProcessMessageFilter(code, lpMsg);
}
程序中涉及到像皮筋類的使用,就不多說了,知識庫中有許多文章,接著就雙擊選區保存圖片到剪貼板中。就說到這。我嘴笨 , 詳細的請參看源文件注釋,,有什麼問題或您有更好的建意請不要忘了和我聯系哦,郵箱: [email protected]
本文配套源碼