由於前次寫的代碼過於倉促(相關文章參見:“QQ 靜態截圖程序模擬實現”),還沒仔細修改就投稿了,在這裡向大家表示道歉,可能你覺得這種程序不值的一看,但我本著精益求精的態度,還是把它完善了一下,更重要的是深入了解CRectTracer類的內部機制,以能更靈活和使用該類 ,在此我把MFC的CRectTracker類源碼,提取出來做了小小的改造,有興趣的朋友還可能更深入的增加更 多的功能。
本文主要講述三個問題:
程序中操作提示窗口文本更新閃爍問題;
程序在調整截取矩形大小和位置時,主窗口收不到消息;
CRectTracker類的簡要說明和改造類 CMyTracker;
圖一 示列
一、操作提示窗口是一個編輯框控件,刷新時由 於整個文本刷新,所以會有很難看的閃爍,而其實只有上面的RGB值在變化,那麼就
只要更新RGB 值的文本就可以了,由於CEdit中沒有更改指定文本內容的成員方法,在這裡有一個巧妙的方法來實現, 用CEdit的成員方法 SetSel選中要更改的RGB文本字符,然後用ReplaceSel就可以把選中的文本替換,從 而達到不用更新整個文本,面造極度成閃爍。
程序代碼如下:
void CCatchScreenDlg::ChangeRGB()
程序中存在硬編碼,但只要知道就行了!!
{
//保存舊的RGB值字符串
static CString strOld("");
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;
string.Format("(%d,%d,%d) ",rValue,gValue,bValue);
//如果當前顏色沒變則不刷新RGB值,以免窗口有更多閃爍
if(strOld!=string)
{
//得到RGB文本那一行的文本長度
int LineLength=m_tipEdit.LineLength(6);
//復選RGB值文本,也就是選中 (255,255,255)樣式
m_tipEdit.SetSel(20,LineLength+6);
//替換 RGB內容
m_tipEdit.ReplaceSel(string);
}
//保存RGB值字符串
strOld=string;
}
二、程序在調整大小和位置時,主窗口收不到消息,這是由於CRectTracker內部處處理了消息,看一下 CRectTracker::TrackHandle的MFC源碼 :
// get messages until capture lost or cancelled/accepted
for (;;)
{
MSG msg;
VERIFY (::GetMessage(&msg, NULL, 0, 0));
if (CWnd::GetCapture() != pWnd)
break;
//增加的,把消息派送給窗口
DispatchMessage(&msg);
switch (msg.message)
{
// handle movement/accept messages
case WM_LBUTTONUP:
case WM_MOUSEMOVE:
rectOld = m_rect;
// handle resize cases (and part of move)
if (px != NULL)
*px = (int) (short)LOWORD(msg.lParam) - xDiff;
if (py != NULL)
*py = (int)(short)HIWORD(msg.lParam) - yDiff;
// handle move case
if (nHandle == hitMiddle)
{
m_rect.right = m_rect.left + nWidth;
m_rect.bottom = m_rect.top + nHeight;
}
// allow caller to adjust the rectangle if necessary
AdjustRect(nHandle, &m_rect);
// only redraw and callback if the rect actually changed!
m_bFinalErase = (msg.message == WM_LBUTTONUP);
if (!rectOld.EqualRect(&m_rect) || m_bFinalErase)
{
if (bMoved)
{
m_bErase = TRUE;
DrawTrackerRect(&rectOld, pWndClipTo, pDrawDC, pWnd);
}
OnChangedRect(rectOld);
if (msg.message != WM_LBUTTONUP)
{
bMoved = TRUE;
}
}
if (m_bFinalErase)
goto ExitLoop;
if (!rectOld.EqualRect(&m_rect))
{
m_bErase = FALSE;
DrawTrackerRect (&m_rect, pWndClipTo, pDrawDC, pWnd);
}
break;
// handle cancel messages
case WM_KEYDOWN:
if (msg.wParam != VK_ESCAPE)
break;
case WM_RBUTTONDOWN:
if (bMoved)
{
m_bErase = m_bFinalErase = TRUE;
//DrawTrackerRect(&m_rect, pWndClipTo, pDrawDC, pWnd);
}
m_rect = rectSave;
goto ExitLoop;
// just dispatch rest of the messages
default:
DispatchMessage(&msg);
break;
}
}
我們只要在GetMessage(&msg, NULL, 0, 0)之後調用DispatchMessage(&msg),就可以把消息傳遞到 主窗口,這樣,內部處理和主窗口消息兩不誤,進而為程序為CRectTrakcer不能響應WM_LBUTTONUP和其消 息而不用大改程序了...
三、CRectTracker類的簡要說明和改造類CMyTracker, CMyTracker類中增加 了更改矩形顏色方法,增加StyleFlags的resizeMiddle設置中間位置,增加SetResizeCursor方法用開改 變調整矩形大小和位置時鼠標光標,CRectTracker類中有幾個重要的成員方法,一個是Draw方法負責畫出 當前矩形,在此方法中可能更改矩形顏色,看如下代碼
// draw lines
if ((m_nStyle & (dottedLine|solidLine)) != 0)
{
if (m_nStyle & dottedLine)
{
//改變當前矩形顏色 ,點線
pOldPen = pDC->SelectObject(CPen::FromHandle(_afxBlackDottedPen));
}
else
{
//改變當前矩形顏色 ,實線
//pOldPen = (CPen*)pDC->SelectStockObject(BLACK_PEN);
pOldPen = pDC- >SelectObject(CPen::FromHandle(_afxBlackSolidPen));
}
pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
nOldROP = pDC- >SetROP2(R2_COPYPEN);
rect.InflateRect(+1, +1); // borders are one pixel outside
pDC->Rectangle(rect.left, rect.top, rect.right, rect.bottom);
pDC->SetROP2(nOldROP);
}
其中_afxBlackSolidPen是我增加的全局 畫筆句柄,在初始化時創建,通過增加的SetRectColor方法可以改變顏色, 修改了矩形顏色,當然還得 修改調整矩形手柄了,也就是那八個點,修改代碼處如下:if ((m_nStyle & (resizeInside|resizeOutside)) != 0)
{
UINT mask = GetHandleMask();
for (int i = 0; i < 8; ++i)
{
GetHandleRect ((TrackerHit)i, &rect);
//改變當前調整手柄矩形顏色,也就是那八個點
pDC->FillSolidRect(rect, m_rectColor);
}
}
其次是Track方法和TrackRubberBand方法,在其內部主要是調用TrackHandle方法,在Tracker方法中 主要是消息捕獲處理,動態調整當前 m_rect 矩形大小,和在調整大小和位置時畫出虛線,當然畫虛線 功能是在DrawTrackerRect方法中實現,在此方法中主要是調用CDC類中的DrawDragRect方法,至使動態 畫虛線時不用刷新窗口.程序中由於不需要畫虛線所以把DrawTrackerRect方法中代碼注釋了,直接更新主窗口,如果需要原來的功能,可能把注釋去掉,在CRectTracker類中還有一些輔助方法,在這就 不一一講說。
四、CMyTracker類從MFC源文件COPY過來,頭文件在AFXEXT.H中,實現文件為 TRCKRECT.CPP,COPY時去掉了一些調試信息,類的無參數構造
函數定義為內聯函數,是在 AFXEXT.INL中實現,在構造函數中調用類中初始化函數Construct(),可以直接在實現文件中加入無參數 構造函
的實現,直接調用函數Construct(),其實這些簡單的功能只要直接修改MFC源代碼,程序 調試完成後再改回來,但這樣不能很好的通用,有些朋友認為微軟的MFC源碼神聖不可侵犯,但是為了程 序的性能和功能,就要不擇手段。