一、实现的功能
1、程序可以画点、直线、矩形、椭圆
2、可以设置线宽、颜色、字体,可以看到线型示例
3、可以显示鼠标点的坐标,可以显示系统时间
4、在IDR_MAINFRAME字符串里面直接更改程序标题
5、画图文件的重绘。
6、程序用VS2008编写,个人觉得,VC6.0就像windowsXP
VS2008就像Win10,习惯了就好
二、实现的功能图片
三、实现的过程与代码
3.1、添加的菜单项
1、IDM_DOT 点 IDM_LINE 线 IDM_RECTANGLE 矩形 IDM_ELLIPSE 椭圆
IDM_COLOR颜色 IDM_FONT 字体 IDM_SETTING
3.2、添加的对话框资源
1、IDD_DLG_SETTING 设置 IDC_LINE_WIDTH 线宽(线型默认设置)IDC_SAMPLE 示例
3.3、添加的成员变量
1、CGraphicview
UNITm_nDrawType;//保存绘图选择,分别为1、2、3、4、初始化为0
CPointm_ptOrigin;//保存鼠标当前按下的点,初始化为0
COLORREFm_clr;//将当前所绘画的颜色保存下来,初始化为RGB(255,0,0)
UNITm_nLineWidth;//保存线宽值,然后在画图程序中使用,初始化为0
intm_nLineStyle;//保存线型,画图时使用,初始化为0
CFontm_font;//选择一种字体
CString m_strFontName;//保存所选字体的名称
CPtrArray m_ptrArray;//集合类的变量保存对象值
2、设置对话框增加了一个新类CSettingDlg
UNITm_nLineWidth;//保存对话框选择的线宽
int m_nLineStyle;//保存对话框选择的线型
3、图形保存与重绘
UINT m_nDrawType;//保存绘图选择
CPoint m_ptOrigin;//保存起点
CPoint m_ptEnd;//保存终点
COLORREFm_clr;//保存颜色
3.3代码的实现过程
1、所有变量在构造函数中初始化
CGraphicView::CGraphicView()
{
m_nDrawType=0;
m_ptOrigin=0;
m_nLineWidth=0;
m_nLineStyle=0;
m_clr=RGB(255,0,0);
m_strFontName="";
}
2、在CGraphicView类添加命令响应(添加事件处理程序)
同时设置变量UNIT m_nDrawType;//保存绘图选择,分别为1、2、3、4、表示
点、直线、矩形、椭圆
程序实现代码:
void CGraphicView::OnDot()
{
m_nDrawType=1;
}
void CGraphicView::OnLine()
{
m_nDrawType=2;
}
void CGraphicView::OnRectangle()
{
m_nDrawType=3;
}
void CGraphicView::OnEllipse()
{
m_nDrawType=4;
}
3、在CGraphicView类增加鼠标左键按下和鼠标左键松开两个消息响应函数
在左键按下的时候保存起点
在左键松开的时候,实现画图功能
程序代码实现如下:
void CGraphicView::OnLButtonDown(UINTnFlags, CPoint point)
{
m_ptOrigin=point;
CView::OnLButtonDown(nFlags, point);
}
void CGraphicView::OnLButtonUp(UINTnFlags, CPoint point)
{
CClientDCdc(this);
//选择画笔
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
dc.SelectObject(&pen);
// 透明画刷
CBrush*pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
dc.SelectObject(pBrush);
//画图实现
switch(m_nDrawType)
{
case 1:
dc.SetPixel(point,m_clr);
break;
case 2:
dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
break;
case 3:
dc.Rectangle(CRect(m_ptOrigin,point));
break;
case 4:
dc.Ellipse(CRect(m_ptOrigin,point));
break;
}
//为了使得图形保存和重绘,每次绘图操作结束后,就构造一个相应的CGraph对象,并将该对象的地址保//存到 m_ptrArray对象中,如果想要增加一个成员,可以用Add方法,来增加一个void指针所指向的对象
CGraph*pGraph=new CGraph(m_nDrawType,m_ptOrigin,point,m_clr);
m_ptrArray.Add(pGraph);
CView::OnLButtonUp(nFlags, point);
}
4、状态栏直接修改标题,程序改为CAD
IDR_MAINFRAME字符串资源直接修改,字符串2,没有指定就是无标题
本例中指定了CAD,可以直接修改
5、显示鼠标坐标,显示系统时间
程序左下角显示鼠标当前坐标
程序右下角显示系统当前时间
程序代码如下:
首先实现显示鼠标当前坐标,添加WM_MOUSEMOVE消息响应函数
void CGraphicView::OnMouseMove(UINTnFlags, CPoint point)
{
//添加坐标显示
//VC2005及更高版本默认使用Unicode字符集,CString里存的是宽字符,也就是wchar_t,而不再是//char。你可以这么写:
//*strDate.Format(_T("%4d-%2d-%2d"),st.wYear,st.wMonth,st.wDay);
//strTime.Format(_T("%4d:%2d:%2d"),st.wHour,st.wMinute,st.wSecond);
//以后写程序的时候,定义字符串变量,不要用char*,而用TCHAR*。所有字符串常量,不要直接用//"",而要用_T("")。举个例子:
//TCHAR*str = _T( "Hello, World" );
// MessageBox( _T( "Hello" )); */
//所以VC6.0和VS2008还是有一点区别,没有_T还是会报错
//实现的过程中,首先调用GetParent()得到视类窗口的指针,即框架窗口
//因为其返回值是CWnd指针,再强制转换为(CMainFrame*)
//在视类cpp增加框架类的头文件MainFrm.h
//修改成员变量m_wndStatusBar保护类型改为公有类型
CString str;
str.Format(_T("x=%d,y=%d"),point.x,point.y);
((CMainFrame*)GetParent())->m_wndStatusBar.SetWindowText(str);
CView::OnMouseMove(nFlags, point);
}
接着再显示系统当前时间
先在资源String Table中增加IDS_TIMER,,然后再将字符串资源ID加入到indicator数组中,在框架类cpp
static UINTindicators[] =
{
ID_SEPARATOR,
IDS_TIMER,//增加时间
ID_INDICATOR_CAPS,
ID_INDICATOR_NUM,
ID_INDICATOR_SCRL,
};
在OnCreate函数里面实现时间显示
int CMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct)
{
//系统自带程序代码,省略显示
//状态栏显示系统时间,让时间动起来,设置定时器,同时在ontimer消息响应函数中实现
SetTimer(1,1000,NULL);//设置定时器
CTime t=CTime::GetCurrentTime();
CString str=t.Format("%H:%M:%S");
CClientDC dc(this);
CSize sz=dc.GetTextExtent(str);
int index=0;
index=m_wndStatusBar.CommandToIndex(IDS_TIMER);
m_wndStatusBar.SetPaneInfo(index,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(index,str);
return 0;
}
在框架类增加消息响应函数WM_TIMER
void CMainFrame::OnTimer(UINT_PTRnIDEvent)
{
//让状态栏时间动起来
CTime t=CTime::GetCurrentTime();
CString str=t.Format("%H:%M:%S");
CClientDC dc(this);
CSize sz=dc.GetTextExtent(str);
m_wndStatusBar.SetPaneInfo(1,IDS_TIMER,SBPS_NORMAL,sz.cx);
m_wndStatusBar.SetPaneText(1,str);
CFrameWnd::OnTimer(nIDEvent);
}
6选择颜色
增加颜色的消息响应函数,实现代码如下
void CGraphicView::OnColor()
{
//颜色实现与保存
CColorDialog dlg;
//默认与颜色打开CC_RGBINIT,颜色初始保存,CC_FULLOPEN对话框全部打开
dlg.m_cc.Flags |=CC_RGBINIT | CC_FULLOPEN;
dlg.m_cc.rgbResult=m_clr;
if (IDOK==dlg.DoModal())
{
m_clr=dlg.m_cc.rgbResult;
}
}
8、选择字体,先增加两个成员变量
CFont m_font CString m_strFontName再增加消息响应函数
void CGraphicView::OnFont()
{
//实现字体打开
CFontDialog dlg;
if (IDOK==dlg.DoModal())
{
if(m_font.m_hObject)
m_font.DeleteObject();
m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);
m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;
Invalidate();
}
}
然后在OnDraw函数中将所选的字体输出到屏幕
void CGraphicView::OnDraw(CDC*pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//把所选择的字体显示在屏幕
CFont *pOldFont=pDC->SelectObject(&m_font);
pDC->TextOut(0,0,m_strFontName);
pDC->SelectObject(pOldFont);
if (!pDoc)
return;
}
9、设置线宽、线型、显示示例
设置IDD_DLG_SETING,增加一个新类CSettingDlg,然后为编辑框关联添加两个成员变量,保存当前选择的线宽、线型,三个复选框要选择Group选项
UINT m_nLineWidth
int m_nLineStyle
COLORREF m_clr
只是关联值,选择的时候要选value
在设置菜单处增加命令响应函数
设置IDM_SETTING,程序代码为:
void CGraphicView::OnSetting()
{
//线宽,线型实现与保存,还有颜色
CSettingDlg dlg;
dlg.m_nLineWidth=m_nLineWidth;
dlg.m_nLineStyle=m_nLineStyle;
dlg.m_clr=m_clr;
if(IDOK==dlg.DoModal())
{
m_nLineWidth=dlg.m_nLineWidth;
m_nLineStyle=dlg.m_nLineStyle;
m_clr=dlg.m_clr;
}
}同时,在CGraphicView中加上SettingDlg.h头文件
最后,将所选的线宽、线型的数据作为示例显示出来,示例IDC_SAMPLE
实现的代码为:
实现的原理为:对编辑框控件来说,当用户在其上面对文本进行改变时,它会向对话框发送EN_CHANGE的消息,当用户单击单选按钮时,该按钮会向对话框发送BN_CLICKED的消息。所以对这四个控件添加消息响应函数。
首先添加Invalidate()函数让窗口无效,当下一次发生WM_PAINT消息时,重绘窗口,在OnPaint函数中实现。
void CSettingDlg::OnEnChangeLineWidth()
{
Invalidate();
}
void CSettingDlg::OnBnClickedRadio1()
{
Invalidate();
}
void CSettingDlg::OnBnClickedRadio2()
{
Invalidate();
}
void CSettingDlg::OnBnClickedRadio3()
{
Invalidate();
}
void CSettingDlg::OnPaint()
{
CPaintDC dc(this); // device context forpainting
UpdateData();//必须用的
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
dc.SelectObject(&pen);
CRect rect;
GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);
ScreenToClient(&rect);//屏幕坐标转换为客户坐标
dc.MoveTo(rect.left+20,rect.top+rect.Height()/2);
dc.LineTo(rect.right-20,rect.top+rect.Height()/2);
}
10、图形的保存与重绘
需要建立一个新类,来保存绘制线型、起点、终点、颜色,类名CGraph,直接添加,无基类!
增加变量:
public:
CGraph(void);
CGraph::CGraph(UINT m_nDrawType,CPoint m_ptOrigin,CPointm_ptEnd,COLORREF m_clr);
~CGraph(void);
UINT m_nDrawType;
CPoint m_ptOrigin;
CPoint m_ptEnd;
COLORREF m_clr;
提供带参数的构造函数
CGraph::CGraph(UINTm_nDrawType,CPoint m_ptOrigin,CPoint m_ptEnd,COLORREF m_clr)
{
this->m_nDrawType=m_nDrawType;
this->m_ptOrigin=m_ptOrigin;
this->m_ptEnd=m_ptEnd;
this->m_clr=m_clr;
}
在CGraphicView中增加一个集合类的变量CPtrArraym_ptrArray,每次操作结束后,就构造一个CGraph的对象,并将该对象的地址保存在m_ptrArray对象中,见上面OnLButtonUp消息函数中代码
CGraph*pGraph=new CGraph(m_nDrawType,m_ptOrigin,point,m_clr);
m_ptrArray.Add(pGraph);
同时增加Graph.h头文件
最后在CGraphicView的OnDraw函数中,重绘出来
void CGraphicView::OnDraw(CDC*pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
//把图形全部重新绘制一遍
CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
pDC->SelectObject(pBrush);
int j=m_ptrArray.GetSize();
for (int i=0;i { CGraph * pGraph = (CGraph *)m_ptrArray.GetAt(i); CPen pen(m_nLineStyle,m_nLineWidth,pGraph->m_clr); CPen*pOldPen = pDC->SelectObject(&pen); switch(pGraph->m_nDrawType) { case 1: pDC->SetPixel(pGraph->m_ptEnd,m_clr); pDC->SelectObject(pOldPen); break; case 2: pDC->MoveTo(pGraph->m_ptOrigin); pDC->LineTo(pGraph->m_ptEnd); pDC->SelectObject(pOldPen); break; case 3: pDC->Rectangle(CRect(pGraph->m_ptOrigin,pGraph->m_ptEnd)); pDC->SelectObject(pOldPen); break; case 4: pDC->Ellipse(CRect(pGraph->m_ptOrigin,pGraph->m_ptEnd)); pDC->SelectObject(pOldPen); break; } } if (!pDoc) return; } 全部完成!