【MFC】添加对话框,实现D配版画图功能

2024-01-03 11:50

本文主要是介绍【MFC】添加对话框,实现D配版画图功能,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、什么是对话框

二、模式对话框

1.添加打开菜单

2.添加Dialog对话框资源

3.获取线条宽度

1.对话框获取线条宽度

2.滑块框获取

4.模拟动画图标

5.选项框颜色

6.示例效果


我在上篇文章中已经搞定了绘制一些简单图形的功能👉使用MFC做一个低配版画图软件,但是绘制图形的线条样式都是固定的,那么有没有方法能够保证可以随时改变这样线条样式呢?本篇,我将使用对话框来实现动态的样式改变。

最终效果

在开始撸码之前,我们要首先了解一下什么是对话框

一、什么是对话框

与用户进行交互的控件,如文件对话框,字体对话框,颜色对话捐给等,一般用于搞事,提醒等。

大体上说就是一种和用户交互的单独窗口,在这里我为大家介绍其中的一个对话框——模式对话框

二、模式对话框

模式对话框在其显示时,整个程序会暂停,直到关闭该对话框,我们上面使用的就是模式对话框。

1.添加打开菜单

首先我们添加一个打开模式对话框的菜单

编辑菜单和ID

给菜单项添加COMMAND消息事件

2.添加Dialog对话框资源

3.获取线条宽度

我们先搞定调节线条宽度的功能,在这里为大家提供两种方法,一种是通过文本对话框获取;另一种是滑块框获取。

1.对话框获取线条宽度

采用文本方式获取线条宽度Static Text 和 Edit Control

第一步:添加控件并更改控件描述,给对话框资源添加ID为 ID_DLG_SETUP

第二步:绑定对话框资源

给对话框资源添加一个类

第三步:补充消息处理函数并测试

void CMFCApplication6View::OnTypeSetup()
{//弹出对话框选项Setup conf;//调用成员函数的调用 模式对话框并返回对话框结果conf.DoModal();
}

测试

第四步:获取文本框输入内容

给文本编辑框绑定变量

第五步:补充消息处理函数,将文本框中获取数据放入设置画笔函数中

m_nLineWidth为view类成员变量,存储画笔宽度

void CMFCApplication6View::OnTypeSetup()
{//弹出对话框选项Setup conf;//调用成员函数的调用 模式对话框并返回对话框结果//conf.DoModal();//每次进入对话框时,文本框显示的是上一次设置的画笔宽度conf.m_nLineWidth = m_nLineWidth;//用户按下“确定”按钮 DoModal()返回 IDOKif (IDOK == conf.DoModal()) {m_nLineWidth = conf.m_nLineWidth;}
}

测试

2.滑块框获取

第一步:添加Slider Control控件

自动打勾:指定滑块在其值范围内对于每一个增量都有一个刻度线

打勾标记:指定滑块显示刻度线

工具提示:滑块滑到某个位置时显示其值

第二步:设置滑块范围

通过类向导添加OnInitDialog虚函数,也可以直接右击滑块控件添加(更方便)

在虚函数中

BOOL Setup::OnInitDialog()
{CDialogEx::OnInitDialog();//获得滑块控件//GetDlpItem传入ID,获得相应的控件或窗口CSliderCtrl* slider = (CSliderCtrl*)GetDlgItem(IDC_SLIDER1);//修改滑块属性slider->SetRange(1, 30);return TRUE;  // return TRUE unless you set the focus to a control// 异常: OCX 属性页应返回 FALSE
}

其中GetDlgItem返回CWnd* 类型,要将其强转成CSliderCtrl*类型

测试

第四步:获取滑块的值

剩下的操作与上面的文本对话框一样,也是给滑块和view类分别添加成员变量,用来存储画笔宽度

测试

4.模拟动画图标

完成调节线条宽度后接着就是更改画笔样式,画笔样式使用按钮来让用户选择。

第一步:添加:Group Box

在对话框中添加一个Group Box,并修改其标题为“线型”。Group Box起到一个框框的作用,让接下来添加的按钮看起来是一组的。

如下效果

第二步:添加Radio Button

接着添加三个单选按钮Radio Button,并按上面同样方法求改其描述

此时这三个按钮代表三组选项(也就是可以一次选多个),而我们只是想让用户一次只能选择一个,那么我们就要将三个按钮绑定为一组

第三步:按钮绑定为一组

选择第一个按钮,将其“组”属性改为TRUE,那么从这个按钮往下都会成为一组,直到有下一个“组”出现。这个时候这三个选项就会变成一组,每次也只能选择一项。

第四步:添加成员变量

这个时候我们就可以为这一组添加一个成员变量来记录用户选择的是哪一个按钮。

 同样在view文件中也按此方式添加,用来接收对话框中的值

第五步:补充消息处理函数

void CMFCApplication6View::OnTypeSetup()
{//弹出对话框选项Setup conf;//调用成员函数的调用 模式对话框并返回对话框结果//conf.DoModal();//每次进入对话框时,文本框显示的是上一次设置的画笔宽度conf.m_nLineWidth = m_nLineWidth;conf.m_nLineStyle = m_nLineStyle;//用户按下“确定”按钮 DoModal()返回 IDOKif (IDOK == conf.DoModal()) {m_nLineWidth = conf.m_nLineWidth;m_nLineStyle = conf.m_nLineStyle;}
}

当用户选择了第一个按钮会返回0,选择第二个按钮会返回1,依次类推,而PS_SOLID定义的表示也正好是从0开始的,所以我们可以直接将m_nLineStyle填入所有的画笔设置函数中即可

最终效果

5.选项框颜色

选项框颜色我决定不直接将显示在对话框内,而是通过一个按钮,当用户点击按钮时才去打开颜色对话框

添加一个按钮Button,修改其标题为“颜色”

下面就是给按钮添加相应事件,添加相应事件对快捷的方法就是双击按钮,当然也可以通过类向导来添加

void Setup::OnBnClickedButton1()
{//打开颜色对话框CColorDialog colDlg;colDlg.DoModal();
}

测试

按照同样的方法,分别给控件和view 类添加成员变量,再将相应函数补充完整。

void Setup::OnBnClickedButton1()
{//打开颜色对话框CColorDialog colDlg;colDlg.DoModal();if (IDOK == colDlg.DoModal()) {//返回选中的颜色m_color = colDlg.m_cc.rgbResult;}
}
void CMFCApplication6View::OnTypeSetup()
{//弹出对话框选项Setup conf;//调用成员函数的调用 模式对话框并返回对话框结果//conf.DoModal();//每次进入对话框时,文本框显示的是上一次设置的画笔宽度conf.m_nLineWidth = m_nLineWidth;conf.m_nLineStyle = m_nLineStyle;conf.m_color = m_color;//用户按下“确定”按钮 DoModal()返回 IDOKif (IDOK == conf.DoModal()) {m_nLineWidth = conf.m_nLineWidth;m_nLineStyle = conf.m_nLineStyle;m_color = conf.m_color;}
}

 再将程序中设置画笔颜色改为m_color就可以了

与上面添加控件不同的是,我们使用按钮进行颜色选择时是弹出了一个新的对话框,这就导致我们不能像上面那样在view里的相应事件函数中使用conf.m_color = m_color;来保证每次打开都会显示上一次的选择结果(上面那种方式每次打开颜色对话框时都会停留在黑色位置)

我们需要在对应的颜色框响应函数中修改(内容也略微有所不同)

void Setup::OnBnClickedButton1()
{//打开颜色对话框CColorDialog colDlg;colDlg.m_cc.Flags |= CC_RGBINIT;colDlg.m_cc.rgbResult = m_color;if (IDOK == colDlg.DoModal()) {//返回选中的颜色m_color = colDlg.m_cc.rgbResult;}
}

这样就能保证每次打开颜色框时都是保留上次选择的颜色

6.示例效果

每次用户更改线条样式时都会在“示例”区绘制出线条样式。

给对话框添加Group Box,并更改其标题为“示例”

当我们修改线型或者粗细或者颜色时,示例框中的线条也要跟着改变,这就需要我们给这些调整线条样式的控件添加响应函数

我们先给选择线条样式的三个按钮添加

void Setup::OnBnClickedRadio1()
{}void Setup::OnBnClickedRadio2()
{}void Setup::OnBnClickedRadio3()
{}

 每当这些控件发生改变时,就要在“示例”区重新绘制线条,所谓重新绘制,也就是说之气的那个“页面”(对话框页面)不需要了,可以去掉了。Invalidate() 默认参数为TRUE,也就是先发送背景刷新消息,再刷新前景

void Setup::OnBnClickedRadio1()
{//指定是否清除在更新区域内的背景//使窗口内容无效//每当这些控件发生改变时就要去重新绘制线,所谓重新绘制,就是之前的不需要了,可以去掉了//Invalidate( )可以使得当前的区域无效,就要去重新绘制Invalidate();
}void Setup::OnBnClickedRadio2()
{Invalidate();
}void Setup::OnBnClickedRadio3()
{Invalidate();
}

给控件类(Setup)添加WM_PAINT消息

void Setup::OnPaint()
{CPaintDC dc(this); // device context for painting// TODO: 在此处添加消息处理程序代码// 不为绘图消息调用 CDialogEx::OnPaint()//在示例区域绘制一条线CPen pen(m_nLineStyle, m_nLineWidth, m_color);CPen* pOldPen = dc.SelectObject(&pen);//获得“示例”区位置(通过“示例”的ID)“示例”区ID为IDC_SAMPLECRect rect;//得到对话框某一组件或控件的实例,并通过GetWindowRect将组件坐标信息存入到rect中GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);//GetWindowRect得到的是屏幕坐标,而我们想要的是工作区坐标,因此需要转换ScreenToClient(rect);//不要太靠近左右边,与左右边相差20距离dc.MoveTo(rect.left + 20, rect.top + rect.Height() / 2);dc.LineTo(rect.right - 20, rect.top + rect.Height() / 2);dc.SelectObject(pOldPen);
}

这个时候在“示例”区中已经显示了直线,但是当我们选择线型时直线却没有改变,原因在于虽然我们在下面代码中已经 将控件ID和成员变量绑定,但是在OnPaint()函数中这个还没有生效

void Setup::DoDataExchange(CDataExchange* pDX)
{CDialogEx::DoDataExchange(pDX);//数据交换,传入控件ID和变量,将控件值绑定到变量中DDX_Slider(pDX, IDC_SLIDER1, m_nLineWidth);DDX_Radio(pDX, IDC_RADIO1, m_nLineStyle);
}

我们需要在OnPaint()中增添UpdateData(); 实现同步控件和绑定的成员变量

void Setup::OnPaint()
{CPaintDC dc(this); // device context for painting// TODO: 在此处添加消息处理程序代码// 不为绘图消息调用 CDialogEx::OnPaint()//同步控件和绑定的成员变量UpdateData();//在示例区域绘制一条线CPen pen(m_nLineStyle, m_nLineWidth, m_color);CPen* pOldPen = dc.SelectObject(&pen);//获得“示例”区位置(通过“示例”的ID)CRect rect;//得到对话框某一组件或控件的实例,并通过GetWindowRect将组件坐标信息存入到rect中GetDlgItem(IDC_SAMPLE)->GetWindowRect(&rect);//GetWindowRect得到的是屏幕坐标,而我们想要的是工作区坐标,因此需要转换ScreenToClient(rect);//不要太靠近左右边,与左右边相差20距离dc.MoveTo(rect.left + 20, rect.top + rect.Height() / 2);dc.LineTo(rect.right - 20, rect.top + rect.Height() / 2);dc.SelectObject(pOldPen);
}

接下来就是同样的方法,当颜色或者线条粗细发生改变时也要去重新绘制线条

在颜色对话框中,当有colDlg.DoModal() = IDOK就要重新绘制,添加Invalidate( )

void Setup::OnBnClickedButton1()
{//打开颜色对话框CColorDialog colDlg;colDlg.m_cc.Flags |= CC_RGBINIT;colDlg.m_cc.rgbResult = m_color;if (IDOK == colDlg.DoModal()) {//返回选中的颜色m_color = colDlg.m_cc.rgbResult;Invalidate();}
}

滑块有水平滑动和垂直滑动两个事件,而我们的调节线条粗细使用的是水平滑动。如果我们要捕获这个动作,则需要添加WM_HSCROLL消息处理函数

void Setup::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{//响应滑块控件的水平移动消息Invalidate();CDialogEx::OnHScroll(nSBCode, nPos, pScrollBar);
}

最后这个对话框功能就大功告成了

这篇关于【MFC】添加对话框,实现D配版画图功能的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/565603

相关文章

Qt把文件夹从A移动到B的实现示例

《Qt把文件夹从A移动到B的实现示例》本文主要介绍了Qt把文件夹从A移动到B的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录如何移动一个文件? 如何移动文件夹(包含里面的全部内容):如何删除文件夹:QT 文件复制,移动(

Flask 验证码自动生成的实现示例

《Flask验证码自动生成的实现示例》本文主要介绍了Flask验证码自动生成的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习... 目录生成图片以及结果处理验证码蓝图html页面展示想必验证码大家都有所了解,但是可以自己定义图片验证码

VSCode配置Anaconda Python环境的实现

《VSCode配置AnacondaPython环境的实现》VisualStudioCode中可以使用Anaconda环境进行Python开发,本文主要介绍了VSCode配置AnacondaPytho... 目录前言一、安装 Visual Studio Code 和 Anaconda二、创建或激活 conda

使用mvn deploy命令上传jar包的实现

《使用mvndeploy命令上传jar包的实现》本文介绍了使用mvndeploy:deploy-file命令将本地仓库中的JAR包重新发布到Maven私服,文中通过示例代码介绍的非常详细,对大家的学... 目录一、背景二、环境三、配置nexus上传账号四、执行deploy命令上传包1. 首先需要把本地仓中要

JAVA封装多线程实现的方式及原理

《JAVA封装多线程实现的方式及原理》:本文主要介绍Java中封装多线程的原理和常见方式,通过封装可以简化多线程的使用,提高安全性,并增强代码的可维护性和可扩展性,需要的朋友可以参考下... 目录前言一、封装的目标二、常见的封装方式及原理总结前言在 Java 中,封装多线程的原理主要围绕着将多线程相关的操

MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固 通俗易懂版)

《MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固通俗易懂版)》本文主要讲解了MySQL中的多表查询,包括子查询、笛卡尔积、自连接、多表查询的实现方法以及多列子查询等,通过实际例子和操... 目录复合查询1. 回顾查询基本操作group by 分组having1. 显示部门号为10的部门名,员

java导出pdf文件的详细实现方法

《java导出pdf文件的详细实现方法》:本文主要介绍java导出pdf文件的详细实现方法,包括制作模板、获取中文字体文件、实现后端服务以及前端发起请求并生成下载链接,需要的朋友可以参考下... 目录使用注意点包含内容1、制作pdf模板2、获取pdf导出中文需要的文件3、实现4、前端发起请求并生成下载链接使

Java的volatile和sychronized底层实现原理解析

《Java的volatile和sychronized底层实现原理解析》文章详细介绍了Java中的synchronized和volatile关键字的底层实现原理,包括字节码层面、JVM层面的实现细节,以... 目录1. 概览2. Synchronized2.1 字节码层面2.2 JVM层面2.2.1 ente

Linux下修改hostname的三种实现方式

《Linux下修改hostname的三种实现方式》:本文主要介绍Linux下修改hostname的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录linux下修改ho编程stname三种方式方法1:修改配置文件方法2:hFvEWEostnamectl命

Java使用Mail构建邮件功能的完整指南

《Java使用Mail构建邮件功能的完整指南》JavaMailAPI是一个功能强大的工具,它可以帮助开发者轻松实现邮件的发送与接收功能,本文将介绍如何使用JavaMail发送和接收邮件,希望对大家有所... 目录1、简述2、主要特点3、发送样例3.1 发送纯文本邮件3.2 发送 html 邮件3.3 发送带