vs2019 MFC實現office界面的畫圖小項目
vs2019安裝MFC
有許多新手不知道MFC在vs2019裡的安裝選項,其實它不會在勾選工作負載時自動默認勾選,而通常需要人為勾選,具體安裝步驟如下:(安裝時間不是很長,網速夠快幾分鐘就下載完畢)
1.打開vs安裝程序
2.選擇Visual Studio擴展開發
3.選擇C++ MFC 生成工具(x86 和 x64)進行安裝
4.選擇修改,等待安裝
5.等待安裝完成
6.安裝完成,我們打開vs2019
7.我們創建新項目,可以看到已經有MFC應用這個選項
說明我們的MFC安裝成功~
vs2019 MFC實現office界面的畫圖小項目
一、創建項目
1.點擊文件–>新建–>項目,選擇MFC應用,點擊下一步
2.項目名稱為Draw,點擊創建
3.可以看到有很多內容
4.應用程序類型有:
- 單個文檔
- 多個文檔
- 基於對話框
- 多個頂層文檔
5.項目樣式有:
- MFC standard
- Windows Explorer
- Visual Studio
- Office
6.這裡應用程序類型選擇多個文檔,項目樣式選擇Office。
視覺樣式和顏色選擇默認的Office 2007(Blue theme)即可。
值得註意的是:Office會比默認選擇的項目樣式多一個Ribbon框,後面會說到~
7.點擊下一步,我們來到文檔模板屬性,可以看到主框架描述和文檔類型名稱等內容,這裡可以默認不用修改
8.下一步,來到用戶界面功能,可以看到Command bar裡有三個選項,這裡我們選擇默認的使用功能區(ribbon)
9.下一步,來到高級功能,可以直接默認跳過
10.點擊下一步來到最後一步——生成的類,可以看到生成的類和類名,我們選擇默認的App即可,這樣我們的頭文件和.cpp文件就是以項目名稱命名
11.點擊完成,之後看到左側的解決方案資源管理器,這裡包含瞭5個內容:
- 引用
- 外部依賴項
- 頭文件
- 源文件
- 資源文件
其中,我們可以在頭文件和源文件裡看到生成的.h和.cpp文件
二、進入多個文檔的控件界面
1.因為是基於多個文檔,所以我們需要瞭解如何在對話框上如何添加控件。因此我們可以雙擊 項目名稱.rc2,進入資源視圖;
當然,我們也可以直接點擊系統默認打開的底下的資源視圖選項(註意:不能resource.h文件同時打開!!!)
在這裡喲~
如果不小心關閉瞭,也可以在菜單欄裡 視圖->資源視圖裡重新打開該視圖
2.這裡比較重要的是Menu部分,因為有很多MFC已經內置好的功能,例如主框架IDR_MAINFRAME裡就有文件下拉菜單等選項,我們想要添加一個新的下拉菜單,隻需要在右邊的“請在此鍵入”輸入內容,並且編寫對應的代碼即可。但這裡博主並不在這裡添加畫圖的功能。
3.博主這裡要在Ribbon裡添加畫圖的功能
4.點擊右邊的工具箱(豎著的,治療頸椎~)
然後點擊Ribbon編輯器,可以看到有很多種類的控件
三、編寫畫圖小程序(先從畫矩形開始)
1.我們點擊面板,然後拖動到窗口面板的右邊,可以看到多瞭一個面板1
2.我們點擊這個面板,在屬性窗口中的外觀下面,修改Caption,把面板1改為圖形,這就算給這個面板改瞭名字
3.我們再選擇Ribbon工具箱裡的按鈕,同樣拖動,至圖形面板,如下,名字為button1
4.修改這個按鈕的屬性中雜項的ID,改為ID_RECTANGLE
這裡指的註意的就是這個ID,這個在MFC編程中十分重要,因為我們往往需要獲取控件的ID號來對該控件進行函數編寫、消息處理等操作!!!
5.既然是按鈕,那就得有觸發這個按鈕所要執行的操作,右鍵這個按鈕,我們選擇添加事件處理程序
6.彈出以下框
7.類列表我們選擇CDrawView,點擊確定
8.我們可以看到在DrawView.cpp中生成的命令函數
我們也可以看到在前面的代碼中多瞭一個ON_COMMAND函數,說明我們確實添加瞭這樣的一個按鈕命令(註意:ID_RECTANGLE這個ID號就是對應的按鈕的編號,&CDrawView::OnRectangle表示這個ID的按鈕實現的命令函數)
這裡的紅波浪線提示沒有這個ID,其實我們是添加瞭這個按鈕的,可以在Resource.h中看到(註意打開Resource.h再去看資源試圖是打不開的,會報錯,因此需要先關掉Resource.h再去訪問資源試圖!!!!!)
#define ID_RECTANGLE 32771
這個IDE編輯器的小問題,我們可以選擇重啟vs2019打開就不會顯示未定義ID瞭,如下,沒有紅色波浪線瞭
9.現在的問題就是如何畫圖的問題:畫矩形,則定義一個矩形類,寫方法,在消息函數裡新建對象即可;但是我們如果不滿足隻畫矩形呢?畫箭頭、三角可不可以?這個時候我們就應該想到繼承,即建一個抽象類graph,然後派生幾個子類去完成這個功能。因此我們應該先新建一個graph抽象類:
我們右鍵頭文件,選擇添加–>新建項,彈出如下界面;
選擇頭文件(.h),名稱為graph.h,點擊確定
10.如下
11.添加如下代碼:
graph.h
class graph : public CObject { protected: //邊框 DECLARE_SERIAL(graph) int left, up, right, down; //選中狀態 unsigned int state; int sx, sy; int f_width = 5; int fcolor = 0xffffff, bcolor = 0; public: graph() :graph(50, 50, 100, 100) { } graph(int l, int u, int r, int d); void Offset(int cx, int cy); void onPress(int x, int y); // 鼠標按下 int onMove(int cx, int cy); // 鼠標移動 void onRelease(int x, int y); // 鼠標釋放 virtual void onDraw(CDC* pDC); virtual int getGraphID() { return 0; } virtual void Serialize(CArchive& ar); void SetFillColor(int color); void SetBorderColor(int color); ~graph(); };
結果報瞭一堆錯誤,事實是因為我們新建的graph並沒有和MFC本身的類關聯起來
我們可以這樣做:打開framework.h(vs2017裡是stdafx.h),我們在這裡include一下我們的graph抽象類
如下(註意自己寫的頭文件要使用引號“”)
#include "graph.h"
我們再回過頭看graph.h,發現已經沒有錯誤瞭
12.寫瞭頭文件,還要寫對應的源文件:
我們右鍵頭文件,選擇添加–>新建項,彈出如下界面;
選擇C++文件(.cpp),名稱為graph.cpp,點擊確定
13.如下
14.填寫如下代碼
graph.cpp
#include "framework.h" IMPLEMENT_SERIAL(graph, CObject, 1) graph::graph(int l, int u, int r, int d) { left = l; up = u; right = r; down = d; state = 0; fcolor = 0xffffff; } void graph::Offset(int cx, int cy) { left += cx; right += cx; up += cy; down += cy; } void graph::onPress(int x, int y) { sx = x; sy = y; state = 0; //選中圖形 if (left < x && x < right && up < y && y < down) { state = 1; return; } if (left - f_width / 2 < x && x < left + f_width / 2) state |= 2; // 選中左邊 if (up - f_width / 2 < y && y < up + f_width / 2) state |= 4;//選中上邊 if (right - f_width / 2 < x && x < right + f_width / 2) state |= 8;//選中右邊 if (down - f_width / 2 < y && y < down + f_width / 2) state |= 16; // 選中下邊 } void graph::onRelease(int x, int y) { state = 0; } void graph::SetBorderColor(int color) { fcolor = color; } void graph::SetFillColor(int color) { bcolor = color; } int graph::onMove(int x, int y) { int cx, cy; cx = x - sx; cy = y - sy; sx = x; sy = y; if (state == 1) { Offset(cx, cy); // 位移量cx,cy } if (2 == (state & 2)) { left = x; } if (4 == (state & 4)) { up = y; } if (8 == (state & 8)) { right = x; } if (16 == (state & 16)) { down = y; } return state == 0 ? 0 : 1; } void graph::Serialize(CArchive & ar) { CObject::Serialize(ar); if (ar.IsLoading()) { ar >> left >> right >> up >> down >> f_width >> fcolor >> bcolor; } else { ar << left << right << up << down << f_width << fcolor << bcolor; } } graph::~graph() { } void graph::onDraw(CDC * pDC) { CBrush b(fcolor); pDC->SelectObject(&b); CRect r(left, up, right, down); pDC->FillRect(&r, &b); CPen p(PS_SOLID, 1, bcolor); pDC->SelectObject(&p); pDC->Rectangle(left, up, right, down); pDC->MoveTo(left, up); pDC->DrawText(_T("空圖形"), -1, new CRect(left, up, right, down), DT_CENTER | DT_VCENTER | DT_SINGLELINE); }
15.根據上面的步驟,同樣地,我們再新建一個矩形Rectangle類。這裡直接列出頭文件和源文件
rectangle.h
#pragma once #include "graph.h" class rectangle : public graph { public: //DECLARE_SERIAL(graph) //void Serialize(CArchive& ar); rectangle() :graph(50, 50, 100, 100) {} rectangle(int l, int u, int r, int d); void onDraw(CDC* pDC); int getGraphID() { return 2; } ~rectangle(); };
rectangle.cpp
#include "framework.h" rectangle::rectangle(int l, int u, int r, int d) :graph(l, u, r, d) { state = 0; fcolor = 0xffffff; } void rectangle::onDraw(CDC* pDC) { CBrush b(fcolor); pDC->SelectObject(&b); CRect r(left, up, right, down); pDC->FillRect(&r, &b); CPen p(PS_SOLID, 1, bcolor); pDC->SelectObject(&p); pDC->Rectangle(left, up, right, down); pDC->MoveTo(left, up); } rectangle::~rectangle() { }
註意framework.h不要忘瞭加上:
#include "rectangle.h"
16.由於我們需要可以添加多個圖形,因此一個以graph對象構成的list是必不可少的。我們在DrawDoc.h文檔頭文件添加這個list,可以添加//操作下面
17.如下,可以看到又報錯瞭:
std::list<graph*> graphList;
還是一樣的,把list的頭文件加到framework.h中
#include <list>
再回去看DrawDoc.h,發現沒有錯誤
18.我們再回到DrawView.cpp,填寫矩形Rectangle的消息處理程序,如下。代碼解釋為每點擊一次矩形按鈕,添加一個矩形:
void CDrawView::OnRectangle() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; pDoc->graphList.push_front(new rectangle(50, 50, 100, 100)); Invalidate(); }
19.我們還需要修改DrawView.cpp裡的繪圖代碼部分
添加如下代碼(CDC* 後面的pDC取消註釋)
// CDrawView 繪圖 void CDrawView::OnDraw(CDC* pDC) { CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此處為本機數據添加繪制代碼 std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->onDraw(pDC); } }
20.運行程序,發現報錯,這是預編譯頭的問題
1>—— 已啟動生成: 項目: Draw, 配置: Debug Win32 ——
1>pch.cpp
1>calendarbar.cpp
1>ChildFrm.cpp
1>Draw.cpp
1>DrawDoc.cpp
1>DrawView.cpp
1>graph.cpp
1>D:\vs2019_project\Draw\graph.cpp(110): fatal error C1010: 在查找預編譯頭時遇到意外的文件結尾。是否忘記瞭向源中添加“#include “pch.h””?
1>MainFrm.cpp
1>rectangle.cpp
1>D:\vs2019_project\Draw\rectangle.cpp(25): fatal error C1010: 在查找預編譯頭時遇到意外的文件結尾。是否忘記瞭向源中添加“#include “pch.h””?
1>正在生成代碼…
1>已完成生成項目“Draw.vcxproj”的操作 – 失敗。
========== 生成: 成功 0 個,失敗 1 個,最新 0 個,跳過 0 個 ==========
21.點擊菜單欄的項目–>屬性,選擇C/C++–>預編譯頭,如下
改為不使用預編譯頭,點擊確定
22.我們再次運行代碼,出現如下界面
23.我們點擊圖形面板的矩形,可以看到窗口生成瞭一個矩形
24.然而,僅僅是生成一個矩形還是不夠的;我們還需要添加鼠標的相關消息響應函數,例如鼠標移動,鼠標按下和鼠標抬起
右鍵源文件,點擊類向導
25.如下
26.我們添加一個鼠標左鍵按下的消息響應:選擇消息欄,選擇WM_LBUTTONUP,類名選擇CDrawView,點擊添加處理程序
如下
添加如下代碼:
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息處理程序代碼和/或調用默認值 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此處為本機數據添加繪制代碼 std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->onPress(point.x, point.y); } Invalidate(); //CView::OnLButtonDown(nFlags, point); }
27.同樣地,我們再添加鼠標左鍵松開
填寫代碼:
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息處理程序代碼和/或調用默認值 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此處為本機數據添加繪制代碼 std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->onRelease(point.x, point.y); } Invalidate(); //CView::OnLButtonUp(nFlags, point); }
28.同樣地,我們再添加鼠標移動
填寫代碼:
void CDrawView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息處理程序代碼和/或調用默認值 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此處為本機數據添加繪制代碼 std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->onMove(point.x, point.y); } Invalidate(); //CView::OnMouseMove(nFlags, point); }
29.運行程序,我們點擊矩形,可以拖動這個矩形瞭!!
30.博主這裡還做瞭放大和縮小:把鼠標移到矩形邊緣,點擊邊緣就可以放大縮小~
31.當然,我們還可以再添加好幾個矩形,因為別忘瞭博主是用list來存儲每次生成的graph對象的~
四、我們還可以再多畫一些,例如箭頭、直線和三角
1.相信前面的步驟大傢瞭解的話,我相信添加按鈕是很容易的,這裡就直接給出博主的按鈕ID
三角形:ID_TRIANGLE
箭頭:ID_ARROW
直線:ID_LINE
2.添加的類和方法:
*framework.h
#include <afxwin.h> // MFC 核心組件和標準組件 #include <afxext.h> // MFC 擴展 #include "graph.h" #include "rectangle.h" #include "triangle.h" #include "arrow.h" #include "line.h" #include <list>
(1)三角形:
triangle.h
#pragma once #include "graph.h" class triangle : public graph { protected: public: triangle(int l, int u, int r, int d); int getGraphID() { return 3; } void onDraw(CDC* pDC); ~triangle(); };
triangle.cpp
#include "framework.h" triangle::triangle(int l, int u, int r, int d) :graph(l, u, r, d) { state = 0; fcolor = 0xffffff; } void triangle::onDraw(CDC* pDC) { CPoint pts[3]; pts[0].x = (left + right) / 2; pts[0].y = up; pts[1].x = left; pts[1].y = down; pts[2].x = right; pts[2].y = down; CBrush b(fcolor); pDC->SelectObject(&b); CPen p(PS_SOLID, 1, bcolor); pDC->SelectObject(&p); pDC->Polygon(pts, 3); } triangle::~triangle() { }
(2)箭頭:
arrow.h
#pragma once #include "graph.h" class arrow : public graph { public: arrow(int l, int u, int r, int d); void onDraw(CDC* pDC); int getGraphID() { return 4; } ~arrow(); };
arrow.cpp
#include "framework.h" arrow::arrow(int l, int u, int r, int d) :graph(l, u, r, d) { } void arrow::onDraw(CDC* pDC) { CPoint pts[2], pt[3]; pts[0].x = left; pts[0].y = (up + down) / 2; pts[1].x = (left + right) / 2; pts[1].y = (up + down) / 2; pt[0].x = (left + right) / 2; pt[0].y = up; pt[1].x = (left + right) / 2; pt[1].y = down; pt[2].x = right; pt[2].y = (up + down) / 2; CBrush b(fcolor); pDC->SelectObject(&b); CPen p(PS_SOLID, 1, bcolor); pDC->SelectObject(&p); pDC->Polygon(pts, 2); pDC->Polygon(pt, 3); } arrow::~arrow() { }
(3)直線:
line.h
#pragma once #include "graph.h" class line : public graph { public: line() :line(50, 50, 100, 100) {} line(int l, int u, int r, int d); void onDraw(CDC* pDC); int getGraphID() { return 1; } ~line(); };
line.cpp
#include "framework.h" line::line(int l, int u, int r, int d) :graph(l, u, r, d) { state = 0; fcolor = 0xffffff; } void line::onDraw(CDC* pDC) { CPoint pts[2]; pts[0].x = left; pts[0].y = (up + down) / 2; pts[1].x = right; pts[1].y = (up + down) / 2; CBrush b(fcolor); pDC->SelectObject(&b); CPen p(PS_SOLID, 1, bcolor); pDC->SelectObject(&p); pDC->Polygon(pts, 2); } line::~line() { }
3.添加的事件處理程序:
(1)三角形:
void CDrawView::OnTriangle() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; pDoc->graphList.push_front(new triangle(50, 50, 100, 100)); Invalidate(); }
(2)箭頭:
void CDrawView::OnArrow() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; pDoc->graphList.push_front(new arrow(50, 50, 100, 100)); Invalidate(); }
(3)直線:
void CDrawView::OnLine() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; pDoc->graphList.push_front(new line(50, 50, 100, 100)); Invalidate(); }
4.運行程序,現在可以添加各種圖形並且可以改變大小啦
五、圖形的輪廓填充和內部填充(為瞭方便,都是統一更改顏色,一個一個改代碼很麻煩)
1.添加一個面板,再添加兩個按鈕。按鈕的選擇是顏色按鈕
2.如下
輪廓:ID_FILLCOLOR_LINE
內部:ID_FILLCOLOR_IN
3.添加的事件處理程序:
(1)需要在DrawView.cpp中添加MainFrm.h頭文件
#include "MainFrm.h"
(2)還需要在MainFrm.h中將m_wndRibbonBar從protected變為public,這樣才能訪問到這個變量,否則報錯!
protected: // 控件條嵌入成員 //CMFCRibbonBar m_wndRibbonBar; CMFCRibbonApplicationButton m_MainButton; CMFCToolBarImages m_PanelImages; CMFCRibbonStatusBar m_wndStatusBar; COutlookBar m_wndNavigationBar; CMFCShellTreeCtrl m_wndTree; CCalendarBar m_wndCalendar; CMFCCaptionBar m_wndCaptionBar; public: CMFCRibbonBar m_wndRibbonBar;
輪廓
void CDrawView::OnFillcolorLine() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd(); CMFCRibbonColorButton* a = (CMFCRibbonColorButton*)((pFrame->m_wndRibbonBar).FindByID(ID_FILLCOLOR_LINE)); COLORREF c = a->GetColor(); std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->SetFillColor(c); } Invalidate(); }
內部
void CDrawView::OnFillcolorIn() { // TODO: 在此添加命令處理程序代碼 CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; CMainFrame* pFrame = (CMainFrame*)AfxGetMainWnd(); CMFCRibbonColorButton* a = (CMFCRibbonColorButton*)((pFrame->m_wndRibbonBar).FindByID(ID_FILLCOLOR_IN)); COLORREF c = a->GetColor(); std::list<graph*>::iterator v; for (v = pDoc->graphList.begin(); v != pDoc->graphList.end(); ++v) { (*v)->SetBorderColor(c); } Invalidate(); }
4.運行程序
(1)輪廓變紅,選擇紅色
如下
(2)內部填充為綠色,選擇綠色
如下
六、序列化保存和讀取文件
1.修改DrawDoc.cpp的序列化部分,這是用於菜單欄裡的保存和打開圖片所使用的
2.修改代碼如下:
// CDrawDoc 序列化 void CDrawDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: 在此添加存儲代碼 ar << graphList.size(); for (auto it = graphList.begin(); it != graphList.end(); it++) { ar << (*it)->getGraphID(); (*it)->Serialize(ar); } } else { // TODO: 在此添加加載代碼 for (auto it = graphList.begin(); it != graphList.end(); it++) { delete* it; } graphList.clear(); int i, gid; ar >> i; graph* g; while (i--) { ar >> gid; switch (gid) { case 1: g = new line(); break; case 2: g = new rectangle(); break; case 3: g = new triangle(0, 0, 0, 0); break; case 4: g = new arrow(0, 0, 0, 0); break; default: g = new graph(); break; } g->Serialize(ar); graphList.push_back(g); } } }
3.運行程序:博主隨便畫一個圖
選擇保存,默認路徑和名字
可以看到有一個Draw1的文件
我們關掉程序,再運行程序,打開這個文件
可以看到多一個窗口,說明我們序列化成功!!
七、自己寫一個導出文件的按鈕
1.再新建一個面板,拖入一個按鈕,名字到導出圖片,ID為ID_SAVE
2.添加的事件處理程序:
void CDrawView::OnSave() { // TODO: 在此添加命令處理程序代碼 CClientDC dc(this); CRect rect; CString saveFilePath; BOOL showMsgTag; BOOL saveTag = FALSE; GetClientRect(&rect); HBITMAP hbitmap = CreateCompatibleBitmap(dc, rect.right - rect.left, rect.bottom - rect.top); HDC hdc = CreateCompatibleDC(dc); HBITMAP hOldMap = (HBITMAP)SelectObject(hdc, hbitmap); BitBlt(hdc, 0, 0, rect.right - rect.left, rect.bottom - rect.top, dc, 0, 0, SRCCOPY); CImage image; image.Attach(hbitmap); if (!saveTag) { saveTag = TRUE; showMsgTag = TRUE; CString strFilter = _T("位圖文件(*.bmp)|*.bmp|JPEG 圖像文件|*.jpg| GIF圖像文件 | *.gif | PNG圖像文件 | *.png |其他格式(*.*) | *.* || "); CFileDialog dlg(FALSE, _T("bmp"), _T("iPaint1.bmp"), NULL, strFilter); if (dlg.DoModal() != IDOK) return; CString strFileName; CString strExtension; strFileName = dlg.m_ofn.lpstrFile; if (dlg.m_ofn.nFileExtension == 0) { switch (dlg.m_ofn.nFilterIndex) { case 1: strExtension = "bmp"; break; case 2: strExtension = "jpg"; break; case 3: strExtension = "gif"; break; case 4: strExtension = "png"; break; } strFileName = strFileName + "." + strExtension; } saveFilePath = strFileName; } else { showMsgTag = FALSE; } HRESULT hResult = image.Save(saveFilePath); if (FAILED(hResult)) { MessageBox(_T("保存圖像文件失敗!")); } else { if (showMsgTag) MessageBox(_T("文件保存成功!")); } image.Detach(); SelectObject(hdc, hOldMap); }
3.運行程序,導入Draw1
點擊導出圖片,選擇路徑和文件名稱,確定
4.提示文件保存成功!
5.雙擊打開這個文件iPaint1.bmp
6.可以看到成功打開(註意:這個文件不能用剛才自己寫的MFC程序自帶的打開來打開這個文件,因為打開的文件不是被序列化過的,因此打開會失敗!)
因此不能用這裡的打開按鈕喲
八、總結
1.MFC的按鈕消息需要熟練掌握
2.鼠標消息的使用也很重要
3.序列化保存和普通的導出圖片不是一碼事
4.對於抽象類的使用,尤其是畫各種圖是很重要的
5.MFC內置的庫函數需要熟練掌握(畫筆、刷子等等)
到此這篇關於vs2019 MFC實現office界面的畫圖小項目的文章就介紹到這瞭,更多相關vs2019 MFC 畫圖內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!