网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
源代码在线查看: 10.5 示例对话框.txt
10.5 示例对话框
上述字体对话框中,当选择某种字体后,在此对话框的示例区立即就可以显示出当前选择的改变(如
图 10.17所示的字体对话框中的示例组框内的内容)。这里,再为Graphic程序添加一个类似的功能,
也就是在已有的设置对话框中作一个示例区,当用户改变线宽或选择不同的线型时,在示例区也能
看到这种改变。
首先在设置对话框中增加一个组框,并将它的 Caption设置为:示例(如图 10.19所示)。前面我们已
经提到过,组框的默认ID是IDC STATIC。如果在程序中需要对组框进行操作的话,需要修改它的ID。
因为后面的程序会对这个示例组框进行一些操作,所以这里将它的ID修改为: IDC_SAMPLE。
图 10.19增加示例组框
对编辑框控件来说,当用户在其上面对文本进行改变时,它会向其父窗口,即对话框发送一个 EN
CHANGE通知消息。同样地,当用户单击单选按钮时,该按钮会向对话框发送BN-CLICKED消息。为了
反映用户对线宽和线型所做的改变, CSettingDlg类需要捕获这两个通知消息,以反映出用户所做
的改变。于是,我们首先利用 ClassWizard为 CSettingDlg类添加编辑框控件 C IDC_LINE_WIDTH)
的EN_CHANGE消息的响应函数: OnChangeLineWidth。然后分别对三个单选按钮 CIDC_RADI01,
IDC_RADI02和 IDC RADI03),都选择BN CLICKED消息,添加它们的消息响应函数: OnRadio 1,
OnRadio2 和OnRadio3o
如果把在示例组框中绘制线条的代码在这四个消息响应函数中都写一遍,代码重复性则太高,不太
合适。我们可以考虑这么做:在这囚个函数中调用 Invalidate函数让窗口无效,当下一次发生WM
PAINT消息时重绘窗口,然后在该消息响应函数: OnPaint中完成示例线条的绘制。这样,编写一处
绘制线条的代码就可以了。
因此,为CSettingDlg类添加WM PAINT消息的响应函数,井在此函数中完成示例线条的绘制。具体实
现代码如例 10-24所示。
1. void CSettingOlg : :OnPaint()
2. {
3. CPaintOC dc(this); // device context for pa工ntìng
4. // TOOO : Add your message handler code here
5 . CPen pen(m_nLineStyle,m_nLineWidth,RGB(255,0,0)) ;
6. dc.SelectObject(&pen);
7 . CRect rect ;
8. GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);
9. dc .MoveTo(rect . left+20 , rect . top+rect . Height() / 2) ;
10. dc.LineTo(rect.right-20 , rect.top+rect.Height() /2 );
11. // 00 not call COialog: :OnPaint() for painting messages
12. }
在此函数中,首先根据指定的线宽和线型创建画笔,这里先将画笔的颜色设置为红色,然后将该画
笔对象选入设备描述表中。
要想在组框中绘图,那么首先要得到组框的矩形区域范围。这可以通过调用 GetDlgItem函数来得到
指向组框窗口对象的指针,然后利用GetWindowRect函数获得组框窗口矩形区域的大小。需要提醒读
者注意的是,这里不能直接调用GetWindowRect函数,否则得到的将是对话框的矩形区域大小。
在绘制线条时,如果不想让线条的起点与组框矩形区域的左边框靠得太近,可以对得到的组框矩形
左边框的x坐标加上20个逻辑单位作为线条的起点x坐标,让组框与线条有一点空隙。线条起点的y
坐标可以利用组框矩形区域左上角的y坐标加上一个值:矩形高度值的一半,相当于将线条原点移到
到组框左边靠中间的位置。而线条终点的x坐标是组框矩形右上角x坐标减去20个逻辑单位,线条终
点的y坐标与起点的y坐标相等。
Build井运行Graphic程序,打开设置对话框,改变线宽的值,但是在示例组框中并没有发现绘制的
线条(如图 10.20所示)。但是当我们把设置对话框移动到屏幕左上角时,可以在该示例组框中看到
我们所期望的线条(如图 10.21所示)。之所以发生这种现象的原因主要是因为GetWindowRect函数的
调用,该函数的声明如下所示。
void GetWindowRect( LPRECT lpRect ) const;
该函数的参数是指向CRect或阻CT结构体的变量,接收屏幕坐标,也就是说,通过该函数接收到的是
屏幕坐标。而我们在绘图时是以对话框左上角为原点的客户区坐标,而通过GetWindowRect函数得到
的屏幕坐标是以屏幕左t角为原点的,这样得到的rect对象的各个坐标值是相对屏幕左上角的,值都
比较大。但是绘制线条时又是以对话框客户区的左上角为原点进行的,因此就绘制到对话框的外面,
就看不到线条了。当把对话框移动到屏幕左上角时,我们所得到的矩形区域坐标和作图时使用的矩
形区域大小基本差不多,因
此在示例组框中就能看到线条。
图 10.20看不到绘制的示例线条
图 10.21移动对话框位置后示例线条的显示
通过上面的分析,可以知道在得到组框的矩形区域大小后,需要将其由屏幕坐标转换为客户坐标。
这可以利用ScreenToClient函数来实现。该函数的声明形式如下所示:
void ScreenToClient(LPRECT lpRect ) consti
即在上述如例 10-24所示 CSettingDlg类 OnPaint函数的第 8行代码之后添加下面这句语句:
ScreenToClient(rect);
细心的读者可能会发现,上面的 ScreenToClient函数的声明中要求该函数的参数是 LPRECT类型,
但我们添加的代码中传递的却是 C Rect对象,程序却能成功编译,这与前面的情况一样,因为 CRect
类重载了 LP阻CT操作符。一般情况下,为了明白起见,通常还是为此参数添加一个取地址符,表示
传递的是指针,即:
ScreenToClient(&rect) ;
再次运行Graphic程序,打开设置对话框,这时就会发现示例组框中就有一条示例线条了,如图 10.22
所示。
图 10.22正确显示的示例线条
改变线宽的值,但是发现示例组框中线条的宽度并没有发生变化。回想一下前面的知识,当一个控
件与一个成员变量关联时,如果想让控件上的值反映到成员变量上,必须调用 UpdateData函数。因
此在上述如例 10-24所示 OnPaint函数的第 5行代码之前添加下面这条语句:
UpdateData();
再次运行 Graphic程序,打开设置对话框,改变线宽,或在线宽为 1时,选择不同线型,这时在设
置对话框的示例组框中随时可以看到用户所做的改变。
如果希望用户选择了颜色之后,也要反映到示例线条上,就要为设置对话框再添加一个 COLORREF
类型的成员变量: m_clr,因为将在 CGraphicView类中访问这个变量,因此将此变量设置为公有的。
并在对话框的构造函数中将此变量初始化红色:
m_clr=RGB(255, O, O);
因为对现在的 Graphic程序来说,当用户利用颜色对话框选择某种颜色后,选择的结果就会保存到
CGraphicView类的 III-clr变量,所以应该在 CGraphicView类中在设置对话框显示时将该变量保存
的颜色值传递给设置对话框的 m clr变量,即在上述例 10-11所示 CGraphicView类的 OnSetting
函数中,在调用 CSettingDIg对象的 DoModal函数之前添加下面这行代码:
dlg.m_clr = m_clr;
然后修改例10-24所示CSettingDlg类的OnPaint函数中创建画笔的代码,将m clr的值传递给该创建
函数的第三个参数,即把创建画笔的代码修改为下面这句代码:
CPen pen (m_nLineStyle ,m_nLineWidth , m_cl r) ;
再次运行Graphic程序,打开颜色对话框选择某种颜色,然后打开设置对话框,这时可以看到示例组
框中线条的颜色就是刚才所选的颜色。