本文内容
用C#语言实现简易记事本(代码)。
思路分析
功能需求
参照win10的记事本,此次实现的简易记事本应当具有如下菜单控件:
各分类下又包括:
实现顺序
考虑到即使是简易的记事本需要实现的功能也较多,所以可以采取先实现记事本(界面)框架,再逐步填充逻辑代码的顺序完成任务。
这样做的好处是可以对照界面完善代码,不容易产生遗漏。
具体实现
界面设计
实际上对win10自带的记事本界面略作修改,即可成为此次界面的模板。接下来所需要做的,就是将已有的界面逆向还原成C#中的各个组件。
先新建一个windows窗体应用程序,再将右下角属性中的text 修改为“记事本”,这样,最大的外边框就实现了。
MenuStrip(菜单控件)
这一步实现各菜单选项。
先在工具箱中找到menustrip并拖动到窗体中,并将右下角属性中的Name修改为“mnusNotepad”(注:这里修改Name是为了方便后续操控,Name可自由定义,下同)。
下面要做的就是将上图中的各控件一一填入menustrip中。
看上去内容较多且存在差异,但操作方法基本相同。单击menustrip输入【文件(&F)】、【编辑(&E)】、【格式(&O)】、【查看(&V)】和【帮助(&H)】,其中“&”作用为实现字母下面那条下划线。输入完成后,实际完成的是一级菜单,也就是图中“记事本”下第一行水平的菜单。
这时,还应该继续点击一级分类菜单,输入二层菜单(也就是图中的下拉框的部分)。以“文件”下的二级菜单为例,点击“文件”,分别输入:新建(&N)、打开(&O)、保存(&S)、另存为(&A)、输入“-”可生成分割横线以及退出(&X)。
下图为具体属性:
依次点击各控件修改属性即可。
至此菜单栏框架设置完成。
ToolStrip(工具栏控件)(不建议添加)
在工具箱中找到“ToolStrip”并拖动到窗体中,在属中修改Name为“tlsNotepad”。
再右击工具栏,选择插入标准项,可完成图形布置。
实现效果如图。但现在的记事本中实际上没有该工具栏,而且该工具栏也影响整体美观,功能重复,所以不建议在程序中添加。
RichTextBox(多格式文本框控件)
仍然是在工具箱中先找到“RichTextBox”,再拖动到窗体中,并在属性中修改Name为“rtxtNotepad”。
这里还要将Anchor属性选择为“Top,Bottom,Left,Right”,这样当窗体大小改变时,RichTextBox控件的大小才会跟着改变。
这里实现的文本框就是图中白色的部分,用来在其中编辑文字。
StatusStrip(状态栏控件)
先添加StatusStrip控件,将其Name属性设为“stsNotepad”,再将Dock属性设为“Bottom”再将Anchor属性设为“Bottom,Left,Right”。实际上,这里Anchor属性最终会自动变为“Top, Left”。
这个设置也是为了在框体大小发生改变时,底部的状态栏能随之变化。
再右键打开【项集合编辑器】对话框,下拉列表中保留默认的选择“StatusLabel”,然后单击【添加】按钮,依次添加2个StatusLabel,并分别命名为“tssLbl1”和“tssLbl2”,再将tssLbl1的Text属性设为“就绪”, tssLbl2的Text属性设为“显示日期、时间”。
这里如果要实现图中的效果,需要进一步设置2个StatusLabel的padding或margin属性值。在默认情况下,2个StatusLabel相互贴靠。还有一点需要注意的是,“显示日期、时间”实际上是为后续的时间显示充当占位符。
各对话框
OpenFileDialog(打开对话框)
从工具箱中找到OpenFileDialog直接拖入窗体中 单击属性
当用户单击记事本的【文件】→【打开】菜单项时,使用打开对话框OpenFileDialog打开文件。OpenFileDialog控件的Name属性为“odlgNotepad”,Filter属性设为“RTF文件|.rtf|所有文件|.*”。
SaveFileDialog(保存对话框)
从工具箱中找到SaveFileDialog直接拖入窗体中 单击属性
当用户单击记事本的【文件】→【保存】(或【另存为】)菜单项时,使用保存对话框SaveFileDialog保存文件。SaveFileDialog控件的Name属性为“sdlgNotepad”,FileName属性改为“无标题”,Filter属性设为“RTF文件|*.rtf”。
FontDialog(字体对话框)
从工具箱中找到FontDialog直接拖入窗体中 单击属性
当用户单击记事本的【格式】→【字体】菜单项时,使用字体对话框FontDialog设置文本字体。FontDialog控件的Name属性为“fdlgNotepad”。
Timer(计时器控件)
从工具箱中找到Timer直接拖入窗体中 单击属性
本章介绍的记事本在状态栏中显示了时钟,这就需要使用一个Timer控件来实现。Timer控件的Name属性设为“tmrNotepad”,Enabled(激活的可行的)属性设为“True”,Interval(间隔,间距,幕间时间)属性设为“1000”,表示1秒种触发一次Tick事件,即1秒钟改变一次时钟。
关于记事本
单击vs【项目】的【添加Windows窗体】菜单项,添加一个名为“frmAbout”的窗体,并给窗体“frmAbout”添加几个Label、Button、LinkLabel和PictrueBox控件,按照下图信息设置好属性。
完成后应有如下各控件显示:
至此用户界面设计完毕。
逻辑代码
首先,在代码中的通用段声明以下两个布尔型的公共变量,“b”用于判断文件是新建的还是从磁盘打开的,“s”用于判断文件是否被保存。再分别完成多格式文本框(rtxtNotepad)、菜单(mnusNotepad)、工具栏(tlsNotepad)、计时器(tmrNotepad)对象的逻辑代码。
由于篇幅关系,此处不做一一讲解,Gitee源代码中包含注解。在这里选取“新建”功能的程序进行补充解释。
private void tsmiNew_Click(object sender, EventArgs e)
{
// 判断当前文件是否从磁盘打开,或者新建时文档不为空,并且文件未被保存
if (b == true || rtxtNotepad.Text.Trim() != "")
{
// 若文件未保存
if (s == false)
{
string result;
result = MessageBox.Show("文件尚未保存,是否保存?",
"保存文件", MessageBoxButtons.YesNoCancel).ToString();
switch (result)
{
case "Yes":
// 若文件是从磁盘打开的
if (b == true)
{
// 按文件打开的路径保存文件
rtxtNotepad.SaveFile(odlgNotepad.FileName);
}
// 若文件不是从磁盘打开的
else if (sdlgNotepad.ShowDialog() == DialogResult.OK)
{
rtxtNotepad.SaveFile(sdlgNotepad.FileName);
}
s = true;
rtxtNotepad.Text = "";
break;
case "No":
b = false;
rtxtNotepad.Text = "";
break;
}
}
}
}
复制代码
事实上,该段代码将“新建”的功能已基本完成,但存在一个小bug。代码中着重考虑了“新建时文档不为空,并且文件未被保存”的情况。
如果此时是在刚打开并输入文字的情况下,不会出现什么问题。但是如果此时是在先点击“打开”,编辑原本已有的rtf文件并保存后(或不做编辑),再点击“新建”的情况下,代码执行的效果就不尽如人意了:程序并不会生成一个新的文本框供用户编辑,用户操作的仍是先前已打开的源文件。
对前后代码稍作分析可以知道,由于“保存”与“另存为”命令最后都会将变量s置为true,那么在打开一个已保存的文件后,“打开”命令的代码并不会满足if (s == false)
这一条件,所以这整段代码并不会执行,也就不会有新的文本框生成了。
对这个bug的修改也不难,只需要补上s == true
时的情况即可。
private void tsmiNew_Click(object sender, EventArgs e)
{
// 判断当前文件是否从磁盘打开,或者新建时文档不为空,并且文件未被保存
if (b == true || rtxtNotepad.Text.Trim() != "")
{
// 若文件未保存
if (s == false)
{
string result;
result = MessageBox.Show("文件尚未保存,是否保存?",
"保存文件", MessageBoxButtons.YesNoCancel).ToString();
switch (result)
{
case "Yes":
// 若文件是从磁盘打开的
if (b == true)
{
// 按文件打开的路径保存文件
rtxtNotepad.SaveFile(odlgNotepad.FileName);
}
// 若文件不是从磁盘打开的
else if (sdlgNotepad.ShowDialog() == DialogResult.OK)
{
rtxtNotepad.SaveFile(sdlgNotepad.FileName);
}
s = true;
rtxtNotepad.Text = "";
break;
case "No":
b = false;
rtxtNotepad.Text = "";
break;
}
}
else
{
rtxtNotepad.Text = "";
b = false;
}
}
}
复制代码
可以看出,最后补上的else { rtxtNotepad.Text = ""; b = false; }
将s == true
时的情况考虑到了执行情况中,b = false;
表示该文件是新建的,rtxtNotepad.Text = "";
清空文本框,这样,就实现了新建一个文件的情况。
下面是部分执行情况:
以上就是本文的全部内容。