本周学习了孙鑫老师的第十课,本节课主要讲的是:画图以及改变控件的颜色、背景、字体、大小。
通过上面四个选项,设置我们画图的形状。下面三个选项,设置我们线条的大小、颜色和字体。
首先是选择颜色的窗口:
窗口mfc已经为我们写好了,我们只需要调用一下,在单文档的view类里面添加相应点击颜色菜单的函数:
void CGraphicView::OnColor()
{
// TODO: 在此添加命令处理程序代码
CColorDialog dlg;
dlg.m_cc.Flags |= CC_RGBINIT;//设置颜色对话框的初始颜色由用户指定
dlg.m_cc.rgbResult = m_clr;//初始颜色
if (IDOK == dlg.DoModal())
{
m_clr = dlg.m_cc.rgbResult;//保存用户选定的颜色
}
}
/*
CColorDialog 中有一个类型为CHOOSECOLOR的成员变量m_cc,我们可以通过改变他的值来设置颜色。
*/
typedef struct {
DWORD lStructSize;
HWND hwndOwner;
HWND hInstance;
COLORREF rgbResult;
COLORREF *lpCustColors;
DWORD Flags;
LPARAM lCustData;
LPCCHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
} CHOOSECOLOR, *LPCHOOSECOLOR;
rgbResult
/*
如果Flags设置了CC_RGBINIT标志,则rgbResult是创建对话框时最初选择的颜色。
如果指定的颜色值不在可用颜色中,系统将选择最接近的纯色。
如果rgbResult为零或未设置CC_RGBINIT,则最初选择的颜色为黑色。
如果用户单击“确定”按钮,则rgbResult指定用户的颜色选择。
要创建COLORREF颜色值,请使用RGB宏。
*/
其次是字体类型和字体大小的选择:
这个窗口也由mfc给我写好了,我们只需要调用CFontDialog
void CGraphicView::OnFont()
{
// TODO: 在此添加命令处理程序代码
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();//重绘窗口
}
}
/*
msdn 中关于成员变量m_font的描述是:构造CFontDialog对象后,可以使用m_cf结构初始化对话框中控件的值或状态。 m_cf结构的类型为CHOOSEFONT。
*/
typedef struct {
DWORD lStructSize;
HWND hwndOwner;
HDC hDC;
LPLOGFONT lpLogFont;
INT iPointSize;
DWORD Flags;
COLORREF rgbColors;
LPARAM lCustData;
LPCFHOOKPROC lpfnHook;
LPCTSTR lpTemplateName;
HINSTANCE hInstance;
LPTSTR lpszStyle;
WORD nFontType;
INT nSizeMin;
INT nSizeMax;
} CHOOSEFONT, *LPCHOOSEFONT;
lpLogFont
/*
如果在Flags成员中设置CF_INITTOLOGFONTSTRUCT标志并初始化LOGFONT成员,
则ChooseFont函数会使用最接近的字体初始化对话框。
如果用户单击“确定”按钮,则ChooseFont将根据用户的选择设置LOGFONT结构的成员。
*/
发送重绘消息后,在ondraw函数中相应
void CGraphicView::OnDraw(CDC* pDC)
{
CGraphicDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CFont* pOldFont = pDC->SelectObject(&m_font);//将用户选择的字体添加到设备描述表中,并返回之前的字体
pDC->TextOut(0,0,m_strFontName);//打印字体名称
pDC->SelectObject(pOldFont);//
}
第三个是设置对话框,设置线型、线宽,另外还有一个示例,可以实时展示用户的选择样式。
当我们在编辑框里面输入内容时,编辑框会发送一个EN_CHANGE消息,我们需要相应这个消息就可以实时示例中改变线宽。线型的话,需要相应BN_CLICKED消息。
void CSettingDlg::OnEnChangeLineWidth()
{
Invalidate();
}
void CSettingDlg::OnBnClickedRadio1()
{
// TODO: 在此添加控件通知处理程序代码
Invalidate();
}
void CSettingDlg::OnBnClickedRadio2()
{
// TODO: 在此添加控件通知处理程序代码
Invalidate();
}
void CSettingDlg::OnBnClickedRadio3()
{
// TODO: 在此添加控件通知处理程序代码
Invalidate();
}
Invalidate()会向系统发送WM_PAINT消息,我们只需要相应该消息即可。
void CSettingDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
UpdateData(TRUE);//将控件的数据更新到与之关联的空间变量
CPen pen(m_nLineStyle, m_nLineWidth, m_clr);
dc.SelectObject(&pen);
CRect rect;
GetDlgItem(IDC_SIMPLE)->GetWindowRect(&rect);//得到示例的画图区域
ScreenToClient(&rect);
dc.MoveTo(rect.left+20, rect.top + rect.Height() / 2);
dc.LineTo(rect.right-20, rect.top + rect.Height() / 2);
// 不为绘图消息调用 CDialog::OnPaint()
}
最后画图的话,只需要在view类中实现鼠标点下和松开的方法:
void CGraphicView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
m_ptOrigin = point;//保存鼠标点下时的坐标
CView::OnLButtonDown(nFlags, point);
}
void CGraphicView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
CClientDC dc(this);
CPen pen(m_nLineStyle, m_nLineWidth > 0 ? m_nLineWidth : 1, 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);
}
除此之外,孙老师还着重讲了关于改变控件颜色的方法。
首先我们需要相应WM_CTLCOLOR消息,添加函数OnCtlColor
HBRUSH CSettingDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{//每一个控件都会调用一次,pdc,pwnd指向了每一个子控件
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
// TODO: 在此更改 DC 的任何属性
if (IDC_LINE_STYLE == pWnd->GetDlgCtrlID())
{
pDC->SetTextColor(RGB(255,0,0));//设置文本颜色
pDC->SetBkMode(TRANSPARENT);//设置背景为透明
return m_brush;
}
if (IDC_LINE_WIDTH == pWnd->GetDlgCtrlID())
{
pDC->SetTextColor(RGB(255,0,0));//设置文本颜色
pDC->SetBkColor(RGB(0,0,255));//设置背景颜色
return m_brush;
}
if (IDC_TEXT == pWnd->GetDlgCtrlID())
{
pDC->SelectObject(&m_font);//设置文本的字体
}
// TODO: 如果默认的不是所需画笔,则返回另一个画笔
return hbr;
}
要想改变button的颜色和样式,需要从CButton派生一个类,重写CButton::DrawItem方法。
void CTestBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: 添加您的代码以绘制指定项
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);
}