TabText






3.60/5 (8投票s)
2006年7月10日
7分钟阅读

84692

1515
TabText 是一款带有标签页的文本编辑器,类似于 Excel。
引言
TabText
是一款带有标签页的文本编辑器,类似于 Excel。
该程序具有以下已在 Code Project 上发布的扩展功能:
- 在运行时将纯文本和图像插入 RichTextBox,作者:Khendys Gordon。
- 更丰富的 RichTextBox(第二部分),作者:Nikola Stepan
namespace Khendys.Controls
{
public class ExRichTextBox : RichTextBox
{
//code of Khendis Gordon
}
}
using Khendys.Controls;
namespace Nik.UserControls
{
public class RicherTextBox2 : ExRichTextBox
{
//code of Nikola Stepan
}
}
using Nik.UserControls;
namespace MicrosoftMSDN
{
public class RichTextBoxExt : RicherTextBox2
{
//Code of MSND
}
}
using MicrosoftMSDN;
namespace Compenkie
{
public class RichTextBoxExtend : RichTextBoxExt
{
//code of myself
}
}
TabText
扩展了以下功能:
- 标签页,方便您在文档之间切换。
- 为每个页面添加了
PageSetupDialog
的页面设置。 - 将所有页面序列化到一个文件中。
- 通过
ToolStripMenuItem
数组实现最近文件列表。 - 添加了一个简单的表格。该表格利用
RichTextBox
的功能,通过按 Enter 键来添加更多行。 - 添加了查找和替换功能,如 MSDN 库中所述。
- 通过图片面板插入表情符号。
- 通过上下文菜单插入文本片段。
- 帮助页面。
- 可更改语言的选项。
- 键盘状态。
- 将程序的设置保存在注册表中。
TabText
会创建一个文件夹,我的文档\\Compenkie\\TabText1,用于存储和加载数据文件。TabText
会创建一个注册表项,CurrentUser\\Compenkie\Tabext1,用于存储设置。
程序的构建结构如下:
Black = Form = TabText
Red = SplitContainer = splitContaimer
Bleu = TabControl = tabControl
Green = RichTextBoxExtended (left) = richTextBox
Green = RichTextBox (right) = richTextBoxPreview
richTextBoxPreview
仅用于预览文本片段。
标签页
页面以与设计器相同的方式动态创建。每个页面都添加了一个 RichTextBox,类型为 RichTextBoxExtended
。
public RichTextBoxExtend[] richTextBox = new RichTextBoxExtend[17];
for (int teller = 0; teller < 17; teller++)
{
richTextBox[teller] = new RichTextBoxExtend();
//
// richTextBox1
//
richTextBox[teller].AcceptsTab = true;
richTextBox[teller].Dock = System.Windows.Forms.DockStyle.Fill;
richTextBox[teller].Location = new System.Drawing.Point(3, 3);
richTextBox[teller].Name = "richTextBox" + teller.ToString();
richTextBox[teller].Size = new System.Drawing.Size(397, 380);
richTextBox[teller].TabIndex = teller;
richTextBox[teller].TabStop = true;
richTextBox[teller].Text = "";
richTextBox[teller].SelectionChanged +=
new EventHandler(TabText_SelectionChanged);
richTextBox[teller].CursorPositionChanged +=
new EventHandler(TabText_CursorPositionChanged);
richTextBox[teller].AllowDrop = false;
richTextBox[teller].DragDrop += new DragEventHandler(TabText_DragDrop);
richTextBox[teller].DragEnter += new DragEventHandler(TabText_DragEnter);
}
TabPage[] tabPages = new TabPage[17];
public void AddPage(int pagenummer)
{
// tabPage
//
tabPages[pagenummer] = new TabPage();
tabPages[pagenummer].Location = new System.Drawing.Point(4, 22);
tabPages[pagenummer].Name = "tabPage" + pagenummer.ToString();
tabPages[pagenummer].Padding = new System.Windows.Forms.Padding(3);
tabPages[pagenummer].Size = new System.Drawing.Size(403, 386);
tabPages[pagenummer].TabIndex = pagenummer;
tabPages[pagenummer].MouseHover += new EventHandler(TabText_MouseHover);
tabPages[pagenummer].MouseLeave += new EventHandler(TabText_MouseLeave);
tabPages[pagenummer].ToolTipText = "Dubbelklikken voor wijzigen naam tab";
tabPages[pagenummer].Text = "tabPage" + pagenummer.ToString();
tabPages[pagenummer].Tag = documentDir + "\\" +
tabPages[pagenummer].Text + ".rtf";
tabPages[pagenummer].UseVisualStyleBackColor = true;
tabPages[pagenummer].Controls.Add(richTextBox[pagenummer]);
tabControl.Controls.Add(tabPages[pagenummer]);
tabPages[pagenummer].SuspendLayout();
tabPages[pagenummer].ResumeLayout(false);
int aantal = tabControl.Controls.Count;
tabControl.SelectedIndex = aantal - 1;
this.Text = "TabText - " + tabPages[pagenummer].Text;
}
页面命名为“TapPage0”、“Tabpage1”等。标签页的 Text
属性中包含文件名。标签页的 Tag
属性中包含文件的完整路径。双击标签页会弹出一个文本框,您可以在其中更改文件名。RichTextBox 关闭 DockStyle.Fill
,以便您可以在选项卡控件顶部留出空间来显示 TextBox
。
private void tabControl_DoubleClick(object sender, EventArgs e)
{
TabControl conTrol = (TabControl)sender;
index = conTrol.SelectedIndex;
richTextBox[index].Dock = DockStyle.None;
richTextBox[index].Location = new Point(0, 25);
richTextBox[index].Size = new Size(this.Size.Width, Size.Height - 25);
box = new TextBox();
box.Leave += new System.EventHandler(this.box_Leave);
box.Text = tabPages[index].Text.ToString();
tabPages[index].Controls.Add(box);
box.Show();
box.Focus();
}
当焦点离开文本框时,名称将添加到标签页的文本中。如果不提供扩展名,将自动添加标准扩展名 rtf。文件的完整名称将添加到选项卡控件的 Tag
属性中。
private void box_Leave(object sender, EventArgs e)
{
TextBox box = (TextBox)sender;
tabPages[index].Text = box.Text.ToString();
if (Path.GetExtension(tabPages[index].Text.ToString()) == "")
tabPages[index].Tag = documentDir + "\\" +
tabPages[index].Text + ".rtf";
else
tabPages[index].Tag = documentDir + "\\" + tabPages[index].Text;
box.Hide();
richTextBox[index].Dock = DockStyle.Fill;
}
加载文件
LoadFile
将通过以下方式访问:
- 菜单项 加载。
- 最近文件菜单项 加载。
Modified
属性最初设置为 false
。通过编辑 RichTextBox,该属性变为 true
。这将在保存例程中使用。文件的完整名称将存储在 Tag
属性中,并且文件将被添加到最近文件列表中。如果已存在,则先移除再添加。如果扩展名为 RTF,则按 RTF 文件加载,否则按文本文件加载。
private void loadFile(string fileName)
{
TabPage tab = tabControl.SelectedTab;
try
{
int index = ZoekTab();
string extentie = Path.GetExtension(fileName);
if (extentie == ".rtf")
richTextBox[index].LoadFile(fileName,
RichTextBoxStreamType.RichText);
else
richTextBox[index].LoadFile(fileName,
RichTextBoxStreamType.PlainText);
richTextBox[index].Modified = false;
tab.Tag = fileName; ;
tab.Text = Path.GetFileName(fileName);
this.Text = "TabText - " + tab.Text;
// add successfully opened file to recent file list
removeRecentFile(fileName);
addRecentFile(fileName);
}
catch (IOException ex)
{
removeRecentFile(fileName);
Trace.WriteLine(ex.Message, "Error loading from file");
}
}
保存文件
文件通常保存为 TXT 或 RTF,具体取决于文件名扩展名。默认是“rtf”。如果文件被修改,系统会询问您是否要保存。
private void saveFile(TabPage tab)
{
int index = ZoekTab();
if (richTextBox[index].Modified == true)
{
string messageString = "Save file " + tab.Text.ToString() + "?";
if (MessageBox.Show(messageString, "TabText1",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
string directorie = Path.GetDirectoryName(tab.Tag.ToString());
if (Directory.Exists(directorie) == false)
Directory.CreateDirectory(directorie);
string extentie = Path.GetExtension(tab.Tag.ToString());
if (extentie == ".rtf")
richTextBox[index].SaveFile(tab.Tag.ToString(),
RichTextBoxStreamType.RichText);
else
richTextBox[index].SaveFile(tab.Tag.ToString(),
RichTextBoxStreamType.PlainText);
richTextBox[index].Modified = false;
}
}
addRecentFile(tab.Tag.ToString());
}
最近文件列表
最近文件列表是通过 ToolStripMenuItem
数组创建的。
private ToolStripMenuItem[] recentFiles = new ToolStripMenuItem[11];
int maxRecent;
变量 maxRecent
存储实际的最近文件数量。
在窗体的 Load
事件中,将填充数组。在 ToolTipText
属性中存储文件的路径,以便显示漂亮的工具提示。
RegistryKey key = Registry.CurrentUser.OpenSubKey(strRegKey +
"Recent File List\\");
if (key != null)
{
try
{
for (maxRecent = 0; maxRecent < 10; maxRecent++)
{
string sKey = "file" + maxRecent.ToString();
string longfileNaam = (string)key.GetValue(sKey, "");
if (longfileNaam.Length == 0)
break;
recentFiles[maxRecent].ToolTipText =
longfileNaam.ToString();
recentFiles[maxRecent].Text =
GetShortDisplayName(longfileNaam, 40);
}
}
catch (Exception ex)
{
Trace.WriteLine("Loading Recent Files" +
" from Registry failed: " + ex.Message);
}
key.Close();
}
if (recentFiles[0].Text != "")
loadFile(recentFiles[0].ToolTipText.ToString());
如果文件最初存在,它将被打开并创建一个标签页。
序列化
通过序列化,所有标签页都存储在一个文件中。将使用 BinaryFormatter
来存储数据类型。对于每个页面,我们将存储文件名和文件的完整路径名。还将为每个 TabPage
保存 PageSetupDialog
的页面设置。选中 RichTextBox 的全部内容后,保存内容。通过一个 for
循环,我们将保存所有页面。
private void serializeFileDialog_FileOk(object sender, CancelEventArgs e)
{
sbpMenu.Text = "Serialize alle pagina's";
Stream stream = File.Open(serializeFileDialog.FileName, FileMode.Create);
BinaryFormatter bformatter = new BinaryFormatter();
bformatter.Serialize(stream, maxTab);
for (int teller = 0; teller < maxTab; teller++)
{
bformatter.Serialize(stream, richTextBox[teller].printLandScape);
bformatter.Serialize(stream, richTextBox[teller].printMarginTop);
bformatter.Serialize(stream, richTextBox[teller].printMarginLeft);
bformatter.Serialize(stream, richTextBox[teller].printMarginRight);
bformatter.Serialize(stream, richTextBox[teller].printMarginBottom);
bformatter.Serialize(stream, tabPages[teller].Text.ToString());
bformatter.Serialize(stream, tabPages[teller].Tag.ToString());
richTextBox[teller].SelectAll();
bformatter.Serialize(stream, richTextBox[teller].SelectedRtf);
richTextBox[teller].DeselectAll();
}
stream.Close();
sbpMenu.Text = "Gereed";
}
要从序列化文件中恢复页面,您必须按照与标签页序列化相同的顺序进行操作。我们首先保存现有的标签页,然后清空选项卡控件。加载标签页数量后,我们添加标签页数量,并清空 RichTextBox 的旧内容。当然,在加载 RichTextBox 计数之前,我们加载 PageSetupDialog
的页面设置以及文本和标签属性。
private void deserializeFileDialog_FileOk(object sender, CancelEventArgs e)
{
sbpMenu.Text = "Deserialize alle pagina's";
//Open the file written above and read values from it.
saveAll();
tabControl.TabPages.Clear();
Stream stream = File.Open(deserializeFileDialog.FileName, FileMode.Open);
BinaryFormatter bformatter = new BinaryFormatter();
maxTab = (int)bformatter.Deserialize(stream);
for (int teller = 0; teller < maxTab; teller++)
{
AddPage(teller);
richTextBox[teller].Clear();
richTextBox[teller].printLandScape =
(bool)bformatter.Deserialize(stream);
richTextBox[teller].printMarginTop =
(int)bformatter.Deserialize(stream);
richTextBox[teller].printMarginLeft =
(int)bformatter.Deserialize(stream);
richTextBox[teller].printMarginRight =
(int)bformatter.Deserialize(stream);
richTextBox[teller].printMarginBottom =
(int)bformatter.Deserialize(stream);
tabPages[teller].Text = bformatter.Deserialize(stream).ToString();
tabPages[teller].Tag = bformatter.Deserialize(stream).ToString();
richTextBox[teller].SelectedRtf =
bformatter.Deserialize(stream).ToString();
}
stream.Close();
sbpMenu.Text = "Gereed";
}
表情符号
我们可以添加小图片,这些图片可以从调色板中选择。
调色板是一个带有 PictureBox 的 Panel
。该 Panel
在窗体的 Load
事件中创建。图片文件在 Emotion_collector
中创建。序列化文件作为资源文件嵌入。文件将被加载到 MemoryStream
中。在“选项”框中,您可以选择从磁盘加载图片文件。
images = new ImageInfo[maxImage];
for (int teller = 0; teller < maxImage; teller++)
images[teller] = new ImageInfo();
使用 MemoryStream
从资源加载序列化文件,方式与在标签页中加载序列化文件相同。
// Load Emoticon Images
try
{
MemoryStream stream = new MemoryStream(Resources._default);
BinaryFormatter bformatter = new BinaryFormatter();
imageCounter = (int)bformatter.Deserialize(stream);
for (int teller = 0; teller < imageCounter; teller++)
{
string dummy = bformatter.Deserialize(stream).ToString();
dummy = bformatter.Deserialize(stream).ToString();
images[teller].img = (Image)bformatter.Deserialize(stream);
}
stream.Close();
}
catch (ArgumentException ex)
{
MessageBox.Show(ex.Message.ToString());
}
createImagePanel(images, imageCounter);
通过点击菜单项来显示图片面板。必须先隐藏调色板,因为如果双击菜单项会出现错误。
private void contextmenuemoticonsToolStripMenuItem_Click(object sender,
EventArgs e)
{
ToolStripMenuItem item = (ToolStripMenuItem)sender;
EventArgs args = (EventArgs)e;
if (showForm != null)
{
// first hide, you can not twice Show a form.
showForm.Hide();
showForm.Location = new Point(rectNormal.X + 200,
rectNormal.Y + 200);
showForm.Show();
}
else
MessageBox.Show("No Icons selectede");
}
通过点击 PictureBox
来添加图片。sender 对象包含 PictureBox
。
void box_MouseClick(object sender, MouseEventArgs e)
{
PictureBox box = (PictureBox)sender;
showForm.Hide();
int index = ZoekTab();
try
{
richTextBox[index].InsertImage(box.Image);
}
catch (Exception _e)
{
MessageBox.Show("Rtf Image Insert Error\n\n" +
_e.ToString());
}
}
文本片段
使用相同的方式,您可以插入文本片段。标准文本片段存储在 ToolStripMenuItem
数组中。我创建了四个日期项,并将这些项添加到一个上下文菜单中。通过点击菜单项来显示上下文菜单。
private void contextMenuToolStripMenuItem_Click(object sender, EventArgs e)
{
contextMenu_Text.Show(this, new Point(200, 200));
}
文本片段加载到菜单项的 Tag
属性中。如果文本是纯文本,则 bool
变量 standaard
为 true
。如果文本是 RTF 格式,则 standaard
为 false
。
DateTime time = DateTime.Now;
toolStripMenuDatumKort.Tag = time.ToShortDateString() + "\n";
toolStripMenuDatumLang.Tag = time.ToLongDateString() + "\n";
toolStripMenuTijdKort.Tag = time.ToShortTimeString() + "\n";
toolStripMenuTijdLang.Tag = time.ToLongTimeString() + "\n";
toolStripMenuDatumKort.ToolTipText =
time.ToShortDateString() + "\n";
toolStripMenuDatumLang.ToolTipText =
time.ToLongDateString() + "\n";
toolStripMenuTijdKort.ToolTipText =
time.ToShortTimeString() + "\n";
toolStripMenuTijdLang.ToolTipText =
time.ToLongTimeString() + "\n";
standaard = true;
当鼠标悬停在上下文菜单项上时,会显示一个预览窗口。在 TabText
的构造函数中,将 SplitterDistance
设置为等于分隔符的宽度。
splitContainer.SplitterDistance = splitContainer.Size.Width;
在 MouseHover
事件中,将 SplitterDistance
设置为宽度的三分之二,并显示预览窗口。
private void cmenu_Teksten_MouseHover(object sender, EventArgs e)
{
ToolStripMenuItem item = (ToolStripMenuItem)sender;
splitContainer.SplitterDistance = (splitContainer.Size.Width / 3) * 2;
richTextBoxPreview.Clear();
if (standaard)
richTextBoxPreview.AppendText(item.Tag.ToString());
else
richTextBoxPreview.AppendRtf(item.Tag.ToString());
}
当上下文菜单关闭时,预览窗口将随着上下文菜单的 Closed
事件而消失。
private void cmenu_Teksten_Closed(object sender,
ToolStripDropDownClosedEventArgs e)
{
splitContainer.SplitterDistance = splitContainer.Size.Width;
}
文本片段可以通过序列化标签页来创建。在“选项”框中,您可以选择并从磁盘加载文本片段文件。
帮助
用户可以通过三种方式获得帮助:
- 常规工具提示。
- 状态栏上的额外信息。
- 带有用户信息的标签页。
状态栏信息存储在菜单项的 Tag
属性中。当鼠标悬停在菜单项上时,会触发 MouseHover
事件,并在状态栏上显示信息。
private void toolStripMenuItem_MouseHover(object sender, EventArgs e)
{
ToolStripMenuItem menu = (ToolStripMenuItem)sender;
sbpMenu.Text = (string)menu.Tag;
}
当鼠标离开菜单项时,会触发 MouseLeave
事件并重置文本。
private void toolStripMenuItem_MouseLeave(object sender, EventArgs e)
{
sbpMenu.Text = "Ready";
}
在“帮助”菜单中,为用户提供帮助。点击“帮助”菜单中的“帮助”,分割容器将更改为一个带有标签页的选项卡控件。这里最重要的是添加帮助控件和菜单控件的顺序。
private void helpHelpToolStripMenuItem_Click(object sender, EventArgs e)
{
Controls.Remove(this.splitContainer);
Controls.Remove(this.comboStrip);
Controls.Remove(this.buttonStrip);
Controls.Remove(this.menuStrip);
Controls.Remove(this.statusStrip);
Controls.Add(helpControl);
Controls.Add(helpMenu);
}
点击帮助菜单的后退按钮将用分割容器替换帮助菜单。
public void backToolStripMenuItem_Click(object sender, EventArgs e)
{
Controls.Add(splitContainer);
Controls.Add(comboStrip);
Controls.Add(buttonStrip);
Controls.Add(menuStrip);
Controls.Add(statusStrip);
Controls.Remove(helpControl);
Controls.Remove(helpMenu);
}
帮助菜单控件声明为一个变量。您可以发现,它与反序列化的标签页完全相同,只是使用了内存流。
this.TabPages.Clear();
MemoryStream stream =new MemoryStream(Resources.HelpFile);
BinaryFormatter bformatter = new BinaryFormatter();
int maxTab = (int)bformatter.Deserialize(stream);
for (int teller = 0; teller < maxTab; teller++)
{
AddPage(teller);
richTextBox[teller].Clear();
tabPage[teller].Text = bformatter.Deserialize(stream).ToString();
tabPage[teller].Tag = bformatter.Deserialize(stream).ToString();
richTextBox[teller].SelectedRtf = bformatter.Deserialize(stream).ToString();
}
stream.Close();
更改语言
由于信息存储在 ToolStripMenuItem
的三个属性中,您可以轻松切换语言选项。
private void languagetoolStripComboBox_SelectedIndexChanged(object sender,
EventArgs e)
{
ToolStripComboBox box = (ToolStripComboBox)sender;
language = box.Text.ToString();
switch (box.Text)
{
case "Nederlands":
{
Nederlands();
break;
}
case "English":
{
English();
break;
}
}
}
English
函数的一部分如下:
void English()
{
// Menu Bestand
fileToolStripMenuItem.Text = "&File";
// New menu
newToolStripMenuItem.Tag = "Save the ecxist files, close " +
"all the tab-pages and" +
" make a new tab-page";
newToolStripMenuItem.Text = "&New";
newToolStripMenuItem.ToolTipText = "Make a new document";
....
newToolStripButton.Tag = newToolStripMenuItem.Tag.ToString();
newToolStripButton.ToolTipText =
newToolStripMenuItem.ToolTipText.ToString();
}
嵌入式资源
这里简要介绍如何将嵌入式资源添加到您的项目中。
- 根据需要创建标签页,输入文本并进行格式化。
- 将页面序列化为名为 HelpFile.srl 的文件。
- 通过在解决方案资源管理器中右键单击
TabText
,将文件添加到项目中。添加为现有项。 - 将文件 HelpFile.srl 的 Build Action 属性设置为 Embedded Resource。
- 在解决方案资源管理器中打开 Resources.resx。
- 添加资源 -> 添加现有文件,文件 HelpFile.srl。
- 现在您可以使用
Resources.HelpFile
来访问该文件。
键盘状态
要获取 Caps、Insert、ScrollLock 和 Numlock 键的状态,我们需要 Keyboard
类。该类在 Microsoft.VisualBasic.Devices
命名空间中可用。要使用此命名空间,您需要添加必要的引用。
- 转到解决方案资源管理器。
- 右键单击“引用”。
- 添加引用。
- 在 .NET 选项卡中选择“Microsoft.VisualBasic”项。
- 然后单击“确定”。
现在,您可以:
using Microsoft.VisualBasic.Devices;
并在 TabText
的构造函数中声明类:
public Keyboard board = new Keyboard();
在 TimerTick
事件中,可以读取状态:
private void TabText_TimerTick(object sender, EventArgs e)
{
DateTime dt = DateTime.Now;
sbpDate.Text = dt.ToShortDateString();
sbpTime.Text = dt.ToShortTimeString();
if (board.CapsLock)
sbpCapsKey.Text = "Caps on";
else
sbpCapsKey.Text = "Caps off";
if (board.NumLock)
sbpNumberKey.Text = "Num on";
else
sbpNumberKey.Text = "Num off";
if (board.ScrollLock)
sbpScrollLock.Text = "Scroll on";
else
sbpScrollLock.Text = "Scroll off";
int index = ZoekTab();
if (richTextBox[index].GetKeyStateInsert() == 1)
sbpInsert.Text = "Insert";
else
sbpInsert.Text = "Overwrite";
}
sbpDate
、sbpTime
、sbpCapsKey
、sbpNumberKey
、sbpScrollLock
和 sbpInsert
是状态栏上的标签。
但是 Keyboard
类没有 Insert 键的属性。因此,我们需要一个 API 函数,我将其放置在 RichTextBox
中。
[DllImportAttribute("user32.dll")]
private static extern uint GetKeyState(int keystate);
public uint GetKeyStateInsert()
{
return GetKeyState(45); // Keynumber InsertKey
}
注册程序
在窗体的 Load
函数中,程序的设置将从注册表中加载。在窗体的 Closed
事件中,设置将被保存在注册表中。
更多信息
- 在运行时将纯文本和图像插入 RichTextBox,作者:Khendys Gordon。
- 更丰富的 RichTextBox(第二部分),作者:Nikola Stepan。
- Microsoft MSDN: richtextboxprinting.exe
- 书籍:《使用 C# 编程 Microsoft Windows》,作者:Charles Petzold。