(孙鑫 十)绘图控制

图形的绘制,如何使用自定义画笔(颜色,线宽,线形)。如何为程序中添加选项菜单和选项设置对话框,如何使用标准颜色对话框,如何使用字体对话框,在选项对话框中实现预览功能。实现选项对话框和窗口类中的数据交换。如何改变对话框和控件的背景色,如何改变控件的文本颜色,对按钮控件的特殊处理。如何在窗口中显示一幅位图。

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函数中去,则窗体改变的时候闪烁比较严重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值