1、 创建“图形”、“颜色”、“线的类型”、“线宽度”子菜单。
(1) 在新建的工程中“ResourceView”中打开Menu选项,在空白中添加这几项。
(2) 在“图形”下拉菜单中依次添加“椭圆”、“矩形”、“曲线”,并且依次设置ID分别为:ID_ELLIPSE,ID_RECTANGLE,ID_CURVES。
(3) 在“颜色”下拉菜单中依次添加“红色”,“绿色”,“蓝色”,“白色”和“黑色”。并设置其ID分别为ID_COLORRED,ID_COLORGREEN,ID_COLORBLUE,ID_COLORBLACK,ID_COLORWHITE。
(4) 在“线的类型”下拉菜单中依次添加“实线”和“虚线”。其ID分别是ID_LINESOLID,ID_LINEDOT
(5) 在“线宽度”下拉菜单中创建“1”和“2”,其ID分别设为ID_LINEWIDE1,ID_LINEWIDE2。
编译,运行后效果如下:
2、 响应菜单栏中的“图形”下拉子菜单的消息
响应椭圆(ID_ELLIPSE)矩形(ID_RECTANGLE)
(1)、首先在view类中添加变量
BOOL m_ISPointup; //鼠标左键弹起
BOOL m_ISPointdown; //鼠标左键按下
CPoint m_pointup; //鼠标左键弹起的位置
CPoint m_pointdown; //鼠标左键按下的位置
BOOL m_ClickRectangle; //判断是否画矩形
BOOL m_ClickEllipse; //判断是否画椭圆
Int flage;//菜单选项被标记的标志
(2)、在view类中对这些变量初始化
m_pointdown = 0; //原点
m_pointup = 0;
m_ISPointup = FALSE; //未按下
m_ISPointdown = FALSE;
flag = 0;
(3)、响应ID_ELLIPSE和ID_RECTANGLE的command和update消息
void CYangwei20090810229View::OnEllipse()
{
// TODO: Add your command handler code here
flag++;
m_ClickEllipse = TRUE;
m_ClickRectangle = FALSE;
m_ClickCurves = FALSE;
}
void CYangwei20090810229View::OnRectangle()
{
// TODO: Add your command handler code here
flag++;
m_ClickEllipse = FALSE;
m_ClickRectangle = TRUE;
m_ClickCurves = FALSE;
}
void CYangwei20090810229View::OnUpdateEllipse(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(flag%2==0);
if(255 == flag)
{
flag = 1;
}
void CYangwei20090810229View::OnUpdateRectangle(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->SetCheck(flag%2==1);
}
(3)、响应WM_LBUTTONDOWN消息,此时记下该点位置,并表示按下状态,添加代码:
void CYangwei20090810229View::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_pointdown = point;
m_ISPointdown = TRUE;
m_ISPointup = FALSE;
CView::OnLButtonDown(nFlags, point);
}
(4)、响应WM_LBUTTONUP消息记下此点位置,虽然在此程序中未用到改点。
void CYangwei20090810229View::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_pointup = point;
CDC *pDC=GetDC();
CBrush *pnew = CBrush::FromHandle((HBRUSH)GetStockObject(HOLLOW_BRUSH));//获得空画刷
CBrush *pold = pDC->SelectObject(pnew); //选择新建画刷
CPen newpen(m_penstyle,m_linewide,RGB(m_pen.red,m_pen.green,m_pen.blue));//创建自定义的画笔,这里的m_pen是自己写的结构
CPen *poldpen = pDC->SelectObject(&newpen); //选择自定义的画笔
if(m_ClickEllipse)
{
pDC->Ellipse(m_pointdown.x,m_pointdown.y,point.x,point.y);
}
if(m_ClickRectangle)
{
pDC->Rectangle(m_pointdown.x,m_pointdown.y,point.x,point.y);
}
pDC->SelectObject(poldpen);
pDC->SelectObject(pold);
m_ISPointup = TRUE;
m_ISPointdown = FALSE;
CView::OnLButtonUp(nFlags, point);
}
响应曲线(ID_CURVES)
(1)、响应ID_CURVES的command消息
void CYangwei20090810229View::OnCurves()
{
// TODO: Add your command handler code here
m_ClickCurves = TRUE; //代表曲线被选择
m_ClickEllipse = FALSE;
m_ClickRectangle = FALSE;
}
响应WM_MOUSEMOVE消息
void CYangwei20090810229View::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_ISPointdown && m_ClickCurves)
{
CClientDC dc(this);
CPen pen(m_penstyle,m_linewide,RGB(m_pen.red,m_pen.green,m_pen.blue));
CPen *pold = dc.SelectObject(&pen);
dc.MoveTo(m_pointdown);
dc.LineTo(point);
m_pointdown = point;
dc.SelectObject(pold);
}
CView::OnMouseMove(nFlags, point);
}
对于颜色菜单,首先在view类中的头文件中定义一个结构体
struct myColor
{
int red;//红色
int green;//绿色
int blue;//蓝色
};
向view类中添加myColor m_pen; //画笔的颜色
初始化黑色
m_pen.red = 0;
m_pen.green = 0;
m_pen.blue = 0;
响应红色ID_COLORRED的command消息
void CYangwei20090810229View::OnColorred()
{
// TODO: Add your command handler code here
m_pen.red = 255;
m_pen.green = 0;
m_pen.blue = 0;
}
其他的颜色道理一样,只要知道各种颜色的三原色各自的值并且赋给他们即可,不再详述
对于线的类型:
在view类中添加变量m_penstyle并在构造函数中初始化
m_penstyle =PS_SOLID;//线类型实线
然后响应实线ID_LINESOLID的command消息
void CYangwei20090810229View::OnLinesolid()
{
// TODO: Add your command handler code here
m_penstyle = PS_SOLID;
}
对于虚线响应ID_LINEDOT消息
void CYangwei20090810229View::OnLinedot()
{
// TODO: Add your command handler code here
m_penstyle = PS_DOT;
}
对于线宽 1,2分别响应ID_LINEWIDE1和ID_LINEWIDE2的command消息
void CYangwei20090810229View::OnLinewide1()
{
// TODO: Add your command handler code here
m_linewide = 1;//线宽1
}
void CYangwei20090810229View::OnLinewide2()
{
// TODO: Add your command handler code here
m_linewide = 2;//线宽2
}
3、 响应工具栏的的各种图形消息
如椭圆
在ResourceView页面中,双击Toolbar文件夹,可以看到有一个ID位ID_MAINFRAME的工具栏。双击ID_MAINFRAME工具栏,在工具栏编辑框中出现如下图所示的工具栏。
在工具栏的最右边有一空白按钮,双击该按钮,弹出对话框如下图,其中ID选择ID_ELLIPSE,即“椭圆”按钮。该按钮显示在编辑窗口中,可以通过Graphics和Colors工具箱及鼠标画自己的图标。(矩形工具栏图标同椭圆方法)
其他图形一样。
4、 响应右击菜单消息
a) 在工作区的ResourceView选项卡中,右击Menu文件夹,在弹出菜单中选择插入菜单便可创建一个新的菜单资源,其ID为IDR_MENU1。右击IDR_MENU1,在弹出菜单中选择属性,修改其ID为IDR_POPMENU。双击IDR_POPMENU资源进入编辑对话框,对弹出式菜单进行编辑,,完成后的菜单资源如图:
b) 添加代码,实现鼠标右键单击时显示弹出式菜单。在查看菜单项中选择建立类向导来添加右键单击弹出式菜单WM_CONTEXTMENU及消息处理函数,这时MFC会发现创建了一个新资源,将询问是否创建一个新类,取消后,弹出下图对话框,选择ID为CExyangwei20090810229View,Messages为WM_CONTEXTMENU,双击该消息或单击Add Function按钮,将为该消息添加默认处理函数,单击Edit Code按钮进入OnContextMenu()函数,对其进行编辑。
void CYangwei20090810229View::OnContextMenu(CWnd*, CPoint point)
{
// CG: This block was added by the Pop-up Menu component
{
if (point.x == -1 && point.y == -1){
//keystroke invocation
CRect rect;
GetClientRect(rect);
ClientToScreen(rect);
point = rect.TopLeft();
point.Offset(5, 5);
}
CMenu menu;
VERIFY(menu.LoadMenu(CG_IDR_POPUP_YANGWEI20090810229_VIEW));
CMenu* pPopup = menu.GetSubMenu(0);
ASSERT(pPopup != NULL);
CWnd* pWndPopupOwner = this;
while (pWndPopupOwner->GetStyle() & WS_CHILD)
pWndPopupOwner = pWndPopupOwner->GetParent();
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_RIGHTBUTTON, point.x, point.y,
pWndPopupOwner);
}
}
其中响应画各种图形的方法与工具栏中的做法差不多
对于清空消息ID_UPDATE
void CYangwei20090810229View::OnUpdate()
{
// TODO: Add your command handler code here
Invalidate();
UpdateWindow();
}
5、 下面美化状态栏
(1)、将状态栏的提示器改成自己的东西,在这里我改成了作者和日期
即2011-4-2 made by Veiker.其实就是在ResourseView中的StringTable中找到
AFX_IDS_IDLEMESSAGE 将其属性改下
(2)、修改状态栏中的提示器
让状态栏显示鼠标箭头的位置,CTRL键是否按下,时间、进度条
A、 在Stringtable中添加对应的ID
B、 在Frame类构造函数中的indicators数组中添加ID(对应ID如下显示)
static UINT indicators[] =
{
ID_SEPARATOR, // status line indicator
ID_XY, //显示鼠标位置
ID_INDICATOR_CTRL,//显示CTRL键是否按下
ID_INDICATOR_TIME,//显示时间
ID_INDICATOR_PROG,//显示进度条
ID_INDICATOR_NUM,//显示数字
};
显示鼠标位置:
响应WM_MOUSEMOVE 由于前面响应过这里只要向里面添加代码
CString str;
str.Format("x=%d,y=%d",point.x,point.y);
CMainFrame*pMainFrame=(CMainFrame*)(AfxGetApp()->GetMainWnd());
pMainFrame->m_wndStatusBar.SetPaneText(1,str);
注意:包含MainFrm.h
显示CTRL键是否按下在View类中的消息注释宏中添加
ON_UPDATE_COMMAND_UI(ID_INDICATOR_CTRL,OnUpdateKeyCtrl)
然后响应函数
void CYangwei20090810229View::OnUpdateKeyCtrl(CCmdUI* pCmdUI)
{
pCmdUI->Enable(::GetKeyState(VK_CONTROL)<0); //更新状态指示器
}
显示时间
在frame类中OnCreate()中添加
SetTimer(1,1000,NULL);
CTime time = CTime::GetCurrentTime();
CString str = time.Format("%H:%M:%S");
m_wndStatusBar.SetPaneText(3,str);
响应WM_TIMER消息
void CMainFrame::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CTime time = CTime::GetCurrentTime();
CString str = time.Format("%H:%M:%S");
m_wndStatusBar.SetPaneText(3,str);
CFrameWnd::OnTimer(nIDEvent);
}
显示进度条:
在frame类中添加变量CProgressCtrl m_Process;
响应WM_PAINT消息
void CMainFrame::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
CRect rect;
m_wndStatusBar.GetItemRect(4,&rect);
if(m_Process.m_hWnd)
{
m_Process.SetWindowPos(NULL,rect.left,rect.top,rect.Width(),rect.Height(),SWP_NOZORDER);
}
else{
m_Process.Create(WS_CHILD|WS_VISIBLE,rect,&m_wndStatusBar,111);
}
// Do not call CFrameWnd::OnPaint() for painting messages
}
向OnTimer()中添加m_Process.StepIt();
三、 运行后总体效果:
源代码:见附件