题目
在MFC调用对话框读入数据,并在客户区输出。
这是《计算机图形学基础教程》的一个习题:
使用MFC设计一个长方形类CRectangle,调用对话框读入长方形的长度和宽度,在客户区输出长方形的周长和面积。
这个书上并没有教怎么用对话框读取输入,我在这之前也完全没接触过MFC的对话框。弄了两小时,终于把这道题做出来了。以此文记录一下
如果图片转存失败,可以去我个人博客看此文
参考链接
设计对话框
找了一下,MFC似乎没有像python那样的input()
或者像是VB里面的inputBox()
之类的函数,所以得自己先设计对话框。
首先打开Resource View
,在Dialog
处右键菜单插入新的对话框。
接着就是放控件以及给控件命名了。这个比较简单,就不详细说了。
我设计的对话框有两个Edit
控件,一个是IDC_LENGTH
,用于输入长方形的长,一个是IDC_WIDTH
,用于输入长方形的宽。
[外链图片转存失败(img-ghTlZDXq-1568120588103)(https://raw.githubusercontent.com/HaneChiri/PicBed/master/blog_images/20190910194014.png)]
新建对话框类
在设计好的对话框上右键菜单打开类向导,也就是classWizard
,会弹出一个对话框如下图:
大致意思是:检测到有个新建的对话框资源,你可能想要为它创建一个类,要创建吗?
点确定创建一个对应的类。
如果没有弹出这个对话框,你也可以在类向导右上角的Add Class
按钮来创建一个MFC里面的类,把基类调整成CDialog
,Dialog ID
设置成你刚刚设计的对话框ID就可以了。
[外链图片转存失败(img-sPpBeQm3-1568120638663)(https://raw.githubusercontent.com/HaneChiri/PicBed/master/blog_images/20190910108.png14)]
(其实命名最好在后面加个Dlg
后缀以表示这是对话框,但是我懒得改了)
添加关联变量
在类向导里面选择第二个选项卡,也就是Member Bariables
成员变量选项卡。
[外链图片转存失败(img-0hnIGnM1-1568119768730)(https://raw.githubusercontent.com/HaneChiri/PicBed/master/blog_images/20190910195436.png)]
这里面列出了对话框上控件的ID,这些ID可以在设计对话框的时候指定。
选中用于输入数据的控件,然后点击Add Variable
添加对话框类的成员变量。改变量名字,其他选项默认即可。
[外链图片转存失败(img-PKHLHFs6-1568119768730)(https://raw.githubusercontent.com/HaneChiri/PicBed/master/blog_images/20190910200353.png)]
这个操作与你直接在类代码中添加的区别是,这个操作会建立起控件和这个成员变量的关联关系。这个关联关系体现在自定义对话框类的DoDataExchange()
这个成员函数内:
void CInputRectangle::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CInputRectangle)
DDX_Text(pDX, IDC_LENGTH, m_edLength);//添加关联变量之前,这里是没有这两行的
DDX_Text(pDX, IDC_WIDTH, m_edWidth);
//}}AFX_DATA_MAP
}
调用对话框
如图,我打算使用菜单来调用对话框输入矩形长和宽。
添加菜单的过程不详细说。
直接跳到菜单的响应函数:
void CComputerGraphicsExerciseView::OnHomework2_2()
{
// TODO: Add your command handler code here
CInputRectangleDlg inputDlg;
int nResponse = inputDlg.DoModal();
if(nResponse==IDOK)
{
//这里获取输入并在客户区输出
}
}
在文件开头include对话框类的头文件,声明对象,并调用对话框对象的DoModal()
方法。
这个方法在对话框关闭之后,才会返回一个值,对应关闭对话框的动作,这里我用nResponse
这个int变量接收返回值。
接着判断返回值,如果是点击确定按钮关闭对话框,那么获取对话框的输入,并且在客户区输出。
获取输入
绑定对话框上两个编辑框的变量分别为:m_edWidth
和m_edLength
。默认情况下,它们是CString类型的,因此需要进行类型转换。
int width=atoi(inputDlg.m_edWidth.GetBuffer(0));
int height=atoi(inputDlg.m_edLength.GetBuffer(0));
对上面两行代码的说明:
- 两个关联变量是
public
的,因此可以直接访问。 - CString的
GetBuffer()
成员函数返回对应的字符数组类型的字符串 - atoi(ASCII to integer)把字符串转换成整型数
进行输出
获取设备上下文,并调整坐标系:
CDC *pDC=GetDC();//获取设备上下文
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
pDC->Rectangle(rect);//清空屏幕
输出数据,并释放设备上下文:
CRectangle crect(width,height);
CString perimeter_text,area_text;
perimeter_text.Format("长方形的周长为:%.2f",crect.perimeter());
area_text.Format("长方形的面积为:%.2f",crect.area());
pDC->TextOut(0,0,perimeter_text);
pDC->TextOut(0,20,area_text);
ReleaseDC(pDC);//释放设备上下文
这样就完成了
菜单代码概览
void CComputerGraphicsExerciseView::OnHomework2_2()
{
// TODO: Add your command handler code here
CInputRectangleDlg inputDlg;
int nResponse = inputDlg.DoModal();
if(nResponse==IDOK)
{
CDC *pDC=GetDC();
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
pDC->Rectangle(rect);//清空屏幕
int width=atoi(inputDlg.m_edWidth.GetBuffer(0));
int height=atoi(inputDlg.m_edLength.GetBuffer(0));
CRectangle crect(width,height);
CString perimeter_text,area_text;
perimeter_text.Format("长方形的周长为:%.2f",crect.perimeter());
area_text.Format("长方形的面积为:%.2f",crect.area());
pDC->TextOut(0,0,perimeter_text);
pDC->TextOut(0,20,area_text);
ReleaseDC(pDC);
}
}
错误思路
一开始我以为需要编写对话框的ok
按钮的响应事件,写成了下面这样,试了一下不行,不知道为什么:
void CInputRectangleDlg::OnOK()
{
// TODO: Add extra validation here
CDialog::OnOK();
UpdateData();//用于将数据从对话框同步到成员变量中
int width=atoi( m_edWidth.GetBuffer(0));
int height=atoi( m_edLength.GetBuffer(0));
CRectangle crect(width,height);
CDC *pDC=GetDC();
CRect rect;
GetClientRect(&rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(rect.Width(),rect.Height());
pDC->SetViewportExt(rect.Width(),-rect.Height());
pDC->SetViewportOrg(rect.Width()/2,rect.Height()/2);
rect.OffsetRect(-rect.Width()/2,-rect.Height()/2);
pDC->Rectangle(rect);//清空屏幕
CString perimeter_text,area_text;
perimeter_text.Format("长方形的周长为:%.2f",crect.perimeter());
area_text.Format("长方形的面积为:%.2f",crect.area());
pDC->TextOut(100,100,perimeter_text);
pDC->TextOut(100,300,area_text);
ReleaseDC(pDC);
}