MFC习题|RGB颜色模型演示程序

习题来源:《计算机图形学基础教程》孔令德(第二版)

用 mfc 基于对话框的编程,实现下图的 RGB 颜色模型演示程序。点击颜色按钮能将“颜色及代码”这个组框中的静态文本框变成对应的颜色,调色板按钮可以调出自带的颜色选择对话框。滚动条和旁边的编辑框都可以调整颜色。

设计对话框过程不详述,直接开始代码和思路介绍。参考链接见文末。

改变演示块颜色

我在这里将用于演示颜色的静态文本框称为演示块,对应的 ID 为IDC_COLOR_BOX

查找了很久关于“如何修改控件颜色”的资料。

改变控件颜色需要在对话框类的OnCltColor()成员函数里面写对应代码。要生成这个方法,需要添加WM_CTLCOLOR这个消息的响应函数,在Class View的对话框类上右键可以找到Add Windows Message Handler,在这里添加就可以了。

生成的代码如下:

1
2
3
4
5
6
7
8
9
HBRUSH CComputerGraphcisExercise2Dlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);

// TODO: Change any attributes of the DC here

// TODO: Return a different brush if the default is not desired
return hbr;
}

这个函数会在每个控件被重绘时调用,所以将改变控件颜色的代码放在这里就行了。

参数pWnd可以用来识别现在是哪个控件正在被重绘。

它的返回值是用于填充控件的画刷。

可以先判断是哪个控件正在被重绘,当演示块被重绘时,将它的颜色调整为自己设置的颜色。

1
2
3
4
5
6
7
8
9
10
11
12
13
HBRUSH CComputerGraphcisExercise2Dlg::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_COLOR_BOX)//判断控件
{
hbr=CreateSolidBrush(m_color);//调整颜色
}

// TODO: Return a different brush if the default is not desired
return hbr;
}

上面代码的m_color是一个对话框类的protected变量,我把它和自动生成的m_hIcon放在了一起。

注意:如果这个变量被设置为public,就会在运行时产生错误,原因未知。

此变量在对话框类的初始化函数OnInitDialog()内初始化。

有了以上代码之后,想要改变演示块的颜色,只需要改变m_color的值并刷新对话框(例如使用Invalidate())就可以了。

显示颜色代码

在演示块下面有一个静态文本框用于显示当前颜色的十六进制代码,例如“#ffffff”。

由于颜色每次都是在对话框刷新的时候被改变的,可以将这个功能写在OnPaint()内。获取方式也不难,看代码基本能看懂,不赘述。

1
2
3
4
5
6
7
8
9
10
void CComputerGraphcisExercise2Dlg::OnPaint()
{
//其他代码
//获取颜色代码

CStatic *color_code = (CStatic*)GetDlgItem(IDC_COLOR_CODE);
CString color;
color.Format("#%02x%02x%02x",GetRValue(m_color),GetGValue(m_color),GetBValue(m_color));
color_code ->SetWindowText(color);
}

实现颜色按钮

双击每个颜色按钮,添加它们的响应事件,例如:

1
2
3
4
5
6
void CComputerGraphcisExercise2Dlg::OnButtonRed()
{
// TODO: Add your control notification handler code here
m_color = RGB(255,0,0);
Invalidate();
}

调整它们的颜色,并进行刷新重绘。

至于调色板按钮,需要使用 mfc 内置的颜色对话框CColorDlg:

1
2
3
4
5
6
7
8
9
10
11
12
void CComputerGraphcisExercise2Dlg::OnButtonPalette()
{
// TODO: Add your control notification handler code here
CColorDialog palette;
int nResponse = palette.DoModal();
if(nResponse == IDOK)
{
m_color = palette.GetColor();//获取调色板的颜色
}
Invalidate();

}

实现滚动条

初始化滚动条

首先需要在对话框的OnInitDialog()方法内,新增初始化滚动条范围值的代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BOOL CComputerGraphcisExercise2Dlg::OnInitDialog()
{
//其它代码
//...

CScrollBar *scroll=(CScrollBar*)GetDlgItem(IDC_SCROLLBAR_R);

scroll->SetScrollRange(0,255);

scroll = (CScrollBar*)GetDlgItem(IDC_SCROLLBAR_G);

scroll->SetScrollRange(0,255);

scroll = (CScrollBar*)GetDlgItem(IDC_SCROLLBAR_B);
scroll->SetScrollRange(0,255);

return TRUE; // return TRUE unless you set the focus to a control
}

这段代码初始化了三个滚动条控件,首先用GetDlgItem()来获取 ID 对应的控件对象的指针,然后调用SetScrollRange()来设定其范围为 0~255。

响应滚动条事件

滚动条的响应事件不像按钮一样是每个按钮分开的,而是分为水平滚动条事件响应函数,和垂直滚动条响应函数。

Class View里对对话框类右键,在右键菜单中找到Add Windows Message Handler,添加WM_HSCROLL消息的响应函数(如果是垂直滚动条,应该是WM_VSCROLL消息)。

生成的响应函数是这样的:

1
2
3
4
5
void CComputerGraphcisExercise2Dlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default
CDialog::OnHScroll(nSBCode, nPos, pScrollBar);
}

没看文档,不过参数大概意思可能是:

  • nSBCode:滚动条响应的消息类型
  • nPos:滚动条改变状态之后的值
  • pScrollBar:指向被改变状态的滚动条控件的指针

滚动条拖动的代码需要自己写,在实现功能之前,你即使用鼠标拖动滑块,滑块也会回到原来的位置。

在这个响应函数里面,我只让滚动条改变对应的编辑框对应的数值。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void CComputerGraphcisExercise2Dlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
// TODO: Add your message handler code here and/or call default

CDialog::OnHScroll(nSBCode, nPos, pScrollBar);

int pos = pScrollBar->GetScrollPos();//获取当前位置

switch(nSBCode)
{
case SB_THUMBPOSITION://被拖动
pos = nPos;
break;
//其实这里还可以写别的事件响应,丰富功能
}
pScrollBar->SetScrollPos(pos);

//设置与滚动条对应的编辑框的数值
switch(pScrollBar->GetDlgCtrlID())
{
case IDC_SCROLLBAR_R:
SetDlgItemInt(IDC_EDIT_R,pos);
break;
case IDC_SCROLLBAR_G:
SetDlgItemInt(IDC_EDIT_G,pos);
break;
case IDC_SCROLLBAR_B:
SetDlgItemInt(IDC_EDIT_B,pos);
break;
}

}

响应编辑框变化事件

现在已经可以滑动滚动条来修改编辑框内的值了,但演示块的颜色还不会改变,我把这个功能写在编辑框里面了,这样,可以顺便实现“在编辑框内修改值来修改颜色”的功能。

这是其中一个编辑框的响应函数代码,其他两个类似,要说的内容都写在注释里面了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void CComputerGraphcisExercise2Dlg::OnChangeEditR()
{
// TODO: If this is a RICHEDIT control, the control will not
// send this notification unless you override the CDialog::OnInitDialog()
// function and call CRichEditCtrl().SetEventMask()
// with the ENM_CHANGE flag ORed into the mask.

// TODO: Add your control notification handler code here
UpdateData();//更新数据,将数据从控件上同步到绑定的变量
int pos = atoi(m_R_value.GetBuffer(0));
((CScrollBar*)GetDlgItem(IDC_SCROLLBAR_R))->SetScrollPos(pos);

//根据滚动条位置设置当前颜色值
int R=0,G=0,B=0;
R=((CScrollBar*)GetDlgItem(IDC_SCROLLBAR_R))->GetScrollPos();
G=((CScrollBar*)GetDlgItem(IDC_SCROLLBAR_G))->GetScrollPos();
B=((CScrollBar*)GetDlgItem(IDC_SCROLLBAR_B))->GetScrollPos();
m_color = RGB(R,G,B);

//为了防止整个对话框闪烁,只刷新演示块
CRect rect;
((CStatic*)GetDlgItem(IDC_COLOR_BOX))->GetWindowRect(&rect);
ScreenToClient(&rect);//转换为对话框上的客户坐标
InvalidateRect(rect);//只刷新控件位置
}

完成这一步之后,已经能够实现使用滚动条或者编辑框来改变颜色了,但是当你在点击颜色按钮时,虽然颜色改变了,但是滚动条的位置和编辑框的值不会随之改变。

因此还需要一步:

滚动条随颜色而变化位置

这个对话框内只有颜色按钮能够改变颜色,所以简单地在所有颜色按钮的代码内添加改变位置的代码即可。

而改变滚动条的位置只需要改变对应的编辑框的数值就可以了。

于是颜色按钮代码变成了这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void CComputerGraphcisExercise2Dlg::OnButtonRed()
{
// TODO: Add your control notification handler code here
m_color = RGB(255,0,0);

//调整滚动条位置
int R=0,G=0,B=0;
R=GetRValue(m_color);
G=GetGValue(m_color);
B=GetBValue(m_color);
SetDlgItemInt(IDC_EDIT_R,R);
SetDlgItemInt(IDC_EDIT_G,G);
SetDlgItemInt(IDC_EDIT_B,B);

Invalidate();
}

部分用到的 MFC 函数或宏的简介

详情见百度

  • GetRValue()GetGValue()GetBValue(),分别用于获取颜色值的 RGB 三个通道的值
  • SetDlgItemInt(),可以将值送入 ID 对应的控件
  • GetDlgItem(),通过 ID 来获取指向控件的指针,记得转换指针类型
  • Invalidate(),使客户区无效化,引起重绘

参考链接

MFC习题|RGB颜色模型演示程序

https://yxchangingself.xyz/posts/MFC_RGB_demonstration/

作者

憧憬少

发布于

2019-09-14

更新于

2019-09-14

许可协议