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

ops/2024/12/16 16:11:47/

一、功能目标:
  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.ppmy.cn/ops/142408.html

相关文章

L1-6 流量分析

1. 初步分析 数据包下载 流量分析基础篇 使用科来网络分析系统&#xff0c;打开L1-6.pcapng数据包&#xff0c;查看数据包中telnet和ftp的协议占的比例较大。 2. 找出黑客获取到的可成功登录目标服务器FTP的账号密码&#xff0c;并将黑客获取到的账号密码作为flag值(用户名与…

HCIA-Access V2.5_2_2_2网络通信基础_IP编址与路由

网络层数据封装 首先IP地址封装在网络层&#xff0c;它用于标识一台网络设备&#xff0c;其中IP地址分为两个部分&#xff0c;网络地址和主机地址&#xff0c;通过我们采用点分十进制的形式进行表示。 IP地址分类 对IP地址而言&#xff0c;它细分为五类&#xff0c;A,B,C,D,E,…

JAVA入门:文件管理

JAVA入门:文件管理 在学习java之前,首先学习一下java的文件管理,以便后续更好地学习。 创建一个空项目 点击右上角File->New->Module 创建新模块 配置工程环境 点击File->Project Structure 选择project&#

智尚招聘求职小程序V1.0.18

微信小程序招聘管理系统。支持多城市、人才版块、招聘会、职场资讯、经纪人入驻等功能。提供全部无加密源码&#xff0c;支持私有化部署。 V1.0.18增加功能与修复一些BUG 1、增加过审机制(后台系统设置里开启)2、增加后台经纪派遣人才管理3、优化前端经纪派遣人功能4、修复前…

大模型日报 2024-12-15

大模型日报 2024-12-15 大模型资讯 标题&#xff1a; KDD2025 | 多标签节点分类场景下&#xff0c;阿里安全&浙大对图神经网络增强发起挑战 摘要&#xff1a;本文介绍了阿里安全与浙江大学在多标签节点分类场景下的图神经网络增强技术的研究成果&#xff0c;论文《Correlat…

记录:VB6 直接获取 PictureBox 的图像数据到数组 GetDIBits

记得十几年前写几个游戏辅助工具的时候用过这个功能&#xff0c;这几天想直接把图片控件的数据转换为 PNG 文件不想用存出 BMP 文件交换&#xff0c;直接取得图像数据操作即可&#xff0c;但是忘记了当初是怎么做的了&#xff0c;找到个 2007 年的例子好像不太对&#xff0c;运…

前端使用pdf.js进行pdf文件预览的第二种方式:Viewer.html

背景 最近需要实现一个PDF文档预览的功能&#xff0c;按理说&#xff0c;如果只是简单的预览&#xff0c;使用<embed>、<object>等就可以实现。 但是&#xff0c;我们的需求要实现搜索&#xff01;而且&#xff0c;文档还都超大&#xff0c;均300页以上。那<e…

[图形渲染]【Unity】Shader基础10- 什么是Shader?

Shader 是图形渲染中用于控制特定渲染阶段行为的程序,运行在GPU上,可以高度自定义渲染细节。Shader 的诞生和发展使得现代渲染技术得以实现复杂的光影效果和高度真实感的画面。 1. Shader的定义与作用 Shader 是在图形渲染流水线的特定阶段运行的小程序,用于控制图形数据如…