【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

相关文章

C语言小项目实战之通讯录功能

《C语言小项目实战之通讯录功能》:本文主要介绍如何设计和实现一个简单的通讯录管理系统,包括联系人信息的存储、增加、删除、查找、修改和排序等功能,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录功能介绍:添加联系人模块显示联系人模块删除联系人模块查找联系人模块修改联系人模块排序联系人模块源代码如下

Java中使用Java Mail实现邮件服务功能示例

《Java中使用JavaMail实现邮件服务功能示例》:本文主要介绍Java中使用JavaMail实现邮件服务功能的相关资料,文章还提供了一个发送邮件的示例代码,包括创建参数类、邮件类和执行结... 目录前言一、历史背景二编程、pom依赖三、API说明(一)Session (会话)(二)Message编程客

Java中List转Map的几种具体实现方式和特点

《Java中List转Map的几种具体实现方式和特点》:本文主要介绍几种常用的List转Map的方式,包括使用for循环遍历、Java8StreamAPI、ApacheCommonsCollect... 目录前言1、使用for循环遍历:2、Java8 Stream API:3、Apache Commons

C#提取PDF表单数据的实现流程

《C#提取PDF表单数据的实现流程》PDF表单是一种常见的数据收集工具,广泛应用于调查问卷、业务合同等场景,凭借出色的跨平台兼容性和标准化特点,PDF表单在各行各业中得到了广泛应用,本文将探讨如何使用... 目录引言使用工具C# 提取多个PDF表单域的数据C# 提取特定PDF表单域的数据引言PDF表单是一

使用Python实现高效的端口扫描器

《使用Python实现高效的端口扫描器》在网络安全领域,端口扫描是一项基本而重要的技能,通过端口扫描,可以发现目标主机上开放的服务和端口,这对于安全评估、渗透测试等有着不可忽视的作用,本文将介绍如何使... 目录1. 端口扫描的基本原理2. 使用python实现端口扫描2.1 安装必要的库2.2 编写端口扫

PyCharm接入DeepSeek实现AI编程的操作流程

《PyCharm接入DeepSeek实现AI编程的操作流程》DeepSeek是一家专注于人工智能技术研发的公司,致力于开发高性能、低成本的AI模型,接下来,我们把DeepSeek接入到PyCharm中... 目录引言效果演示创建API key在PyCharm中下载Continue插件配置Continue引言

MySQL分表自动化创建的实现方案

《MySQL分表自动化创建的实现方案》在数据库应用场景中,随着数据量的不断增长,单表存储数据可能会面临性能瓶颈,例如查询、插入、更新等操作的效率会逐渐降低,分表是一种有效的优化策略,它将数据分散存储在... 目录一、项目目的二、实现过程(一)mysql 事件调度器结合存储过程方式1. 开启事件调度器2. 创

使用Python实现操作mongodb详解

《使用Python实现操作mongodb详解》这篇文章主要为大家详细介绍了使用Python实现操作mongodb的相关知识,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一、示例二、常用指令三、遇到的问题一、示例from pymongo import MongoClientf

SQL Server使用SELECT INTO实现表备份的代码示例

《SQLServer使用SELECTINTO实现表备份的代码示例》在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误,在SQLServer中,可以使用SELECTINT... 在数据库管理过程中,有时我们需要对表进行备份,以防数据丢失或修改错误。在 SQL Server 中,可以使用 SE

基于Go语言实现一个压测工具

《基于Go语言实现一个压测工具》这篇文章主要为大家详细介绍了基于Go语言实现一个简单的压测工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录整体架构通用数据处理模块Http请求响应数据处理Curl参数解析处理客户端模块Http客户端处理Grpc客户端处理Websocket客户端