1,简单绘图
画直线
a,鼠标按下和抬起
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_myPoint = point; CView::OnLButtonDown(nFlags, point); }
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CClientDC dc(this); dc.MoveTo(m_myPoint); dc.LineTo(point); CView::OnLButtonUp(nFlags, point); }
b,CPaintDC 只能在OnPaint 中使用
CClientDC 在任何地方都可以使用
c,起点和终点
MoveTo 移动当前位置
LineTo 从当前位置到一点画直线,但不包括那个点
d,选择所属类 -> 右击 -> 添加变量,这种方法会自动帮你初始化变量
连续的线
鼠标移动事件
// CDrawView 消息处理程序 void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 m_myPoint = point; m_isPressed = true; CView::OnLButtonDown(nFlags, point); } void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 #if 0 CClientDC dc(this); dc.MoveTo(m_myPoint); dc.LineTo(point); #endif m_isPressed = false; CView::OnLButtonUp(nFlags, point); } void CDrawView::OnMouseMove(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (m_isPressed) { CClientDC dc(this); dc.MoveTo(m_myPoint); dc.LineTo(point); // 终点作为起点 m_myPoint = point; } CView::OnMouseMove(nFlags, point); }
void CDrawView::OnDraw(CDC* pDC) { CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 // 画圆 /* 参数: x1 指定椭圆外接矩形左上角的X逻辑坐标。 y1 指定椭圆外接矩形左上角的Y逻辑坐标。 x2 指定椭圆外接矩形右下角的X逻辑坐标。 y2 指定椭圆外接矩形右下角的Y逻辑坐标。 */ pDC->Ellipse(20,20,120,120); // 画刷 CBrush brush(RGB(255, 0, 0)); pDC->SelectObject(&brush); pDC->Ellipse(20, 20, 120, 120); }
2,位图的 使用
// CDrawView 绘图 void CDrawView::OnDraw(CDC* pDC) { CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 // 画圆 /* 参数: x1 指定椭圆外接矩形左上角的X逻辑坐标。 y1 指定椭圆外接矩形左上角的Y逻辑坐标。 x2 指定椭圆外接矩形右下角的X逻辑坐标。 y2 指定椭圆外接矩形右下角的Y逻辑坐标。 */ pDC->Ellipse(20,20,120,120); // 画刷 CBrush brush(RGB(255, 0, 0)); pDC->SelectObject(&brush); pDC->Ellipse(20, 20, 120, 120); // 定义一个位图对象 CBitmap bitmap; bitmap.LoadBitmapW(IDB_BITMAP1); CBrush brush2(&bitmap); pDC->SelectObject(&brush2); pDC->Ellipse(120,120,240,240); }
3,字体
// CDrawView 绘图 void CDrawView::OnDraw(CDC* pDC) { CDrawDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 // 画圆 /* 参数: x1 指定椭圆外接矩形左上角的X逻辑坐标。 y1 指定椭圆外接矩形左上角的Y逻辑坐标。 x2 指定椭圆外接矩形右下角的X逻辑坐标。 y2 指定椭圆外接矩形右下角的Y逻辑坐标。 */ pDC->Ellipse(20,20,120,120); // 画刷 CBrush brush(RGB(255, 0, 0)); pDC->SelectObject(&brush); pDC->Ellipse(20, 20, 120, 120); // 定义一个位图对象 CBitmap bitmap; bitmap.LoadBitmapW(IDB_BITMAP1); CBrush brush2(&bitmap); pDC->SelectObject(&brush2); pDC->Ellipse(120,120,240,240); CFont font; font.CreatePointFont(500, TEXT("楷体")); pDC->SelectObject(&font); pDC->TextOutW(100,100,TEXT("hello world")); }
4,文本编程
1,创建插入符CWnd::CreateSolidCaret()
a,创建CWnd::CreateSolidCaret()
b,显示CWnd::ShowCaret()
c,插入符的高度是根据字体的高度来确定
获取字体信息CDC::GetTextMetrics()
d,设置插入符的位置CWnd::SetCaretPos()
2,在字符消息处理函数中写字
a,写字CDC::TextOutW()
b,获取字符串的尺寸信息CDC::GetTextExtent()
c,截取字符串(CString)左边指定长度的字符 str = str.Left(str.GetLength() - 1);
int CEditorView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 // 获取字体信息 CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); // 继承与CWnd CreateSolidCaret(tm.tmAveCharWidth / 8,tm.tmHeight); // 创建插入符 ShowCaret(); return 0; }
写字
// CEditorView 消息处理程序 int CEditorView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 // 获取字体信息 CClientDC dc(this); TEXTMETRIC tm; dc.GetTextMetrics(&tm); // 继承与CWnd CreateSolidCaret(tm.tmAveCharWidth / 8,tm.tmHeight); // 创建插入符 ShowCaret(); return 0; } void CEditorView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCaretPos(point);//设置插入符的位置 m_point = point;// 保存点的坐标 m_str.Empty(); // 清空上一次的数据 CView::OnLButtonDown(nFlags, point); } // 点击键盘,启动调用 void CEditorView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CClientDC dc(this); // 换行和退格 if (nChar == VK_RETURN) { // 获取字体信息 TEXTMETRIC tm; dc.GetTextMetrics(&tm); m_point.y = m_point.y + tm.tmHeight; m_str.Empty(); } else if (nChar == VK_BACK) { COLORREF color = dc.GetBkColor();// 获取背景色 COLORREF oldColor = dc.SetTextColor(color);// 设置写字的颜色,返回以前的文本颜色的 RGB 值。 // 白色重写一次文本 dc.TextOutW(m_point.x, m_point.y, m_str); // 去掉最后一个字符 m_str = m_str.Left(m_str.GetLength() - 1); dc.SetTextColor(oldColor); } else { m_str += (TCHAR)nChar; } CSize size = dc.GetTextExtent(m_str); // 可以获取文本的宽度和长度 // 移动光标 CPoint pos; pos.x = m_point.x + size.cx; pos.y = m_point.y; SetCaretPos(pos); dc.TextOutW(m_point.x, m_point.y, m_str); CView::OnChar(nChar, nRepCnt, nFlags); }
5,菜单
1,菜单命令响应函数
a,弹式菜单,ID不可编辑,按下去,弹出一个菜单项
b,非弹式菜单,ID可编辑
c,菜单响应命令消息的路由(顺序)
void CMainFrame::OnTestDemo() { // TODO: 在此添加命令处理程序代码 MessageBox(TEXT("Frame")); }
void CTimerApp::OnTestDemo() { // TODO: 在此添加命令处理程序代码 AfxMessageBox(TEXT("app")); }
void CTimerDoc::OnTestDemo() { // TODO: 在此添加命令处理程序代码 AfxMessageBox(TEXT("doc")); }
void CTimerView::OnTestDemo() { // TODO: 在此添加命令处理程序代码 MessageBox(TEXT("view")); }
菜单命令响应路由
视图--文档-框架-应用程序
d,消息类型
非标准消息
命令消息WM_COMMAND:菜单处理函数选中;通告消息,点击按钮,处理函数CCmdTarget, CWnd子类能接收到非标准消息
标准消息 WM_XXXX ,属性->消息 CWnd子类才能接收到标准消息,CCmdTarget不能接收标准消息
CMainFrame::CMainFrame() { // TODO: 在此添加成员初始化代码 m_bAutoMenuEnable = false; }
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("未能创建工具栏 "); return -1; // 未能创建 } if (!m_wndStatusBar.Create(this)) { TRACE0("未能创建状态栏 "); return -1; // 未能创建 } m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); // TODO: 如果不需要可停靠工具栏,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); // 标志 // 获取菜单 //获取主菜单 CMenu *menu = GetMenu(); // 获取子菜单 CMenu *fileMenu = menu->GetSubMenu(0); // 标志新建 fileMenu->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED); fileMenu->CheckMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_CHECKED); // 设置默认项 加粗,一个菜单项只有一个默认菜单 // ID FALSE // 位置 TRUE fileMenu->SetDefaultItem(ID_FILE_SAVE, FALSE); fileMenu->SetDefaultItem(3, TRUE); // 变灰 // 需要把CFrameWnd::m_bAutoMenuEnable 设置 false fileMenu->EnableMenuItem(ID_FILE_PRINT, MF_BYCOMMAND | MF_DISABLED); // MF_GRAYED 与 MF_DISABLED等价 return 0; }
菜单更新机制
void CMainFrame::OnUpdateTest1A(CCmdUI *pCmdUI) { // TODO: 在此添加命令更新用户界面处理程序代码 if (m_update) { pCmdUI->Enable(TRUE); } else { pCmdUI->Enable(FALSE); } } void CMainFrame::OnTest1B() { // TODO: 在此添加命令处理程序代码 m_update = !m_update; }
CMainFrame::CMainFrame() { // TODO: 在此添加成员初始化代码 m_bAutoMenuEnable = false; }
// CMenuView 消息处理程序 void CMenuView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 // 获取主菜单 CMenu menu; menu.LoadMenuW(IDR_MENU1); // 获取子菜单 CMenu *subMenu = menu.GetSubMenu(1); ClientToScreen(&point); // 子菜单作为快捷菜单,右击菜单 subMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, point.x, point.y, this); CView::OnLButtonDown(nFlags, point); }
点击
6,定时器实现渐变色
字体渐变
1,定时器的使用
a,设置定时器:CWnd::SetTimer()
b,关闭定时器:CWnd::KillTimer()
c,定时器消息:WM_TIMER
2,视图类中的OnDraw()中,写字 CDC::TextOutW()
3,指定区域写字:CDC::DrawText()
4,让窗口失效,产生WM_PAINT ,间接调用OnDraw()函数:CWnd::Invalidate
// CTimerView 消息处理程序 int CTimerView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 // 设置定时器 // 1:定时器ID // 200:时间间隔,ms // NULL:使用系统默认的处理函数,每隔...毫秒,触发WM_TIMER SetTimer(1, 1000, NULL); return 0; } void CTimerView::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (nIDEvent == 1) { static int i = 0; i++; CString str; str.Format(TEXT("%d"), i); if (i >= 5) { KillTimer(1); } MessageBox(str); } CView::OnTimer(nIDEvent); }
// CTimerView 消息处理程序 int CTimerView::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 // 设置定时器 // 1:定时器ID // 200:时间间隔,ms // NULL:使用系统默认的处理函数,每隔...毫秒,触发WM_TIMER SetTimer(1, 200, NULL); return 0; } void CTimerView::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 if (nIDEvent == 1) { static int w = 0; w += 5; CString str = TEXT("在此添加消息处理程序代码和/或调用默认值"); CClientDC dc(this); CSize size = dc.GetTextExtent(str); // 如果宽度大于字符串的宽度,重新开始 if (w > size.cx) { w = 0; Invalidate();// 刷新窗口,相当于Qt里面的Update() } int x = 30; int y = 30; // 黑色写一次 dc.TextOutW(x, y, str); // 设置字体颜色 dc.SetTextColor(RGB(255, 0, 0)); CRect rect(x, y, x + w, y + size.cy); dc.DrawText(str, &rect, DT_LEFT); } CView::OnTimer(nIDEvent); }
7,动态图标
在资源视图中添加4个icon文件
在框架 .h 文件中添加
private: HICON icon[4];
构造函数中加载资源
// CMainFrame 构造/析构 CMainFrame::CMainFrame() { // TODO: 在此添加成员初始化代码 // 加载图片 // 获取应用程序 AfxGetApp() icon[0] = AfxGetApp()->LoadIconW(IDI_ICON1); icon[1] = AfxGetApp()->LoadIconW(IDI_ICON2); icon[2] = AfxGetApp()->LoadIconW(IDI_ICON3); icon[3] = AfxGetApp()->LoadIconW(IDI_ICON4); }
设置定时器
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CFrameWnd::OnCreate(lpCreateStruct) == -1) return -1; if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME)) { TRACE0("未能创建工具栏 "); return -1; // 未能创建 } if (!m_wndStatusBar.Create(this)) { TRACE0("未能创建状态栏 "); return -1; // 未能创建 } m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)); // TODO: 如果不需要可停靠工具栏,则删除这三行 m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); SetTimer(1, 200, NULL); return 0; }
定时器处理函数
void CMainFrame::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 static int i = 0; // 修改标题 SetClassLong(m_hWnd, GCL_HICON, (LONG)icon[i]); i++; if (i == 4) { i = 0; } CFrameWnd::OnTimer(nIDEvent); }
https://docs.microsoft.com/en-us/windows/desktop/api/winuser/nf-winuser-setclasslonga