1.简单绘图应用
1.1 画一条直线
1.1.1 鼠标按下和抬起
1.1.2 创建画家对象CClientDc;例如 CClientDc dc(this);dc.xxxx
1.1.3 起点:CDC::MoveTo 和终点:CDC::LineTo
1.1.4 选中所属类->右击->添加变量
1.2 画刷、画笔的使用
1.2.1 定义画家
1.2.2 定义画刷(画笔)CBrush,CPen
1.2.3 把画笔交给画家,用CDC::SelectObject
1.2.4 画刷:单色,样式,位图
1.3 写字,CFont的使用
1.4 位图加载
// CMy02DrawView 绘图
void CMy02DrawView::OnDraw(CDC* pDC)
{
CMy02DrawDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
//1.2.1 定义画家
// 1.2.2 定义画刷(画笔)CBrush,CPen
// 1.2.3 把画笔交给画家,用CDC::SelectObject
//ps_dash:虚线 1:线宽
CPen pen(PS_DASH, 1, RGB(255, 0, 0));
//pDC->SelectObject(&pen);
//返回设置前状态
CPen *oldPen = pDC->SelectObject(&pen);
pDC->MoveTo(10, 10);
pDC->LineTo(120, 10);
//恢复原来的状态
pDC->SelectObject(oldPen);
//画圆
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;
//500:字体宽度,0.1倍
// TEXT("楷体"):字体风格
font.CreatePointFont(500, TEXT("楷体"));
//使用字体,字体交给画家
pDC->SelectObject(&font);
pDC->TextOutW(100, 100, TEXT("hello 12"));
// TODO: 在此处为本机数据添加绘制代码
}
// CMy02DrawView 消息处理程序
void CMy02DrawView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_myPoint = point;//保存点击的坐标
m_isPress = true;
CView::OnLButtonDown(nFlags, point);
}
// 鼠标抬起
void CMy02DrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
#if 0
//创建画家 指定绘图设备
CClientDC dc(this);
dc.MoveTo(m_myPoint);
dc.LineTo(point);
#endif
m_isPress = false;
CView::OnLButtonUp(nFlags, point);
}
void CMy02DrawView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if (m_isPress == true)
{
//创建画家 指定绘图设备
CClientDC dc(this);
dc.MoveTo(m_myPoint);
dc.LineTo(point);
//终点作为起点
m_myPoint = point;
}
CView::OnMouseMove(nFlags, point);
}
2.文本编辑器
2.1 创建插入符CWnd::CreateSolidCaret ()-----视图创建好之后才创建插入符,放在OnCreate()中
2.1.1 创建CWnd::CreateSolidCaret ()
2.1.2 显示CWnd::ShowCaret ()
2.1.3 插入符的高度是根据字体的高度来确定
获取字体信息CDC::GetTextMetrics ()
2.1.4 设置插入符位置Cwnd::SetCaretPos ()----没有用对象调,是继承CWnd的,直接用
//窗口创建后自动调用
int CMy03EditorView::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;
}
2.2 在字符消息处理函数中写字
2.2.1 写字CDC::TextOutW ()
2.2.2 获取字符串的尺寸信息CDC::GetTextExtent ()
2.2.3 截取字符串(CString)左边指定长度的字符str = str. Left (str .GetIength() - 1) ;
void CMy03EditorView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
SetCaretPos(point);//移动插入符
//保存点击坐标
m_point = point;
m_str = TEXT("");//将之前的所敲入的字符清空
m_str.Empty();
CView::OnLButtonDown(nFlags, point);
}
//点击键盘,启动调用
void CMy03EditorView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
if (nChar==VK_RETURN)//按下换行
{
m_str.Empty();
//获取字体信息
CClientDC dc(this);
TEXTMETRIC tm;//字体信息结构体
dc.GetTextMetrics(&tm);
m_point.y = m_point.y +tm.tmHeight;
}
else if (nChar == VK_BACK)//按下退格
{
//获取背景图
COLORREF color = dc.GetBkColor();
//设置写字的颜色
COLORREF oldColor = dc.SetTextColor(color);
//白色重写一次
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.GetOutputTextExtent(m_str);//获取敲入的字符串长度
int x = m_point.x + size.cx;
int y = m_point.y;
SetCaretPos(CPoint(x, y));
dc.TextOutW(m_point.x, m_point.y, m_str);
CView::OnChar(nChar, nRepCnt, nFlags);
}
3.字体渐变
3.1 定时器的使用(重点)
3.1.1 设置定时器: CWnd::SetTimer ()
3.1.2 关闭定时器: CWnd::KillTimer ()
3.1.3 定时器消息: WM_ TIMER
3.2 视图类中的OnDraw()中,写字CDC::TextOutw ()
3.3 指定区域写字:CDC::DrawText ()
3.4 让窗口失效,产生WM_ PAINT,间接调用OnDraw()函数: CWnd::Invalida
int CMy04TimeoutView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
//设置定时器; 1:定时器ID 500:时间间隔,单位毫秒 NULL: 使用系统默认处理函数,每隔500毫秒触发该信号
SetTimer(1,220,NULL);
return 0;
}
void CMy04TimeoutView::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();
}
int x = 30;
int y = 30;
CRect rect(x, y,x+w,y+size.cy);
//黑色写一次
dc.TextOutW(x, y, str);
//设置字体颜色
dc.SetTextColor(RGB(255, 0, 0));
dc.DrawText(str, &rect, DT_LEFT);
}
CView::OnTimer(nIDEvent);
}
4.菜单的相关操作
4.1 菜单的命令响应函数
4.1.1 弹式菜单,ID不可编辑,按下去,弹出一一个菜单项
4.1.2 非弹式菜单,ID可编辑
4.1.3 菜单响应命令消息的路由(顺序)
4.1.4 消息类型:
非标准消息
WM_ COMMAND,命令消息、通告消息,CCmdTarget、 CWnd子类子类能接收到非标准消息
WM XXXX ,标准消息,CWnd子类才能接收到标准消息
命令消息WM_COMMAND: 菜单处理函数选中
标准消息:在属性->消息中 设定
通告消息:点击按钮,运行处理函数
CWnd可以接收任何消息,CCmdTarget不能接收标准消息
4.2 菜单相关静态操作
4.2.1 在框架类中进行相应操作,在OnCreate()中实现
4.2.2 获取菜单栏: CWnd::GetMenu()///如果要在View中使用应该先创建菜单项,通过菜单ID加载菜单
4.2.3 获取菜单栏中的子菜单:CMenu::GetSubMenu
4.2.3.1 标志菜单: CMenu::CheckMenuItem
ME_ BYPOSITION:通过位置
ME RVCOMMAND:通过ID
4.2.3.2 设置默认菜单: CMenu::SetDe faultItem,
注意:一个菜单项只能设置一一个默认菜单
4.2.3.3 禁用菜单: CMenu::EnableMenultem
注意:需要把CFrameWnd: :m bAutoMenuEnable成员变量设置为FALSE
4.2.3.4 分隔线也算一个
4.2.4 移除菜单CWnd::SetMenu
SetMenu (NULL) ;
4.2.5 装载菜单
4.2.5.1 创建菜单CMenu::LoadMenu
4.2.5.2 设置菜单CWnd::SetMenu
4.2.5.3 从CMenu对象中分离windows菜单CMenu::Detach
4.2.6 菜单命令更新机制(要掌握)
4.2.7 快捷菜单,弹出菜单(一定要新建菜单,不能使用框架类的主菜单)
由于鼠标点击的区域是在视图区域,所以需要在视图类中处理
4.2.7.1 处理鼠标右击事件WM RBUTTONDOWN
4.2.7.2 获取所需的子菜单
4.2.7.3 弹出菜单项CMenu::TrackPopupMenu
4.2.7.4 客户区坐标转屏幕坐标: CWnd::ClientToScreen
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("未能创建工具栏\n");
return -1; // 未能创建
}
if (!m_wndStatusBar.Create(this))
{
TRACE0("未能创建状态栏\n");
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);
//标志“新建”,第一个参数由MF_BYPOSITION 决定
fileMenu->CheckMenuItem(0, MF_BYPOSITION | MF_CHECKED);
//标志“新建”,第一个参数由MF_BYCOMMAND决定
fileMenu->CheckMenuItem(ID_FILE_OPEN, MF_BYCOMMAND | MF_CHECKED);
//设置默认项, 加粗,一个菜单只有一个默认菜单
//flase:用的是ID
//true:用的是位置
fileMenu->SetDefaultItem(ID_FILE_SAVE, false);
/*fileMenu->SetDefaultItem(2, true);*/
//变灰操作
//需要把CFrameWnd::m_bAutoMenuEnable 设置 false
fileMenu->EnableMenuItem(5, MF_BYPOSITION | MF_DISABLED|MF_GRAYED);
//移除菜单项
SetMenu(NULL);
//加载菜单
CMenu menu2;
//加载菜单
menu2.LoadMenuW(IDR_MENU1);
SetMenu(&menu2);
//分离 ,
menu2.Detach();
return 0;
}
// CMy05View 消息处理程序
//视图鼠标左键按下
void CMy05View::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获取主菜单
//CMenu *menu = GetMenu();
//创建菜单项
CMenu menu;
menu.LoadMenuW(IDR_MENU1);
//获取子菜单
CMenu *subMenu = menu.GetSubMenu(0);
ClientToScreen(&point);
//子菜单作为左击菜单--快捷菜单
subMenu->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON,
point.x, point.y, this);
CView::OnLButtonDown(nFlags, point);
}
4.3 菜单相关动态操作
4.3.1 创建空菜单CMenu::CreateMenu
4.3.2 追加弹式菜单CMenu::AppendMenu(MF_ POPUP, )
每个菜单都有-一个菜单句柄: CMenu::m_hMenu
重画菜单条: CWnd::DrawMenuBar
4.3.3 追加普通菜单 CMenu::AppendMenu (MF_ STRING, )
4.3.4 插入菜单 CMenu::InsertMenu
4.3.5 删除菜单 CMenu::DeleteMenu
5.动态图标
5.1 定时器: CWnd::SetTimer
5.1.1 定时器信号: WM TIMER
5.1.2 设置定时器应该放在OnCreate()
5.2 加载自定义图标(WinAPI) : LoadIcon ()///或者用
5.2.1 将资源ID转换为字符串 MAKEINTRESOURCE ()
5.2.2 获取应用程序实例:
AfxGetInstanceHandle ()
AfxGetApp()->m_hInstance
5.3 设置图标(WinAPI) SetClassLong ()
窗口句柄: CWnd::m_hWnd
// CMainFrame 消息处理程序
void CMainFrame::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
static int i = 0;
//修改窗口左上角图标
SetClassLong(m_hWnd, GCLP_HICON, (LONG)icon[i]);
i++;
if (i == 2)
{
i = 0;
}
CFrameWnd::OnTimer(nIDEvent);
}