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

提要:
图形的绘制,如何使用自定义画笔(颜色,线宽,线形)。
如何为程序中添加选项菜单和选项设置对话框,
如何使用标准颜色对话框,
如何使用字体对话框,在选项对话框中实现预览功能。
实现选项对话框和窗口类中的数据交换。
如何改变对话框和控件的背景色,
如何改变控件的文本颜色,对按钮控件的特殊处理。
如何在窗口中显示一幅位图。
      
一、课程内容 (例程 Graphic 基于 Single Doc)
1、菜单上设置绘图方式(点、矩形、椭圆),由View类处理这些菜单命令的消息,设置成员变量 UINT m_nDrawType; 用来保存当前用户选取的绘图方式
2、在View类中捕捉WM_LBUTTONDOWN和WM_LBUTTONUP两个鼠标消息,用来设定画线、画椭圆等时所需要的两个点。加入成员变量CPoint m_ptOrigin;
迎来表示绘图的起点。
鼠标按下时,取得绘图起始点
void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point)
{
m_ptOrigin=point;
CView::OnLButtonDown(nFlags, point);
}
然后在WM_LBUTTONUP鼠标消息中绘图
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TOD Add your message handler code here and/or call default
CClientDC dc(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;
}
CView::OnLButtonUp(nFlags, point);
}
3、设置绘图Option对话框(IDD_DLG_SETTING)对应的类为:CSettingDlg,可以设置一些绘图参数(16:40开始),由菜单IDM_SETTING"设置"来关联
对应于每个设置项,设定一个Dialog类中的成员变量,同时在View类中也要加入同名的成员变量,然后从对话框中得到设置值赋予给View类的成员变量中
然后依此决定绘图行为

 

4、颜色对话框(37:40开始)的创建
利用MFC现成的CColorDialog类.增加菜单IDM_COLOR来相应颜色对话框的弹出
void CGraphicView::OnColor()
{
CColorDialog dlg;
dlg.m_cc.Flags|=CC_RGBINIT | CC_FULLOPEN;//m_cc为CColorDialog的一个成员变量,类型是CHOOSECOLOR结构体
   //只有设定CC_RGBINIT的Flag才能使颜色不总是为默认色,CC_FULLOPEN表示展开颜色对话框
  
dlg.m_cc.rgbResult=m_clr;  //rgbResult为m_cc的一个COLORREF类型的成员,返回用户在颜色对话框中选定的颜色
if(IDOK==dlg.DoModal())
{
  m_clr=dlg.m_cc.rgbResult; //m_clr为View类的一个COLORREF类型的成员变量,用来保存用户的颜色选择
}
}

 

5、字体对话框(50:50开始)的创建
利用MFC现成的CFontDialog类.增加菜单IDM_FONT来相应字体对话框的弹出
void CGraphicView::OnFont()
{
CFontDialog dlg;
if(IDOK==dlg.DoModal())
{
  if(m_font.m_hObject) //m_font为View类的CFont 类型的成员变量,m_hObject为CGdiObject对象指向一个WindowsGDI资源的句柄
  //这句用来判断CFont对象是否和一个Window GDI对象关联,如果已经关联则不能再次调用CreateFontIndirect,只能先用DeleteObject,断开关联
  m_font.DeleteObject();
  m_font.CreateFontIndirect(dlg.m_cf.lpLogFont);//m_cf为 CFontDialog的一个成员变量,类型是CHOOSEFONT结构体
  //这句表示从对话框返回的m_cf结构体的lpLogFont上生成字体对象
  m_strFontName=dlg.m_cf.lpLogFont->lfFaceName;//m_strFontName为View类的CString类型的成员变量,用来存放字体名称
  Invalidate();//这句用来使窗体重绘,于是调用View类的OnDraw函数,使新字体生效,这样需要在OnDraw函数中:pDC->SelectObject(&m_font);
}
}

 

6、示例功能(01:06:10开始),指选定字体后在一个框中即时显示字体的样子,这里绘图Option对话框中选定一个线条类型和线宽后,即时显示线条的样子
在对话框中的Edit控件和radio按钮控件中都调用Invalidate()函数,使得窗体重绘(WM_PAINT消息相应函数),在重绘中如下即时显示示例,这样代码比较简捷,只编写一处
void CSettingDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
UpdateData();//即时将对话框中的控件的值反应到成员变量中
CPen pen(m_nLineStyle,m_nLineWidth,m_clr);
dc.SelectObject(&pen);

 

CRect rect;
GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);//得到示例外边框(IDC_SAMPLE)的矩形区域,此处为屏幕坐标,需要用下面函数转换为客户区坐标
ScreenToClient(&rect);

 

dc.MoveTo(rect.left+20,rect.top+rect.Height()/2);
dc.LineTo(rect.right-20,rect.top+rect.Height()/2);
// Do not call CDialog::OnPaint() for painting messages
}

 


7、如何改变对话框和控件的背景色及控件的字体颜色(01:22:00开始)
对话框捕获消息WM_CTLCOLOR,在其响应函数CWnd::OnCtlColor
HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
if(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE)//获得字窗口的ID值,对于控件可以得到其ID
{
  pDC->SetTextColor(RGB(255,0,0));//设置控件的字体颜色
  pDC->SetBkMode(TRANSPARENT); //设置控件文字的背景模式为透明
  return m_brush;//对话框成员变量 CBrush m_brush;,需要构造函数中初始化 m_brush.CreateSolidBrush(RGB(0,0,255));
}
if(pWnd->GetDlgCtrlID()==IDC_LINE_WIDTH)
{
  pDC->SetTextColor(RGB(255,0,0));//设置Edit控件的字体颜色
  //pDC->SetBkMode(TRANSPARENT);
  pDC->SetBkColor(RGB(0,0,255));//设置Edit控件的背景颜色
  return m_brush;
}
if(pWnd->GetDlgCtrlID()==IDC_TEXT)  //static静态文本控件

{
  pDC->SelectObject(&m_font);//对话框成员变量 CFont m_font,需要构造函数中初始化m_font.CreatePointFont(200,"华文行楷");
 
}
/*if(pWnd->GetDlgCtrlID()==IDOK)   //OK按钮控件,在OnCtlColor函数中无法修改按钮的颜色等
{
  pDC->SetTextColor(RGB(255,0,0));
  return m_brush;
}*/
return hbr;//返回HBRUSH,针对所有对话框中的控件起作用,上面每次return m_brush只对单个控件起作用
//return m_brush;
}

 

在OnCtlColor函数中无法修改按钮的颜色等GDI类型,需要自己建立一个从CButton类派生的按钮类(CTestBtn 做为对话框类的成员变量),
然后改写CTestBtn的虚函数DrawItem(代码拷贝自MSDN例子)
void CTestBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
UINT uStyle = DFCS_BUTTONPUSH;

 

   // This code only works with buttons.
   ASSERT(lpDrawItemStruct->CtlType == ODT_BUTTON);

 

   // If drawing selected, add the pushed style to DrawFrameControl.
   if (lpDrawItemStruct->itemState & ODS_SELECTED)
      uStyle |= DFCS_PUSHED;

 

   // Draw the button frame.
   ::DrawFrameControl(lpDrawItemStruct->hDC, &lpDrawItemStruct->rcItem,
      DFC_BUTTON, uStyle);

 

   // Get the button's text.
   CString strText;
   GetWindowText(strText);

 

   // Draw the button text using the text color red.
   COLORREF crOldColor = ::SetTextColor(lpDrawItemStruct->hDC, RGB(255,0,0));
   ::DrawText(lpDrawItemStruct->hDC, strText, strText.GetLength(),
      &lpDrawItemStruct->rcItem, DT_SINGLELINE|DT_VCENTER|DT_CENTER);
   ::SetTextColor(lpDrawItemStruct->hDC, crOldColor);

 

}
将对话框中的OK按钮关联到一个成员变量m_btnTest,其类型为CTestBtn
还需要将对话框中的OK按钮属性中加上Owner draw的Style

 

可以参考两个按钮类SXBtn.cpp,BtnST.cpp,
演示Cancel按钮关联到m_BtnCancel成员变量(CSXBtn类的对象),
演示ButtonST按钮关联到m_btnSTl成员变量(CButtonST类的对象),注意:对于CButtonST类的使用不需要将按钮加上Owner draw的Style
在WM_INITDIALOG消息中处理
BOOL CSettingDlg::OnInitDialog()
{
CDialog::OnInitDialog();
m_btnST.SetActiveBgColor(RGB(0,0,255));//设置按钮活动背景
m_btnST.SetActiveFgColor(RGB(255,0,0));//设置按钮活动文字颜色

 

m_btnST.SetInactiveBgColor(RGB(255,0,255));//设置按钮非活动背景
m_btnST.SetInactiveFgColor(RGB(255,255,0));//设置按钮非活动文字颜色
return TRUE;  // return TRUE unless you set the focus to a control

 

}

 

8、在窗口中显示一幅位图(01:58:10开始)
4个步骤:
1、创建位图
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);

 

2、创建兼容DC
CDC dcCompatible;
dcCompatible.CreateCompatibleDC(pDC);

 

3、将位图选到兼容DC中
dcCompatible.SelectObject(&bitmap);

 

4、将兼容DC中的位图贴到当前DC中。
pDC->BitBlt(rect.left,rect.top,rect.Width(),
rect.Height(),&dcCompatible,0,0,SRCCOPY);

 

可以在void CGraphicView::OnDraw(CDC* pDC)中处理(会出现闪烁-每次都要擦除后重绘造成的)
或者在 WM_ERASEBKGND 消息对应函数BOOL CGraphicView::OnEraseBkgnd(CDC* pDC) 中处理
BOOL CGraphicView::OnEraseBkgnd(CDC* pDC)
{
CBitmap bitmap;
bitmap.LoadBitmap(IDB_BITMAP1);

 

BITMAP bmp;
bitmap.GetBitmap(&bmp);

 

CDC dcCompatible;
dcCompatible.CreateCompatibleDC(pDC);

 

dcCompatible.SelectObject(&bitmap);

 

CRect rect;
GetClientRect(&rect);
// pDC->BitBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,0,0,SRCCOPY);//BitBlt拷贝的位图不改变大小
pDC->StretchBlt(0,0,rect.Width(),rect.Height(),&dcCompatible,   //StretchBlt拷贝的位图或者拉抻或者压缩,使之与目的DC一样大
  0,0,bmp.bmWidth,bmp.bmHeight,SRCCOPY); //注意这里bmp用的是BITMAP结构变量
return TRUE;
// return CView::OnEraseBkgnd(pDC);
}

 

二、知识点

 

1、新加的类无法在ClassWizard中出现
删除*.clw文件重新生成即可

 

2、对于多个Radio单选按钮,有一个设置为Group属性,则只到下一个Group属性的按钮出现,否则所有的按钮都属于同一组,
可以只针对具有Group属性的按钮关联一个成员变量,所有的按钮都对应着个变量,其值从0开始递增(Group属性的按钮值为0)

 

3、为何在上面 dlg.m_cc.Flags|=CC_RGBINIT  中用 dlg.m_cc.Flags=CC_RGBINIT 会报内存错
这是因为只用CC_RGBINIT不足以满足颜色对话框的初始要求,又要用到CC_RGBINIT这个Flag完成所需功能,于是可以用|逻辑符来实现

 

4、如何得到控件的外围举行区域RECT
CRect rect;
GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);//得到'示例'外边框(IDC_SAMPLE)的矩形区域,此处rect为屏幕坐标,需要用下面函数转换为客户区坐标
ScreenToClient(&rect);

 

5、如何通过CWnd值得到控件的ID
if(pWnd->GetDlgCtrlID()==IDC_LINE_STYLE)//GetDlgCtrlID函数用来获得字窗口的ID值,对于控件可以得到其ID

 

6、如何设置DC的背景模式
pDC->SetBkMode(TRANSPARENT); //设置背景模式为透明

你可能感兴趣的:(C/C++)