简单文档编辑器
一、学习目标
l 参考系统的写字板功能,编写一个小型的文字编辑工具。
l 该文档编辑器,有以下功能:
①文件操作:新建,打开,保存,另存为,退出;
②编辑操作: 撤销,恢复,复制,剪切,粘贴,全选,清空;
③搜索:查找与替换;
④格式操作: 字体,颜色,粗体,斜体,下划线;
⑤支持快捷键操作
l 界面设计观,操作简便,有工具栏、右键菜单、状态栏。
二、设计思路
1)首先,是窗口的设计,一个好的UI界面,用户使用起来会更加方便快捷。把MainForm 的控件设计做好。菜单用MenuStrip,工具栏用ToolStrip,文本编辑框用RichTextBox,
状态栏用statusStrip,右键菜单用contextMenuStrip,保存文件对话框saveFileDialog,打开文件对话框openFileDialog。然后在Visual Studio C# 中把控件相应的属性设置好,比如Dock属性、filter属性、Font属性等。
菜单的图标在网上搜索或者截图。
菜单栏ToolStripMenuItem通过ShortCutKeys属性设置菜单的快捷键。
然后将SearchAndReplaceForm设计好。
2)文本的新建,打开,保存,另存为功能实现
首先文本的状态设置有2中,文档是否被修改isChanged和文档是否曾保存在文件中isSaved。
新建文件时
private void 新建ToolStripMenuItem_Click(object sender, EventArgs e)
{
AlertSaveFile(); // 提示用户保存文件
this.txtMain.Clear();//清空文本内容
this.isSaved = false;
this.saveStatus.Text = "未保存";
this.Text = "无标题 ---- Editor";
this.isChanged = false;
}
private bool AlertSaveFile() // 提示用户保存文件
{
if (isChanged) // 表示文档有改动并且未保存
{
DialogResult result =
MessageBox.Show(this, "存在文件尚未保存,要保存改动吗?", "文本编辑器", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning);
// 保存文档
if (result == DialogResult.Yes)
{
if (this.isSaved)
{
this.txtMain.SaveFile(FileName);
}
else
{
另存为toolStripMenuItem_Click(null, null);
}
}// 不保存文档
else if (result == DialogResult.No)
{
}// 取消
else
{
return false; // 表示点击取消
}
}
return true; // 表示点击其他
}
另存为时
private void 另存为toolStripMenuItem_Click(object sender, EventArgs e)
{
if (this.saveFileDialog2.ShowDialog() == DialogResult.OK)//保存文件确认
{
try
{
FileInfo finfo = new FileInfo(this.saveFileDialog2.FileName);//文件名
if (finfo.Extension == ".rtf")//若为rtf格式的文档
{
this.txtMain.SaveFile(finfo.FullName, RichTextBoxStreamType.RichText);
}
else//其他情况下的文档
{
this.txtMain.SaveFile(finfo.FullName, RichTextBoxStreamType.PlainText);
}
this.FileName = this.saveFileDialog2.FileName;
this.isSaved = true;//更改保存状态为已保存
this.saveStatus.Text = "已保存于" + DateTime.Now.ToShortTimeString();
this.isChanged = false;
this.Text = this.FileName;
文件打开是先要检查当前文本是否已经有改动,若有改动要询问用户是否保存,其他情况类似上面讲的。
文件保存和另存为类似,如果已经保存过了,就直接写入当前文件,如果没有保存过,就调用另存为的功能。
3)文本编辑的复制,剪切,粘贴,全选,清空,这些操作的对象都是RichTextBox中的文本,调用相应的函数就可以了。
复制 this.txtMain.Copy();
剪切 this.txtMain.Cut();
粘贴 this.txtMain.Paste();
全选 this.txtMain.SelectAll();
清空 this.txtMain.Text = "";
4)查找与替换
初始化是指定父窗口
public SearchAndReplaceForm(MainForm parent)
{
InitializeComponent();
this.parentForm = parent;
}
文本框的作用范围由默认的private修改为public
public System.Windows.Forms.RichTextBox txtMain;
查找功能:SearchText(true);
这个方法,主要判断查找的方向、是否大小写匹配,关键语句是
//函数完成文本的查找功能,参数表示是否在未找到指定文本时显示消息,返回值为是否找到指定文本
private bool SearchText(bool isShowFound)
{
bool isFound = true;
if (this.caseCheckBox.Checked)// 表示大小写匹配查找
{
if (this.downRadioButton.Checked) // 表示向下查找
{
this.searchPos = this.parentForm.txtMain.Find(this.strSearch, searchPos,this.parentForm.txtMain.Text.Length, RichTextBoxFinds.MatchCase);
}
else
{
this.searchPos = this.parentForm.txtMain.Find(this.strSearch, 0,searchPos, RichTextBoxFinds.MatchCase | RichTextBoxFinds.Reverse);
}
}
else
{
if (this.downRadioButton.Checked)
{
this.searchPos = this.parentForm.txtMain.Find(this.strSearch, searchPos,this.parentForm.txtMain.Text.Length, RichTextBoxFinds.None);
}
else
{
this.searchPos = this.parentForm.txtMain.Find(this.strSearch, 0,searchPos, RichTextBoxFinds.Reverse);
}
}
if (this.searchPos < 0)//如果未找到,则显示信息,将上次查找位置复原,置标志位为未找到
{
if (isShowFound)
{
MessageBox.Show("已完成对文档的搜索,未找到搜索项", "Editor", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
this.searchPos = this.lastSearchPos;
isFound = false;
}
else
{
if (this.downRadioButton.Checked)
{
this.searchPos += this.strSearch.Length;
}
else
{
this.searchPos -= this.strSearch.Length;
}
this.parentForm.Focus();// 使主窗体获得焦点
}
this.lastSearchPos = this.searchPos;
return isFound;
}
替换功能,如果替换的字符串为空,替换和替换全部的按键不可点
private void replaceAllButton_Click(object sender, EventArgs e)
{
this.strSearch = this.searchText.Text;//搜索文字
this.strReplace = this.replaceText.Text;//替换文字
while (SearchText(false))//直到没有匹配内容
{
if (this.parentForm.txtMain.SelectedText.Length > 0)//如果找到位子
{
this.parentForm.txtMain.SelectedText = this.strReplace;//替换操作
}
}
}
5)格式操作: 字体,颜色
这些操作大同小异,先判断选中的文本,在进行相应操作
private void 颜色ToolStripMenuItem_Click(object sender, EventArgs e)
{
this.colorDialog1.Color = this.txtMain.SelectionColor;
if (this.colorDialog1.ShowDialog(this) == DialogResult.OK)
{
this.txtMain.SelectionColor = this.colorDialog1.Color;
}
this.isChanged = true;
}
至于下拉菜单中改变字体的功能,先要获取系统的字体集合并加入到Items中
private void MainForm_Load(object sender, EventArgs e)
{
//获得系统字体列表
InstalledFontCollection fonts = new InstalledFontCollection();
foreach (FontFamily family in fonts.Families)
{
fontFamilyToolStripComboBox.Items.Add(family.Name);
}
}
。
6)工具栏中文本操作:粗体,斜体,下划线
粗体,斜体,下划线操作先要保存本来的字体属性,再在这个基础上添加相应的效果。关键代码如下:
int selectionStart = this.txtMain.SelectionStart;
int lastEdit = selectionStart + this.txtMain.SelectionLength;
bool flag = true;
for (int i = selectionStart; i < lastEdit; i++)
{
this.txtMain.Select(i, 1);
this.txtMain.SelectionFont = new System.Drawing.Font(this.txtMain.SelectionFont.FontFamily.Name, this.txtMain.SelectionFont.Size, this.txtMain.SelectionFont.Style ^ FontStyle.Bold);
if (!this.txtMain.SelectionFont.Bold)
{
flag = false;
}
}
this.boldButton.Checked = flag;
this.txtMain.Select(selectionStart, lastEdit - selectionStart);
文本对其功能这块,注意的是根据鼠标所指文本的当前状态来确定窗口中,那三个对应的按键是否为Checked,随时替换状态;鼠标所指位置文本状态的确定,通过这个文本框事件。
private void txtMain_SelectionChanged(object sender, EventArgs e)
{
this.cursor();
}
7)附加功能,编辑器背景色,字数统计
改变背景色只需要把选中的颜色改变编辑框的BackColor 即可实现
this.txtMain.BackColor = this.colorDialog1.Color;
字数统计这个功能是仿照WPS的,不过不是很完善。
private void 字数统计ToolStripMenuItem_Click(object sender, EventArgs e)
{
int totalNum = 0;
string[] strArray = this.txtMain.Text.Split(" \t\n\0".ToCharArray());
foreach (string str in strArray)
{
totalNum += str.Length;
}
MessageBox.Show(this, string.Concat(new object[] { "当前编辑文件:\n", this.fileName, "\n字符数(计空格) ", this.txtMain.TextLength, "\n字符数(不计空格) ", totalNum, "\n" }), "字数统计", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
三、个人总结
这个简易文本编辑器使用C#语言写的,在这个过程中遇到了各种问题。首先,是获取系统字体的问题。需要经过查询InstalledFontCollection 中获取系统字体,再取出系统字体的family就可以了。然后是保存时的默认格式,我想编辑为rtf(富文本)格式,可是却出现了一些我无法解决的问题,但是不影响整个程序的运行。在做查找和替换那块时,将替换全部和替换部分的事件写反了,查找了比较久才发现问题所在,命名又相近不好查错,花了好多时间。
通过本次试验,我感觉受益匪浅,也提醒了自己要心细一些。
浙公网安备 33010602011771号