MFC案例:基于对话框的简易阅读器

一、功能目标:
  1.阅读txt文件
  2.阅读时可以调整字体及字的大小
  3.打开曾经阅读过的文件时,能够自动从上次阅读结束的位置开始显示,也就是能够保存和再次使用阅读信息。
  4.对于利用剪贴板粘贴来的文字能够存储成txt文件保存。
  5.显示界面可以调整大小。
二、设计步骤
  1. 建立一个基于对话框的MFC项目,项目名:simpleReader
  1.1 对话框左上角图标Icon改为自己的图标
     步骤:右键资源视图Icon->选择添加资源->导入自己的图标->回到资源视图->删除ID为IDR_MAINFRAME的Icon->右键新导入Icon ID->选择属性,ID号改为IDR_MAINFRAME;
  2.从工具箱中向对话框内拖入一个文本编辑框(Edit Control)。
  2.1 让编辑框充满对话框,这个编辑框是显示阅读文字的界面。
  2.2 右键编辑框,点击属性,将编辑框的ID改为IDC_TEXTEDIT。同时,对编辑框的其它属性进行设置:Auto VScroll置为True,垂直滚动置为True,多行置为True,想要返回置为True。
  2.3 右键文本编辑框,选择添加变量,变量名:m_textEdit,注意是控件类型。
  3.在CsimpleReaderDlg类中以public方式声明需要的变量
      具体位置可在simpleReaderDlg.h文件最后(在自动生成的变量m_textEdit的后边)。
  3.1 声明 CString filePathName; //阅读文件的路径及文件名
  3.2 声明自定义类readFileInfo,用于记录阅读文件的相关信息
     typedef class
     {
     public:
         CString fileName; //已阅读文件名(含路径)
         int startPos; //阅读位置
         int endPos; //阅读位置
      } readFileInfo;
      //说明:阅读位置使用阅读结束时光标所在位置(字符数)表示。这个位置实质是光标选黑的区域,因此表示其位置需有两个数表示。通过编辑框对象的成员函数GetSel()函数获得,该函数的返回值是DWORD类型,通过LOWORD、HIWORD两个有参宏将返回值解析得到两个阅读位置。当没有选择区域只是光标停在某位置时,这两个值相等。
  3.3 #define READNUM 4 //定义记录阅读文件个数的常量(可更改),打开文件个数超过READNUM时,最早打开的文件会被顶掉。
  3.4 声明readFileInfo数组:
    readFileInfo readfileinfo[READNUM]; //用于记录最多READNUM个文件阅读信息的自定义类数组
  3.5 #define MAXTCHAR 10000  //文本编辑框接收数组最大长度
  4. 阅读信息存储文件
  4.1 前面声明了自定义数组readfileinfo[READNUM]用来处理阅读信息,这些信息如不保存进文件,程序关闭时信息会丢失,因此有必要建立一个文件进行保存,文件名:readInfo.txt,保存路径就在项目目录中。
  4.2 在simpleReaderDlg.h文件中,类内以public方式声明阅读信息保存函数:readInfoSave(); 在文件simpleReaderDlg.cpp中实现这个函数。代码如下:

void CsimpleReaderDlg::readInfoSave()
{CFile file;file.Open(L"readInfo.txt", CFile::modeCreate | CFile::modeWrite);for (int i = 0; i < READNUM; i++){TCHAR a[256] = { 0 };wcscpy_s(a, readfileinfo[i].fileName);TCHAR b[64] = { 0 };TCHAR c[64] = { 0 };wsprintf(b, L"%i\0", readfileinfo[i].startPos);wsprintf(c, L"%i\0", readfileinfo[i].endPos);file.Write(a, 256);file.Write(b, 64);file.Write(c, 64);}file.Close();
}

  4.3 在simpleReaderDlg.h文件中,类内以public方式声明阅读信息读取函数:readInfoRead(); 并在simpleReaderDlg.cpp中实现这个函数。代码如下:

void CsimpleReaderDlg::readInfoRead()
{CFile file;if (file.Open(L"readInfo.txt", CFile::modeRead))//打开成功{TCHAR a[258] = { 0 };TCHAR b[64] = { 0 };TCHAR c[64] = { 0 };for (int i = 0; i < READNUM; i++){file.Read(a, 256);file.Read(b, 64);file.Read(c, 64);readfileinfo[i].fileName = a;readfileinfo[i].startPos = _wtoi(b);readfileinfo[i].endPos = _wtoi(c);}file.Close();} else{MessageBox(L"调试");return;}
}

  4.4 在simpleReaderDlg.cpp中,找到OnInitDialog()函数,在里面添加一些代码。目的是,当程序第一次运行,保存阅读文件信息的文件readInfo.txt不存在时,添加一个记录内容为空的文件保存成readInfo.txt。具体在TODO:后面添加下列代码:

  CFile fileCheck;if (!fileCheck.Open(L"readInfo.txt", CFile::modeRead)){fileCheck.Open(L"readInfo.txt", CFile::modeCreate | CFile::modeWrite); //如不存在,新建一个for (int i = 0; i < READNUM; i++) //填入空数据{readfileinfo[i].fileName = L"";readfileinfo[i].startPos = 0;readfileinfo[i].endPos = 0;}fileCheck.Close();readInfoSave(); //保存文件}else fileCheck.Close(); //如存在,结束检查readInfoRead(); //读入数据存进数组readfileinfo[READNUM]

  5.退出函数
  5.1 对话框右上角“X”单击响应退出函数
   右键对话框->属性->单击消息列->选中消息 WM_CLOSE->点击<Add>OnClose。这样,在simpleReaderDlg.cpp中添加了void CsimpleReaderDlg::OnClose()函数,这个函数是点击对话框右上角“X”的响应函数,这个系统自动生成的函数在函数尾部自动调用了父类关闭函数CDialogEx::OnClose()。我们在此只需处理保存阅读文件信息即可,其余交给CDialogEx::OnClose()处理,代码如下:

void CsimpleReaderDlg::OnClose()
{int m_startPos = LOWORD(m_textEdit.GetSel()); int m_endPos = HIWORD(m_textEdit.GetSel());//m_textEdit.GetSel()的返回值是DWORD类型,其低位、高位有不同含义。//低位代表选择区域的开始位置、高位代表选择区域的结束位置。将光标//置于某处不做选择,高低位值相等,用此位置表示阅读位置。readFileInfo temp;temp.fileName = filePathName;temp.startPos = m_startPos;temp.endPos = m_endPos;int choice = -1; //choice用来表示当前阅读文件是否读过以及相关信息在readfileinfo数组//中的位置,-1表示没有读过,数组中没有它的信息for (int i = 0; i < READNUM; i++) //确定choice的值{if (readfileinfo[i].fileName == filePathName) choice = i;}if (choice == -1) //当前阅读文件信息不在readfileinfo数组中{for (int i = READNUM - 1; i > 0; i--) //将数组第0位置腾出{readfileinfo[i] = readfileinfo[i - 1];}}if (choice > 0 && choice < READNUM) /*当前阅读文件信息在readfileinfo数组1~READNUM-1之间,需将其移动到数组第0位置,实际是空出0位,后边重新写入*/{for (int i = choice; i > 0; i--){readfileinfo[i] = readfileinfo[i - 1];}}//choice==0的情况无需调整,故不考虑readfileinfo[0] = temp; //将当前阅读文件信息存入数组第0位置readInfoSave(); //将readfileinfo数组存入文件readInfo.txt

  5.1 选择菜单退出
    见后。
  6. 在对话框上添加菜单栏
   步骤:解决方案资源管理器->右键项目名simpleReader->添加->资源->选择Meni->新建->进入菜单编辑界面->顶行写上“文件(F)”。这时,回到资源视图,点击Menu,可看到菜单(指整个菜单)的ID是IDR_MENU1。右键对话框->属性->菜单->选中这个ID。
  6.1 打开文件函数 
  再回到菜单编辑界面,在“文件(F)”的下方添加菜单“打开(O)”,接着,右键“打开(O)”选择属性,将其ID改为ID_OPEN;再次右键“打开(O)”,选择“添加事件处理程序”进入事件处理程序设置界面:类列表选择CsimpleReaderDlg,其余按缺省,确定后在simpleReaderDlg.cpp可看到空的函数void CsimpleReaderDlg::OnOpen(),相关代码如下:

void CsimpleReaderDlg::OnOpen()
{CFileDialog dlg ( //打开文件对话框TRUE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,L"All Files(*.TXT)|*.TXT||", AfxGetMainWnd());CString tempText = _T("");if (dlg.DoModal() == IDOK){filePathName = dlg.GetPathName();CFile file(filePathName, CFile::modeRead);TCHAR* read = new TCHAR[MAXTCHAR];memset(read, '\0', sizeof(TCHAR) * MAXTCHAR);file.Read(read, MAXTCHAR);for (int i = 0;; i++){tempText += read[i];if (read[i] == '\0')break;}file.Close();m_textEdit.SetWindowText(tempText);}int choice = -1; //检查当前打开文件是否已阅读过for (int i = 0; i < READNUM; i++) //{if (readfileinfo[i].fileName == filePathName) choice = i;}int a, b;if (choice == -1){a = 0; b = 0; //如果是未阅读读过的阅读位置设在开始}else {a = readfileinfo[choice].startPos;b = readfileinfo[choice].endPos;}m_textEdit.SetSel(a,b,0);
}

  6.2 从菜单退出函数
   回到菜单编辑界面,在“打开(O)”下面填写“退出(Q)”,右键“退出”->属性->ID改为ID_QUIT;再右键“退出”,选择“添加事件处理程序”进入事件处理程序设置界面:类列表选择CsimpleReaderDlg,其余按缺省,确定后在simpleReaderDlg.cpp可看到空的函数void CsimpleReaderDlg::OnQuit(),有关处理文件退出代码如下,就一句:

void CsimpleReaderDlg::OnQuit()
{// TODO: 在此添加命令处理程序代码OnClose();//这里只需调用点击右上角“X”的响应函数即可
}

  6.3 字体调整函数
  回到菜单编辑界面,在“文件(F)”右边再在添加一列下拉函数“格式(O)”,在“格式”下面填写“字体(F)”,右键“字体”->属性->ID改为ID_FONT;再右键“字体”,选择“添加事件处理程序”进入事件处理程序设置界面:类列表选择CsimpleReaderDlg,其余按缺省,确定后在simpleReaderDlg.cpp可看到空的函数void CsimpleReaderDlg::OnFont()。在写代码前,在CsimpleReaderDlg.h类内先声明一个CFont对象m_Font,用于保存新选定的字体。具体代码如下:

void CsimpleReaderDlg::OnFont()
{// TODO: 在此添加命令处理程序代码//记录阅读位置int m_startPos = LOWORD(m_textEdit.GetSel());int m_endPos = HIWORD(m_textEdit.GetSel());//设置字体CFont* tempFont = m_textEdit.GetFont(); //获取编辑框当前字体指针LOGFONT LogFont; //声明逻辑字体对象tempFont->GetLogFont(&LogFont); //加载逻辑字体CFontDialog dlg(&LogFont);  //逻辑字体对话框,在此选择字体if (dlg.DoModal() == IDOK){m_Font.Detach();  //将m_Font与原对象剥离LOGFONT temp;dlg.GetCurrentFont(&temp);   //获取当前字体信息m_Font.CreateFontIndirect(&temp); //创建字体m_textEdit.SetFont(&m_Font);  //设置字体}//重置阅读位置m_textEdit.SetSel(m_startPos, m_endPos, 0);
}

  7.处理文本框内容变动函数
  单击文本编辑框->右键选择属性->点击控件事件->点击EN_CHANGE->选择
<add>OnEnChangeTextedit,在cpp文件中可以看到增加了void CsimpleReaderDlg::OnEnChangeTextedit()这个文件。添加这个文件的目的是当采用Crt_V方式粘贴进阅读内容时,对粘贴的内容予以保存。相关代码如下:

void CsimpleReaderDlg::OnEnChangeTextedit()
{// TODO:  如果该控件是 RICHEDIT 控件,它将不// 发送此通知,除非重写 CDialogEx::OnInitDialog()// 函数并调用 CRichEditCtrl().SetEventMask(),// 同时将 ENM_CHANGE 标志“或”运算到掩码中。// TODO:  在此添加控件通知处理程序代码CString writeText;m_textEdit.GetWindowText(writeText);TCHAR* write = new TCHAR[MAXTCHAR]; //在堆区声明一个一百万字节的字符串数组memset(write, '\0', sizeof(TCHAR) * MAXTCHAR);write = writeText.GetBuffer();CFileDialog dlg(  //保存文件对话框FALSE, NULL, NULL, OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,_T("All Files(*.TXT)|*.TXT||"), AfxGetMainWnd()); if (dlg.DoModal() == IDOK) //判断另存为确认键是否按下{filePathName = dlg.GetPathName();//获取路径及文件名并赋给全局变量,除此处使用外退出时也需使用if ((filePathName.Right(4) != _T(".TXT")) && (filePathName.Right(4) != _T(".txt"))){filePathName += _T(".TXT"); //如无后缀则添加}CFile file(filePathName, CFile::modeCreate | CFile::modeWrite);file.Write(write, writeText.GetLength() * sizeof(write[0]));file.Close();}
}

  9.处理对话框大小变动函数
  选中对话框,右键属性->单击消息->选择WM_SIZE消息->点击<add>OnSize,这样在.cpp文件中,多了一个函数void CsimpleReaderDlg::OnSize(UINT nType, int cx, int cy),在这个函数中TODO:行后边添加:

	CWnd* pEdit = GetDlgItem(IDC_TEXTEDIT);if (pEdit) pEdit->MoveWindow(0, 0, cx, cy);

10.帮助文件
  选择菜单编辑界面,在“格式”右边在添加一列下拉:“帮助(H)”。在“帮助”下边填上“使用说明(N)”,右键“使用说明”选择属性,将ID改为ID_NOTE;接着,再右键使用说明,选择添加事件处理程序。这样,在.cpp中生成函数void CsimpleReaderDlg::OnNote()。先不写代码,在资源视图中:右键项目名->添加->资源->Dialog->新建;在对话框界面,将“取消”按钮删除。再拖入两个静态文本框,将其ID改为IDC_NOTE、IDC_NOTE1。
  右键对话框,添加MFC类,类名FileHelp,基类CDialogEx,对话框ID使用默认IDD_DIALOG1。然后在 simpleReaderDlg.cpp首部添加:#include “Filehelp.h”。再在解决方案资源管理器中找到HelpFile.cpp,点开,在void HelpFile::DoDataExchange(CDataExchange* pDX)函数的CDialogEx::DoDataExchange(pDX)行下面添加下列代码:

	CFont font,font1;font.CreateFont(20, 20, 0, 0, FW_NORMAL, FALSE, FALSE,FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,FIXED_PITCH | FF_MODERN, _T("楷体") );GetDlgItem(IDC_NOTE)->SetFont(&font);CString strText;strText = L"使用方法:";GetDlgItem(IDC_NOTE)->SetWindowText(strText);font1.CreateFont(18, 0, 0, 0, FW_NORMAL, FALSE, TRUE,TRUE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,FIXED_PITCH | FF_MODERN, _T("楷体"));strText = L"1.一次最好只打开一个文件,只有关闭程序时阅读位置信息才被保存。";GetDlgItem(IDC_NOTE1)->SetWindowText(strText);strText = "2.若调整界面窗口大小可以在打开文件前进行,以免文字跑动。";GetDlgItem(IDC_NOTE2)->SetWindowText(strText);strText = "3.阅读期间改变字体、字号等操作对原文件不起作用。";GetDlgItem(IDC_NOTE3)->SetWindowText(strText);strText = "4.本简易阅读器的字符集是UTF-16,如打开某些文件显示乱码,可用其它软件打开文件然后Ctr_C、Ctr_V到本阅读器,保存一下再打开。";GetDlgItem(IDC_NOTE4)->SetWindowText(strText);

前面生成的OnNote()函数的代码如下:

void CsimpleReaderDlg::OnNote()
{// TODO: 在此添加命令处理程序代码HelpFile dlg;dlg.DoModal();//创建模态对话框
}

程序完成后的界面截图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/489051.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

端点鉴别、安全电子邮件、TLS

文章目录 端点鉴别鉴别协议ap 1.0——发送者直接发送一个报文表明身份鉴别协议ap 2.0——ap1.0 的基础上&#xff0c;接收者对报文的来源IP地址进行鉴别鉴别协议ap 3.0——使用秘密口令&#xff0c;口令为鉴别者和被鉴别者之间共享的秘密鉴别协议ap 3.1——对秘密口令进行加密&…

电脑技巧:Everything 1.5 版本重大更新​支持拼音搜索+全文搜索

目录 一、软件介绍 二、主要更新亮点 更快的搜索速度和拼音搜索 全文搜索功能 智能推荐功能 增强的过滤选项 改进的用户界面 更好的多语言支持 增强的安全性和隐私保护 三、总结 Everything 作为一款备受推崇的文件搜索工具&#xff0c;以其卓越的性能和简洁的用户界…

element左侧导航栏

由element组件搭建的左侧导航栏 预览: html代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>首页</title><style> /*<!-- 调整页面背景颜色-->*/body{background-colo…

Datax可视化工具Datax-web安装部署

文章目录 一、Datax-web官网二、Datax-web介绍 1、Datax-web概述2、架构图3、系统环境要求4、特性支持 三、安装部署 1、环境准备2、Datax-web安装包准备 一、Datax-web官网 github&#xff1a;Datax-web gitee: Datax-web 二、Datax-web介绍 1、Datax-web概述 DataX Web…

node-js Express中间件

中间件介绍 什么是中间件 中间件其本质就是一个回调函数&#xff0c;可以像路由一样访问请求对象&#xff08;request&#xff09;和响应对象&#xff08;response&#xff09;。中间件的作用是什么 通过函数封装公共操作&#xff0c;简化代码中间件类型 - 全局中间件 - 路由中…

【数学】矩阵的逆与伪逆 EEGLAB

文章目录 前言matlab代码作用EEGLAB 中的代码总结参考文献 前言 在 EEGLAB 的使用中&#xff0c;运行程序时出现了矩阵接近奇异值&#xff0c;或者缩放错误。结果可能不准确。RCOND 1.873732e-20 的 bug&#xff0c;调查 EEGLAB 后发现是 raw 数据的问题。 matlab代码 A_1 …

TCP 的三次握手与四次挥手

TCP 的三次握手与四次挥手 TCP 协议&#xff0c;使用 TCP 的三次握手建立连接&#xff0c;使用四次挥手断开连接。 我们先看看基本的计算机网络中的TCP连接建立和断开的过程。 1.HTTP 三次握手 HTTP 的三次握手过程如下&#xff1a; 第一次握手&#xff08;SYN&#xff09;…

解锁前端开发速度的秘密武器【Vite】

在前端开发的江湖中&#xff0c;有人偏爱 Webpack 的强大与稳定&#xff0c;有人钟情于 Rollup 的轻量与高效。而 Vite&#xff0c;这个后来居上的工具&#xff0c;却以“极致的快”和“极简的易”赢得了开发者的芳心。众所周知万事都有缘由&#xff0c;接下来我们就来深度剖析…

【动态库.so | 头文件.hpp】基于CMake与CMakeList编写C++自定义库

前言 最近比较忙&#xff0c;其他系列教程得等到年后一起更&#xff01;请大家多多包涵&#xff01;&#xff01;相信各位在配置C环境和各类库的时候一定经常看到如下小连招 git clone https://github.com/opencv/opencv.git cd opencv mkdir build && cd build cma…

前端编辑器JSON HTML等,vue2-ace-editor,vue3-ace-editor

与框架无关 vue2-ace-editor有问题&#xff0c;ace拿不到&#xff08;brace&#xff09; 一些组件都是基于ace-builds或者brace包装的 不如直接用下面的&#xff0c;不如直接使用下面的 <template><div ref"editor" class"json-editor"><…

SpringMVC框架——入门

目录 一、三层框架和MVC 1. 三层架构 2. MVC模型 二、SpringMVC入门案例 1. SpringMVC的概述 2. SpringMVC的入门程序 3. 入门案例的执行过程分析 4. RequestMapping注解 一、三层框架和MVC 1. 三层架构 开发服务器端程序&#xff0c;一般都基于两种形式&#xff0c;一…

港口智慧应急管理平台:应急先锋,港航卫士

在风云变幻的港航世界&#xff0c;安全是永恒的基石。港口智慧应急管理平台宛如一位无畏的先锋&#xff0c;以智能化、数字化、信息化为利刃&#xff0c;借助 AI 与大数据的神奇力量&#xff0c;为港口保驾护航。 传统应急管理往往在事故发生后被动响应&#xff0c;而此平台却…

Prime2_解法二:openssl解密凭据

Prime2_解法二&#xff1a;openssl解密凭据 本博客提供的所有信息仅供学习和研究目的&#xff0c;旨在提高读者的网络安全意识和技术能力。请在合法合规的前提下使用本文中提供的任何技术、方法或工具。如果您选择使用本博客中的任何信息进行非法活动&#xff0c;您将独自承担全…

恢复删除的文件:6个免费Windows电脑数据恢复软件

数据恢复软件可帮助您从众多存储设备中恢复损坏或删除的数据。您可以使用这些文件恢复软件来检索文件、文档、视频、图片等。这些应用程序支持多种标准文件格式&#xff0c;如 PNG、RTF、PDF、HTML、JPG、MP3 等。 经过超过 75 小时的研究&#xff0c;我分析了 25 最佳免费数据…

爬虫自动化之drissionpage+SwitchyOmega实现随时切换代理ip

本文介绍了如何使用DrizzlePage进行爬虫自动化,并重点讲解了首次启动时设置代理IP以及通过SwitchyOmega插件实现随时切换代理IP的方法。 安装一次,后面调用就不会再去安装了 下载地址:https://github.com/FelisCatus/SwitchyOmega/releases 这两个文件随便那个都可以,下载…

今天你学C++了吗?——C++中的类与对象(日期类的实现)——实践与知识的碰撞❤

♥♥♥~~~~~~欢迎光临知星小度博客空间~~~~~~♥♥♥ ♥♥♥零星地变得优秀~也能拼凑出星河~♥♥♥ ♥♥♥我们一起努力成为更好的自己~♥♥♥ ♥♥♥如果这一篇博客对你有帮助~别忘了点赞分享哦~♥♥♥ ♥♥♥如果有什么问题可以评论区留言或者私信我哦~♥♥♥ ✨✨✨✨✨✨ 个…

kafka进阶_4.kafka扩展

文章目录 一、Controller选举二、Kafka集成2.1、大数据应用场景2.1.1、Flume集成2.1.2、Spark集成2.1.3、Flink集成 2.2、Java应用场景(SpringBoot集成) 三、Kafka常见问题3.1、Kafka都有哪些组件&#xff1f;3.2、分区副本AR, ISR, OSR的含义&#xff1f;3.3、Producer 消息重…

Flink Python作业快速入门

Flink Python快速入门_实时计算 Flink版(Flink)-阿里云帮助中心 import argparse # 用于处理命令行参数和选项&#xff0c;使程序能够接收用户通过命令行传递的参数 import logging import sysfrom pyflink.common import WatermarkStrategy, Encoder, Types from pyflink.data…

前端(五)css属性

css属性 文章目录 css属性一、字体属性二、文本属性三、背景属性四、盒子模型 一、字体属性 font-weight&#xff1a;文字粗细&#xff0c;在100到900之间&#xff0c;normal(400),bord(700),inherit(继承父类) font-style&#xff1a;文字风格&#xff0c;normal表示正常(默认…

nginx反向代理(负载均衡)和tomcat介绍

nginx的代理 负载均衡 负载均衡的算法 负载均衡的架构 基于ip的七层代理 upstream模块要写在http模块中 七层代理的调用要写在location模块中 轮询 加权轮询 最小连接数 ip_Hash URL_HASH 基于域名的七层代理 配置主机 给其余客户机配置域名 给所有机器做域名映射 四层代理…