图形的绘制,如何使用自定义画笔(颜色,线宽,线形)。如何为程序中添加选项菜单和选项设置对话框,如何使用标准颜色对话框,如何使用字体对话框,在选项对话框中实现预览功能。实现选项对话框和窗口类中的数据交换。如何改变对话框和控件的背景色,如何改变控件的文本颜色,对按钮控件的特殊处理。如何在窗口中显示一幅位图。 1.使用自定义画笔画图 建立4个菜单项IDM_DOT LINE RECTANGLE ELLIPSE的,然后分别添加命令响应函数,然后增加一个private的私有成员变量m_nDrawType,在view构造函数中初始化为0;然后在菜单项的命令响应函数中分别将m_nDrawType赋值为1,2,3,4。 然后在view中添加LButtonUp和LButtonDown消息处理,再添加成员变量m_ptOrigin CPoint private记录鼠标按下的坐标,然后在LButtonDown中记录m_ptOrigin,在LButtonUp中用switch(m_nDrawType)作图。 选择dot的时候: CDC::SetPixel //画点 COLORREF SetPixel( int x, int y, COLORREF crColor ); COLORREF SetPixel( POINT point, COLORREF crColor ); 选择rectangle的时候: CDC::Rectangle //画矩形 BOOL Rectangle( int x1, int y1, int x2, int y2 ); BOOL Rectangle( LPCRECT lpRect ); //用CRect构造的时候,它自己会强制转换成LPCRECT CClientDC dc(this); switch(m_nDrawType) { case 1: dc.SetPixel(point,RGB(0,255,0)); //不知为何画点有问题 break; case 2: dc.MoveTo(m_ptOrigin); dc.LineTo(point); break; case 3: dc.Rectangle(CRect(m_ptOrigin,point)); //CRect可强制转换成LPRECT的 break; case 4: dc.Ellipse(CRect(m_ptOrigin,point)); break; } 在前面用这个改变画笔颜色 CPen pen(PS_SOLID,1,RGB(255,0,0)); dc.SelectObject(pen); 使画图透明: CBrush *pBrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH)); dc.SelectObject(pBrush); 2.设置对话框: 先插入一个对话框资源,IDD_DLG_SETTING setting,改一下字体 再插入一个静态文本框“线宽”和一个编辑框IDC_LINE_WIDTH,然后对编辑框点类向导,然后提示创建一个新的类,CSettingDlg,然后给编辑框关联一个成员变量m_nLineWidth UINT 增加一个菜单项--‘设置’ IDM_SETTING,增加一个命令响应view类的:然后建立CSettingDlg类(要包含头文件) CSettingDlg dlg; dlg.DoModal(); 然后修改一下,来接收线宽,增加一个成员变量UINT nLineWidth private,构造函数中初始化为0。然后在设置菜单的响应函数OnSetting中: CSettingDlg dlg; dlg.m_nLineWidth=m_nLineWidth; //读取数据 if(IDOK==dlg.DoModal()) { m_nLineWidth=dlg.m_nLineWidth; } 还要修改上面的CPen pen(PS_SOLID,1,RGB(255,0,0));为CPen pen(PS_SOLID,m_nLineWidth,RGB(255,0,0)); 设置线型,增加一个组框,标题为“线型”,再添加3个单选框(radio),标题分别为:实线,虚线,点线。在第一个单选框上设置为组(group,则可共用一个成员变量)。关联一个变量:m_nLineStyle int 然后在View类也增加一个m_nLineStyle int,在构造函数中初始化为0。 然后在dlg中设置为:m_nLineWidth=dlg.m_nLineWidth; 而因为pen对象的styles,所以注意顺序: #define PS_SOLID 0 #define PS_DASH 1 /* ------- */ #define PS_DOT 2 /* ....... */ 把pen的PS_SOLID改为m_nLineStyle 3.创建颜色对话框 mfc中有个CColorDialog类,可创建颜色对话框 CColorDialog( COLORREF clrInit = 0, DWORD dwFlags = 0, CWnd* pParentWnd = NULL ); 构造函数:clrInit默认为RGB(0,0,0)黑色;样式标志;dialog的父窗口 需要先产生一个对象,然后再用DoModal方法显示出来。 在作图菜单中增加一个颜色菜单项,IDM_COLOR 颜色,建立命令响应。 CColorDialog dlg; dlg.DoModal(); 类中有个成员变量m_cc,是CHOOSECOLOR类型的 typedef struct { // cc DWORD lStructSize; HWND hwndOwner; HWND hInstance; COLORREF rgbResult; //保存了选择的颜色 COLORREF* lpCustColors; DWORD Flags; LPARAM lCustData; LPCCHOOKPROC lpfnHook; LPCTSTR lpTemplateName; } CHOOSECOLOR; 为了保存颜色,在view类增加一个成员变量COLORREF m_clr private;在view的构造函数中初始化为红色RGB(255,0,0)。然后在颜色菜单的响应函数中,保存选择的颜色rgbResult到m_clr中去。再在LButtonUp中将RGB(255,0,0)改为m_clr //CTRL+TAB可在两个窗口间切换 CColorDialog dlg; dlg.m_cc.rgbResult=m_clr; if(IDOK==dlg.DoModal()) { m_clr=dlg.m_cc.rgbResult; } 但这样并不能初始化它的颜色,需要加: dlg.m_cc.Flags|=CC_RGBINIT; //要设置FLAG成CC_RGBINIT才行,这里若不用|的话,就会出错 dlg.m_cc.rgbResult=m_clr; 还可以在flags中设置CC_FULLOPEN使颜色对话框完全打开。 4.设置字体CFontDialog CFontDialog( LPLOGFONT lplfInitial = NULL, DWORD dwFlags = CF_EFFECTS | CF_SCREENFONTS, CDC* pdcPrinter = NULL, CWnd* pParentWnd = NULL ); // LOGFONT的指针;样式标志;打印设备指针;父窗口 再增加一个字体菜单项IDM_FONT,添加view的命令响应。构造对象然DoModal即可显示。 它有一个成员m_cf,是CHOOSEFONT类型的: typedef struct { // cf DWORD lStructSize; HWND hwndOwner; HDC hDC; LPLOGFONT lpLogFont; //创建CFont对象 INT iPointSize; DWORD Flags; DWORD rgbColors; LPARAM lCustData; LPCFHOOKPROC lpfnHook; LPCTSTR lpTemplateName; HINSTANCE hInstance; LPTSTR lpszStyle; WORD nFontType; WORD ___MISSING_ALIGNMENT__; INT nSizeMin; INT nSizeMax; } CHOOSEFONT; 保存字体,在view类增加一个CFont m_Font private,CString m_strFontName private(初始为空) CFontDialog dlg; if(IDOK==dlg.DoModal()) { m_Font.CreateFontIndirect(dlg.m_cf.lpLogFont); m_strFontName=dlg.m_cf.lpLogFont->lfFaceName; Invalidate(); //使窗口无效,引发OnDraw函数 } 在OnDraw函数中编写: CFont *pOldFont=pDC->SelectObject(&m_Font); pDC->TextOut(0,0,m_strFontName); pDC->SelectObject(pOldFont); 但这样在选择第二个字体的时候,程序会出错。要先判断m_Font是否已经关联对象,关联了就删除,然后再关联其他的字体资源对象。 if(m_Font.m_hObject) m_Font.DeleteObject(); 5.画线的示例 增加一个组框:IDC_SAMPLE 示例。 然后在编辑框(EN_CHANGE)和单选按钮(BN_CLICKED)的命令响应函数中写Invalidate调用OnPaint(WM_PAINT)。 如:void CSettingDlg::OnRadio3() { Invalidate(); } 然后给CSettingDlg添加消息处理:WM_PAINT。 UpdateData(); //需要交换数据,m_nLineWidth那些 CPen pen(m_nLineStyle,m_nLineWidth,RGB(255,0,0)); dc.SelectObject(&pen); CRect rect; GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect); //而这样坐标有问题,因为GetWindowRect获取的是屏幕左边 ScreenToClient(&rect);//需要这个转换为客户区坐标 dc.MoveTo(rect.left+20,rect.top+rect.Height()/2); dc.LineTo(rect.right-20,rect.top+rect.Height()/2); 再在CSettingDlg添加成员变量,m_clr COLORREF public,初始化为红色。然后在view类的OnSetting函数中将m_clr赋值给dlg.m_clr.然后再将上面的pen中的RGB改为m_clr即可。 6.设置背景色 CWnd::OnCtlColor afx_msg HBRUSH OnCtlColor( CDC* pDC, CWnd* pWnd, UINT nCtlColor ); 给CSettingDlg增加一个WM_CTLCOLOR消息处理,再增加一个成员变量CBrush m_brush private,在CSettingDlg中初始化:m_brush.CreateSolidBrush(RGB(0,0,255)); 再在OnCtlColor里返回:return m_brush; 用CWnd::GetDlgCtrlID //获取对话框控件ID(或者子窗口ID) int GetDlgCtrlID( ) const; 将线性的属性改为IDC_LINE_STYLE,然后在OnCtlColor中: HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) { HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor); // TODO: Change any attributes of the DC here if(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE) //判断调用这个函数的 是否是IDC_LINE_STYLE { pDC->SetTextColor(RGB(255,0,0)); //设置控件文本颜色 return m_brush; //设置控件背景颜色 } // TODO: Return a different brush if the default is not desired //return m_brush; return hbr; //其他默认 } CDC::SetBkMode int SetBkMode( int nBkMode ); //nBkMode有:OPAQUE默认/TRANSPARENT透明 设置为透明后,背景就可以铺满整个控件(默认是不铺满的) pDC->SetBkMode(TRANSPARENT); //设置控件背景透明 再设置线宽编辑框: if(pWnd->GetDlgCtrlID()==IDC_LINE_WIDTH) { pDC->SetTextColor(RGB(255,0,0)); //pDC->SetBkMode(TRANSPARENT); //sun说不行,但win7上可以的&&他说需要SetBkMode pDC->SetBkColor(RGB(0,0,255)); //这样就可以铺满控件了 return m_brush; } 增加一个静态文本框 IDC_TEXT 程序员。给CSettingDlg添加一个成员变量:CFont m_font private.构造函数中构造一个: m_Font.CreatePointFont(200,"华文行楷"); 再在OnCtlColor中修改背景: if(pWnd->GetDlgCtrlID()==IDC_TEXT) { pDC->SelectObject(&m_Font); } /*if(pWnd->GetDlgCtrlID()==IDOK) { return m_brush; //但这样改变不了确定按钮的文本 }*/ 新建一个类CTestBtn CButton,在CTestBtn上添加虚函数DrawItem,添加从msdn复制的代码。然后将OK按钮关联一个成员变量m_btnTest TestBtn,然后要在CSettingDlg中包含"TestBtn.h",再在button按钮的属性(样式)中,勾选所有者绘制(owner draw),这时ok按钮的ok就变红色了。 然后添加2个类:BtnST.CPP/H SXBtn.CPP/H 再将cancel的所有者绘制选上,关联一个成员变量,m_btnCancel CSXBtn(先选择CTestBtn,再在CSettingDlg的头文件里修改为CSXBtn),还要引入头文件,即可。 再复制一个cancel按钮,IDC_BTN_ST ButtonST,再做一个关联m_btnST CButtonST(通过上面的方法),去掉ownder draw。 在CSettingDlg中添加消息处理:WM_INITDIALOG. m_btnST.SetActiveBgColor(RGB(0,0,255)); //设置激活的颜色 m_btnST.SetActiveFgColor(RGB(255,0,0)); 7.在窗口中贴图 1)创建位图 CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); 2)创建兼容DC CDC::CreateCompatibleDC //在内存中准备资源,创建兼容DC virtual BOOL CreateCompatibleDC( CDC* pDC ); CDC dcCompatible; dcCompatible.CreateCompatibleDC(pDC); 3)将位图选到兼容DC中 用SelectObject dcCompatible.SelectObject(&bitmap); 4)将兼容DC中的位图贴到当前DC中: CDC::BitBlt BOOL BitBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, DWORD dwRop ); //x,y指示左上角的左边;再是宽度和高度(即位图的高度);位图的DC指针;原位图的左边;SRCCOPY复制原位图。 pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY); 举例:先插入一个bitmap的资源,然后选择相应的图片文件。 而因为绘制窗口需要先擦除窗口背景WM_ERASEBKGND,然后重绘。 在view类增加一个WM_ERASEBKGND消息 BOOL CPicView::OnEraseBkgnd(CDC* pDC) { // TODO: Add your message handler code here and/or call default CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP1); CDC dcCompatible; dcCompatible.CreateCompatibleDC(pDC); dcCompatible.SelectObject(&bitmap); CRect rect; GetClientRect(&rect); pDC->BitBlt(rect.left,rect.top,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY); // return CView::OnEraseBkgnd(pDC); return TRUE; } 拉伸矩形 CDC::StretchBlt BOOL StretchBlt( int x, int y, int nWidth, int nHeight, CDC* pSrcDC, int xSrc, int ySrc, int nSrcWidth, int nSrcHeight, DWORD dwRop ); //多了两个参数nSrcWidth,nSrcHeight原位图的宽度、高度 获取位图信息 CBitmap::GetBitmap int GetBitmap( BITMAP* pBitMap ); //指向一个bitmap结构体 typedef struct tagBITMAP { /* bm */ int bmType; int bmWidth; int bmHeight; int bmWidthBytes; BYTE bmPlanes; BYTE bmBitsPixel; LPVOID bmBits; } BITMAP; 在其中定义一个BITMAP变量…… BITMAP bmp; bitmap.GetBitmap(&bmp); 最后再拉伸://就可以不用BitBlt了 pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); 如果把这些代码切到OnDraw函数中去,则窗体改变的时候闪烁比较严重。
(孙鑫 十)绘图控制
最新推荐文章于 2016-12-04 14:49:55 发布