MFC、MFC(Microsoft Foundationクラス)の最近学んだ知識は、マイクロソフトが提供するライブラリである、理解することは簡単なことができ、Win32のパッケージ(Windows API関数のためのMFCパッケージ)のためですが、MFCは、主にオブジェクト指向の導入であります開発は、オブジェクトと呼ばれるすべてのもの、オブジェクト指向の考え方は、私はC ++の統合に大きな助けと思うことを考えて、それがわかりました。知識はいくつかの時間前にWIN32を学んだので、私たちは主に関連するアイデアが介入のポイントとして導入されている++比較Win32とCには、その次の物語で、シンプルな機能とスクリーンショットツールを開発しました。
はじめにMFC(MFCの基盤が友人を持って、あなたはこの段落をスキップすることができます)
1.メッセージマップ
WIN32がスイッチケースを介して、メッセージループにある応答メッセージは、実際には、MFCに、メッセージの代わりに配列をトラバースすることによって部分的に繰り返され、実現され、それぞれのクラスに参加すること)(DECLARE_MESSAGE_MAP、BEGIN_MESSAGE_MAP() 、END_MESSAGE_MAP()は、アレイは、様々なメッセージに対応する関数ポインタに格納され、そしてメッセージとメッセージ処理機能は、マッピングテーブル、メッセージと呼ばれるマッピングテーブルを構成します。同じ目的を持つ配列を作成するために、別の記事ではこの動的な側面とブログ。
2.MFCフレームワーク
MFCシステムによってフレームと最初のウィンドウを設定し、CWinAppの、CFrameWndの、CViewの、CDocumentのこれらのクラスのフォーム、これらのクラス階層、下図のように私を要約したもの
3.MFCメッセージ分類
このメッセージが異なるとWin32、キーボード、マウスとは異なり、MFCコマンドメッセージ、制御/通知メッセージ、カスタムメッセージに標準/システムメッセージに分ける目的で送信されたメッセージのこれらのタイプは、同じを総括し、私がしていました示すように使用すると、どのように、追加します。
この時点でカスタムメッセージにユーザーが実装上の2つの異なる機能を送信する、のSendMessage()がターゲットクラスに直接送信され、そしてのPostMessage()ターゲットクラス、メッセージ・キューに送信されることに注意すること自身のメッセージを傍受するためには、同期と非同期のメッセージ配信機能としても知られている効果なし、から来ました。
そして、あなたは、この画面キャプチャツールの開発者は、デスクトップの顧客領域に格納されている情報は、はいそれはとても簡単ですが、追加機能を描画し、撤回する能力である、すべての最初は、デスクトップ画面情報を取得し、考えを教えて
Snipping Toolを開発
1. MFC窓枠のスタイルを変更します。
これは私がステータスバー、ツールバー、国境(WS_POPUP)を削除し、フルスクリーンポップアップ状態である(Microsoftの開発者やオペレータのビットは、MFCに変数は様々なスタイルを表現することは注目に値する、変わりますさまざまな属性を追加するために)、私は日常業務である、プラスの財産で日常の開発者を信じて、そう、排他的論理和、または反転して属性を削除、変更するときにすることができます
2.一連の制御、およびメッセージハンドラの追加を追加します。
これらは、すべてのコマンドメッセージは、閉じ制御がニュースに追加された以下に示すように、直接ではなく、閉じたメッセージ機能直接PostQuitMessage()に、直接呼び出しているため、その後、メモリリークが存在するであろうことに留意すべきであるれます。
最後のステップを見ることができます> ...-> PostQuitMessageは、終了するにはダイレクトメッセージを送信するので、送信されたメインウィンドウ(CMainFrmeクラス)に、同時に終了をクリックしてください - このプロセスが閉じられたメッセージであるため、WM_CLOSE->破壊クローズニュース
this->のPostMessage(WM_CLOSE);
3.スクリーンショット
そして、画面キャプチャツールの主な機能があり、私は最初のステップ、デスクトップの写真を撮る、第二段階、保存し、第三のステップは、クライアント領域をマッピングするために、3つのステップに分け
これは、MFCにカプセル化された導入HDCを必要とする、HDC Windowsが(例えば、モニタやプリンタなどの)デバイスに関する図面属性情報を含むデータ構造です。さらにMFCはGetDC、ReleaseDCのCDC機能を手動で作成し、解放することなく呼び出しに加えて、クラスのコンストラクタとデストラクタにカプセル化される一方ホワイトパネルに相当するデバイスコンテキストオブジェクトを介して全ての描画呼び出し、ウィンドウハンドルを取得しない、と誰が得る人呼んで、私はいくつかの一般的なDCのクラスをまとめ、
CClientDC DC(本) | Viewクライアントエリア |
CClientDC DC(AfxGetMainWnd()) | メインウィンドウを取得 |
CWindowDC DC(AfxGetMainWnd()) | 窓 |
CWindowDC DC(GetDesktopWindow()) | デスクトップウィンドウ |
1 のCMainFrame ::のCMainFrame() 2 { 3 // ============ ===============セーブデスクトップ画像を得る 4 5 // ---画面パラメータ----------- ----------------獲得 6。 m_nScreenCX = :: GetSystemMetrics関数(SM_CXSCREEN)を、 7 m_nSCreenCY = :: GetSystemMetrics関数(SM_CYSCREEN)。 8 // -------------- ----------------取得画面パラメータ 9 10 // ---------- --- ----------------デスクトップ画像を取得 11 CWindowDC DesktopDC(GetDesktopWindow()); 12 CDC CDC; 13 cdc.CreateCompatibleDC(&DesktopDC); 14 15 CBitmap *bitmap = new CBitmap; 16 bitmap->CreateCompatibleBitmap(&DesktopDC,m_nScreenCX,m_nSCreenCY); 17 cdc.SelectObject(bitmap); 18 cdc.BitBlt(0,0,m_nScreenCX,m_nSCreenCY,&DesktopDC,0,0,SRCCOPY); 19 //------------- 获取桌面图片---------------- 20 21 22 //-----------------保存-------------------- 23 sk.push(bitmap); 24 25 26 27 //-----------------保存-------------------- 28 29 //============获取桌面图片 保存=============== 30 }
值得注意的是,我选择了栈作为保存方式,主要是因为我考虑到之后要写撤销的功能,而之后事实证明,利用栈这一数据结构来保存好处不止这一点,此时的效果如图
4.画图控件处理
我添加了 曲线,直线,长方形,圆形,三角形这些画图功能,在MFC中 ON_COMMAND_RANGE(起始ID,终止ID,处理函数地址)这个函数可以此命令可以处理相同操作的ID,因为无论什么形状,最终的功能就是画图,接下来就是如何判断点击的是何种控件,在这个地方用if去判断也可以,我利用资源中这个控件图片宏的连续性(不连续可以改连续),和枚举来进行判断,避免了大量的if判断
1 enum {PEN,LINE,RETANGLE,CIRCULAR,TANGLE}; 2 3 void CCUTBITMAPView::OnChooseTool(UINT nID) 4 { 5 m_nDrawStyle = nID - ID_TOOL_PEN; 6 }
接下来就是画图功能,来分析一下,在选择后鼠标按下开始画,鼠标松开时结束画,所以添加了WM_LBUTTONDOWN,WM_LBUTTONUP,WM_MOUSEMOVE三个命令消息,并且建立一个标记来记录鼠标是否按下了,不然的话,打开后不用点击就会自动开始画,除了曲线以外都可以用MFC库函数来进行查询(简单练习不建议使用太复杂的多边形,因为到最后就是复杂的高中几何题呀),曲线的画法就像微积分中的微分思维一样,当一条曲线切割的足够短时,就是N多条直线组成,那么只要起始和结束坐标切换足够快的话就是曲线了。
5.bug处理
到这一步就可以在截屏的图案上进行绘画了,但是会发现之前画的痕迹并没有消除,有点3D的感觉,哈哈哈,如何处理这个问题呢,重复贴图,利用之前的栈顶元素来擦除痕迹,接下来痕迹是没有了,但是不停的在闪烁,常见问题--闪烁就用双缓冲来解决吧,不过MFC和WIn32这个思维转化的有点困难,对象调用的思维还得多熟悉熟悉,把代码贴上来,有MFC的初学者也可以看看
1 void CCUTBITMAPView::OnMouseMove(UINT nFlags, CPoint point) 2 { 3 CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd(); 4 if(m_bIsLButtonDown == true) 5 { 6 CClientDC dc(this); 7 if(m_nDrawStyle == PEN) 8 { 9 dc.MoveTo(FirstPoint); 10 dc.LineTo(point); 11 FirstPoint = point; 12 return; 13 } 14 //------------双缓冲------------ 15 CDC hMenDC; 16 hMenDC.CreateCompatibleDC(&dc); 17 CBitmap bitmap; 18 bitmap.CreateCompatibleBitmap(&dc,pFrame->m_nScreenCX,pFrame->m_nSCreenCY); 19 hMenDC.SelectObject(bitmap); 20 21 22 //------------双缓冲------------ 23 24 //-----------用栈顶元素 擦除轨迹------------ 25 CDC cdc; 26 cdc.CreateCompatibleDC(&dc); 27 cdc.SelectObject(pFrame->sk.top()); 28 hMenDC.BitBlt(0,0,pFrame->m_nScreenCX,pFrame->m_nSCreenCY,&cdc,0,0,SRCCOPY); 29 //-----------用栈顶元素 擦除轨迹------------ 30 switch (m_nDrawStyle) 31 { 32 case LINE: 33 { 34 hMenDC.MoveTo(FirstPoint); 35 hMenDC.LineTo(point); 36 } 37 break; 38 case RETANGLE: 39 { 40 hMenDC.Rectangle(FirstPoint.x,FirstPoint.y,point.x,point.y); 41 } 42 break; 43 case CIRCULAR: 44 { 45 hMenDC.Ellipse(FirstPoint.x,FirstPoint.y,point.x,point.y); 46 } 47 break; 48 case TANGLE: 49 { 50 POINT tangle[3] = { 51 {(FirstPoint.x+point.x)/2,FirstPoint.y}, 52 {point.x,point.y}, 53 {FirstPoint.x,point.y} 54 }; 55 hMenDC.Polygon(tangle,3); 56 } 57 break; 58 } 59 dc.BitBlt(0,0,pFrame->m_nScreenCX,pFrame->m_nSCreenCY,&hMenDC,0,0,SRCCOPY); 60 } 61 62 CView::OnMouseMove(nFlags, point); 63 }
但是每一次画的,第二次点击,都会覆盖掉,解决这个,就是和当时截取桌面画面一样,只不过这次在鼠标抬起时,截取客户区,存入栈中,同样每次拿栈顶消除痕迹就会留下痕迹了,代码如下
1 void CCUTBITMAPView::OnLButtonUp(UINT nFlags, CPoint point) 2 { 3 m_bIsLButtonDown = false; 4 //----------------------留下之前的痕迹----------------------- 5 CMainFrame *pFrame = (CMainFrame*)AfxGetMainWnd(); 6 7 8 CClientDC dc(this); 9 10 CDC cdc; 11 cdc.CreateCompatibleDC(&dc); 12 CBitmap *pBitMap = new CBitmap; 13 pBitMap->CreateCompatibleBitmap(&dc,pFrame->m_nScreenCX,pFrame->m_nSCreenCY); 14 cdc.SelectObject(pBitMap); 15 cdc.BitBlt(0,0,pFrame->m_nScreenCX,pFrame->m_nSCreenCY,&dc,0,0,SRCCOPY); 16 17 pFrame->sk.push(pBitMap); 18 //----------------------留下之前的痕迹----------------------- 19 CView::OnLButtonUp(nFlags, point); 20 }
6.撤销功能
Ctrl+Z首先先添加到键盘映射表中
主要思路就是不停的将栈顶元素弹出栈中,就可以了,代码如下
1 void CMainFrame::OnAccelerator32778() 2 { 3 //撤销的函数 4 if(sk.size() > 1) 5 { 6 delete sk.top(); 7 sk.pop(); 8 GetActiveView()->SendMessage(WM_PAINT); 9 } 10 }
接下来,还有保存等其他的功能,未完待续。。。,先放一张实现的截图
最后,记录一个我觉得挺重要MFC的消息流向(因为知道,什么消息写在哪个类中)
标准消息 | WM_XXX | 子类到父类,查找消息映射表 |
命令消息 | WM_COMMAND | 消息路由 CView-->CDoc-->CDocTemplate-->CFrameWnd-->CWinApp |
控件/通知消息 | WM_NOTIFY | 子窗口到父窗口,查找消息映射表 |
自定义消息 | UM_XXX | 确定了,查找调用者那个类 |
2019-07-21 19:17:07 编程小菜鸟自我总结,来往的朋友可以留下自己的建议和意见,谢谢!!!