【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本

经过了之前大量mfc已经明白了许多功能,但是之前的项目一直没有使用到mfc的菜单功能,菜单是Win32功能很常见的东西,这个也必须要懂。其实菜单的建立也很简单,配合之前的文件操作功能,已经能够把开始->附件->记事本,就是那个notepad.exe写出来了。


一、基本目标

首先,这个记事本能够最大化,最小化,里面的编辑框也能够跟住最大化最小化,就是记事本里面组件不会失真,这个也不是理所当然的时候,要对OnSize进行写作,否则里面的组件是不会跟着最大化的,这大概就是mfc比vb艰难的原因吧!


之后,这个记事本的窗体大小与平常Windows的窗口一样,能够自由调整大小,里面有相应的餐单。按帮助->关于,能够显示版权信息。其实这里已经把记事本模仿得很像了,要不是那个版权信息太丑的话~

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第1张图片

点击“新建”按钮会弹出提示框,告诉用户如果继续执行这个命令,所有没有保存的信息会丢失,如果用户点“是”,则新建一个文件

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第2张图片

之后是打开与保存、另存为功能,这里就不再介绍是什么样了,如下图,就是跟你平常用的记事本一模一样

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第3张图片

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第4张图片

最后是设置字体功能,能够设置记事本显示的字体,这与Windows里面的记事本是一模一样,毕竟记事本从头到尾都是一个纯文本的编辑器,设计字体只是设置其显示字体而已!用户选择相应的字体之后,记事本里面的字体就会以用户选择的字体显示。



二、准备过程

1、首先还是新建一个简单的mfc工程,里面什么都没有,我们之后再添加,主要是windows自带的东西太渣了,我们自己写出来更加漂亮。如果你连mfc的创建都不会,也没有关系,可以看我之前的文章


2、新建出来的工程与之前的《【mfc】用对话框的切换实现重新登录》(点击打开链接)一样,把确定按钮的OnOk函数注释掉,免得这个对话框一按回车就没有

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第5张图片

3、之后把对话框里面的组件拉成如下图的形式,同时把各个组件的样式设置好:

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第6张图片

4、之后,我们就开始为这个对话框建立菜单,如下图,为这个工程插入资源,如《【mfc】对于对话框程序的优化与为程序创建图标》(点击打开链接)中的图标一样,菜单也是资源的一种,只是菜单的编辑方式不同而已。


5、菜单的编辑如下图所示,里面还有“分隔符”选项,如果一点分隔符,组件中的所有东西都会变灰,系统自动识别这是“分隔符”而不是一个有功能的子菜单

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第7张图片

6、长按一个子菜单拖拽可以改变子菜单的位置


7、按照上面的方式,建立如下图的菜单,然后切换的主对话框CxxDlg,其中xx为你的工程名,在这个主对话框中的样式添加菜单

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第8张图片

8、之后,如下图为各个菜单中添加相应的类函数

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第9张图片

9、把这个菜单的子菜单的消息映射函数与对话框关联起来,则设置其函数名,最后才能添加函数

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第10张图片

10、对子菜单创建完消息映射函数则与组件的函数一样,能够在ClassView看到,当然,双击ClassView里面的函数也一样能够编辑,为所有子菜单,也就是那些"新建"、"打开"……添加完消息映射函数,我们则可以正式进行程序的写作。



三、各个子菜单的功能制作

虽然上面的准备功能很多,但是之后的函数就很简单,组件的布局完毕,之后写一些简短的函数就完成了,这就是微软旗下的编程的特点,它不像java中的Swing,单单是布局都要写一大堆代码。现在做微软编程的人看不起写Java的,说写一大段然后才能实现一个功能,写java看不起写微软的,说是拖控件的,谁也看不起谁。其实,无知者才是最可怕的,各有各特点,控件你不懂也不拖,代码你不懂你才觉得写一大段才能实现自己的功能,主要是自己废,不关人家编程语言的事情。你两方面都懂才是王道。好了,废话不多说了,回到这个功能里面来。


(一)编辑框的大小随同窗口的大小变化而变化

1、首先你要为这个主功能添加一个窗口消息处理函数,在里面找到WM_SIZE添加,这个与《【mfc】利用文件的读写,theApp全局变量来现实登录帐号管理系统》(点击打开链接)中添加OnInitDialog与OnDestory一样。不多说了,不明白可以翻翻我之前的日志。

【mfc】利用到MFC菜单、字体对话框、OnSize函数实现简易记事本_第11张图片

2、之后对这个OnSize函数写上如下代码,这个函数主要是对用户调整窗口大小时做出的响应,包括最大化,但不包括最小化。最小化的功能系统自己就能够实现,但是它会把自身的窗口坐标变成负数,导致下面基于窗口尺寸的控件大小,出现负值,程序就崩溃。所以正确的做法是,一旦窗口的坐标变成负数,就不要执行这段代码。

void CNotepadDlg::OnSize(UINT nType, int cx, int cy) 
{
	CDialog::OnSize(nType, cx, cy);
	//最小化以后,控件的窗口坐标值都会变成负数,再还原,此时,lastwindowrect为负,
	//需要你把下面的代码进行判断,否则程序会出错
	if(nType!=SIZE_MINIMIZED){
		CWnd *pWnd; 
		//获取ID为i的空间的句柄
		pWnd = GetDlgItem(IDC_EDIT1);
		CRect rect;   //获取控件变化前的大小
		//判断是否为空,因为对话框创建时会调用此函数,而当时控件还未创建
		if(pWnd){
			pWnd->GetWindowRect(&rect);
			ScreenToClient(&rect);//将控件大小转换为在对话框中的区域坐标
			//cx/m_rect.Width()为对话框在横向的变化比例
			//cy/m_rect.Height()为对话框在纵向的变化比例
			rect.left=rect.left*cx/rect.Width();//调整控件大小
			rect.right=rect.right*cx/rect.Width();
			rect.top=rect.top*cy/rect.Height();
			rect.bottom=rect.bottom*cy/rect.Height();
			pWnd->MoveWindow(rect);//设置控件大小		
		}
		GetClientRect(&rect);//将变化后的对话框大小替换旧大小
	}
}

(二)版权信息

这个就不多说,这个与《【mfc】利用文件的读写,theApp全局变量来现实登录帐号管理系统》(点击打开链接)中也多个对话框中切换一模一样,先画好CopyrightDlg这个对话框,再为这个对话框新建类向导,然后因为CopyrightDlg除了显示与自带的关闭功能以外没有任何功能,CopyrightDlg完全不用写东西,只需要在主函数里面的“帮助”->“关于...”类函数,引入头文件,写入打开“关于……”对话框的代码即可

#include "CopyrightDlg.h"

void CNotepadDlg::OnCopyright() 
{
	// TODO: Add your command handler code here
	CCopyrightDlg dlg;
	dlg.DoModal();
	
}


之后的代码都涉及到文件操作,所以首先在notepadDlg.cpp这个文件的开头,也就是包含一堆子菜单这个cpp的开头,引入CString filename;这个全局变量,就在#endif这行系统自带的代码的下方,让"新建"、“打开”、"保存"等命名共享这个文件变量,因为这里仅有一个对话框,所以也没必要大题小做地,如《【mfc】使用系统文件对话框打开文件与保存文件、利用StdAfx.h设置全局变量》( 点击打开链接),把变量写到StdAfx.h里面,又不用多个对话框共享这个变量。


(三)文件->新建

代码如下,很简单:

void CNotepadDlg::OnFileNew() 
{
	// TODO: Add your command handler code here
	if(IDNO==MessageBox("所有没有保存的信息,将会丢失,是否继续?","记事本",MB_YESNO))
		return;
	SetDlgItemText(IDC_EDIT1,"");
	SetWindowText("记事本");
	filename="";

}

首先弹窗提示用户是否继续,然后把文本框、标题栏、操作的文件路径清空即可。


(四)文件->打开

这个有点难,虽然基本原理与《【mfc】使用系统文件对话框打开文件与保存文件、利用StdAfx.h设置全局变量》(点击打开链接)一样,但是这里是对编辑框进行操作,而不是列表空间,因此,你首先要把文件的所有内容读入一个字符数组里面,再读到编辑框里面。注意打开文件之后,把标题栏、当前控制文件的路径更新一样。

void CNotepadDlg::OnFileOpen() 
{
	if(IDNO==MessageBox("所有没有保存的信息,将会丢失,是否继续?","记事本",MB_YESNO))
		return;
	CFileDialog dlg(TRUE,"txt","",OFN_HIDEREADONLY,"文本文件(*.txt)|*.txt||");
	if(IDCANCEL==dlg.DoModal()){
		return;
	}
	filename=dlg.GetPathName();	
	SetWindowText(filename);
	CFile file;
	if(!file.Open(filename,CFile::modeRead|CFile::shareDenyNone)){
		AfxMessageBox("打开文件失败");
		return;
	}
	//读取要打开文件的大小
	//然后根据打开文件的大小创建一个相应大小的字符数组	
	CFileStatus stat;
	file.GetStatus(stat);
	//+1是因为我们要对这个字符数组,后补\0
	char *pText=new char[stat.m_size+1];
	//file.Read的返回值是读到的文件大小
	int nRet=file.Read(pText,stat.m_size);
	pText[nRet]='\0';
	//把读出来的东西放到文本框里面,然后删除这个字符串数组
	SetDlgItemText(IDC_EDIT1,pText);
	delete []pText;
	file.Close();	
}

(五)文件->保存

首先读取当前控制的文件路径,也就是定义在开头的那个filename,如果读不了,证明用户还没有打开文件,就选择“保存”按钮,直接拖去“另存为”的处理,使用一个CString作为编辑框的内容与文件的过渡,把这个CString的内容写入文件,就完事了。

void CNotepadDlg::OnFileSave() 
{
	// TODO: Add your command handler code here
	CFile file;
	if(!file.Open(filename,CFile::modeCreate|CFile::modeWrite)){
		CNotepadDlg::OnFileSaveas();
		return;
	}
	CString string;
	GetDlgItemText(IDC_EDIT1,string);
	file.Write(string,string.GetLength());
	file.Close();
}

(六)文件->另存为

你自然要弹出一个“另存为”的CFileDialog给用户爽吧,然后这个通过CFileDialog,如《【mfc】使用系统文件对话框打开文件与保存文件、利用StdAfx.h设置全局变量》(点击打开链接)一样获取到文件路径,然如上面“保存”那样对文件进行写入操作。注意这里还要更新一下标题栏。

void CNotepadDlg::OnFileSaveas() 
{
	// TODO: Add your command handler code here
	CFileDialog dlg(FALSE,"txt","",OFN_OVERWRITEPROMPT,"文本文件(*.txt)|*.txt||");
	if(IDCANCEL==dlg.DoModal()){
		return;
	}
	CFile file;
	filename=dlg.GetPathName();	
	if(!file.Open(filename,CFile::modeCreate|CFile::modeWrite)){
		AfxMessageBox("保存文件失败");
		return;
	}	
	CString string;
	GetDlgItemText(IDC_EDIT1,string);
	file.Write(string,string.GetLength());
	file.Close();
	SetWindowText(filename);
}

(七)格式->字体

主要是设置显示字体,为了使设置的字体的辉煌仅仅停留在OnFontSet这个函数那样段,这里,你还要在开头像写入CString filename;那样写入CFont font;之后,则如下面的代码所示

void CNotepadDlg::OnFontSet() 
{
	// TODO: Add your command handler code here
	
	//lf是指向字体的指针
	LOGFONT lf={0};
	//如果现在已经存在字体了,那么获取当前字体的信息
	if(font.GetSafeHandle()){
		font.GetLogFont(&lf);
	}
	//字体设置需要到系统的字体编辑对话框,里面的参数是lf所指向的字体
	//一打开字体编辑对话框自动选中这个字体
	CFontDialog dlg(&lf);
	if(IDCANCEL==dlg.DoModal()){
		return;
	}
	//这样就能获取到,用户选中的字体保存到名为font的CFont对象中
	//其中CFont font;已经在本文件的文件开头就定义成本cpp的全局变量了	
	dlg.GetCurrentFont(&lf);
	font.DeleteObject();
	font.CreateFontIndirect(&lf);
	//取出操作文字输入框的句柄m_edit,以后m_edit就是操作这个对话框的句柄
	CEdit* m_edit=(CEdit*)GetDlgItem(IDC_EDIT1);
	m_edit->SetFont(&font);
}

四、总结与展望

至此,整个高仿记事本就制作完毕了。当然,还有“编辑”中的撤销功能,这个估计要设计一个链表记录用户的操作,剪切、复制、粘贴设计MFC中的对剪切板ClipBoard.exe的操作,估计应该有自带的函数,还没有研究。查找与替换与CFileDialog、CFontDialog一样,有自带的对话框,利用这个对话框获取到用户输入的内容,把当前编辑框的文本拿个CString存起来,再进行C语言那样的对CString进行遍历,查找与替换的操作……

你可能感兴趣的:(mfc,字体,菜单,对话框,记事本)