65.9K
CodeProject 正在变化。 阅读更多。
Home

The Wordinator - 创意写作者的文字处理器 - C#2022

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.96/5 (32投票s)

2019年9月24日

CPOL

50分钟阅读

viewsIcon

50228

downloadIcon

2156

在本文中,您将了解一款文字处理器,它利用了多个词典、弹出式定义和一个带有快速Sweep And Prune算法的交互式多按钮图片框。

 

第一部分我如何抓取Merriam-Webster词典

第二部分Merriam-Webster词典:HTML转RTF

压缩的词典文件 

更新 : 2024/09/24 10h08

引言

我是一名作家。我写作。大多数时候,我写软件,但偶尔,我需要转换一下速度,写一个故事,甚至一部小说。任何人都可以使用市面上销售的文字处理器,并且做得很好。我敢猜测,除了像我这样经济拮据的作者,很少有作者会自己构建和测试文字处理器。很少有人花费数周甚至数月将词典录入数据库以集成到他们的写作工具中,更没有人会发布文章,讲述他们如何抓取Merriam-Webster的网站来补充他们的黑客技能,并进行一些散文创作。

您今天在这里读到的就是这一切的结果。

观看一个简短的编辑视频 

观看另一个关于此项目的冗长视频

背景

想当年,在汤房(soup kitchens)无法免费使用WiFi的时候,网吧收费高昂才能让你看看信息高速公路的奇迹,而图书管理员在你老旧的CRT屏幕上工作一小时后就会让你安静下来,屏幕还在缓慢且拥挤地运行着,因此,抓取不存在的在线词典简直是天方夜谭。文字处理器可以进行拼写检查,但要获取定义却需要翻阅一本沉重的书,而面临被纸张割伤的危险。所以,如果你想让文字处理器包含一个词典,你可以要么把你的CD-ROM塞满你能负担得起的词典,然后在尝试不让你的30MHz 386崩溃的同时,在各种应用程序之间摇摆不定,要么你就是查阅爷爷的大词典。除非你够“硬核”,能够从图书馆借阅词典,每三周续借一次,同时将每个词条输入你的PC,然后保存到你拥挤的硬盘上。是的,是的,我认为“硬核”这个词很贴切,否则我将不得不诉诸不适合互联网非TOR顶端的自虐性语言。

所以,如果你读过我之前的文章,《Spell Weller but Grammar's Up to You》(拼写不错,语法由你定),那么你可能知道我热衷于花费数百小时,日复一日地将一个又一个词典输入电脑(我的这种特殊的强迫症目前已缓解,在过去的14多年里没有影响我的日常生活,这要归功于我的新“抓取爱好”和一定的社交生活)。我花了六周时间输入了质量平平的《Webster's New Explorer Dictionary》。在输入了十几本词典和数百个错别字之后,我将它们全部免费送给你,亲爱的读者。只需访问上面的网络链接,即可从我的GoogleDrive.访问它们。


由于该应用程序严重依赖于我从Merriam Webster网站抓取的文件,请随意向他们捐款,以感谢他们的辛勤工作。


安装

该应用程序会自动检测词典文件和目录,但您必须将它们放在预期的位置。

如果您想使用这些词典(这几乎是您想要此应用程序的初衷)

您可以

  1. 下载一份包含最基本词典(3个英语同义词词典和MW词典)的“入门套件在这里.。将Wordinator.7Zip文件解压缩到您的c:\硬盘驱动器上。(需要7Zip应用程序)。有数十万个文件需要解压缩,您可能需要喝杯咖啡,然后让它自行完成。
  2.  或在硬盘驱动器上创建一个目录

C:\Words_Dictionaries\

然后从我的Google Drive下载您想要的词典,并解压缩到上述目录中。

注意 - 自2023/07/21起 - 标题列表更改需要下载以下文件

 ----> 标题列表 - 词典支持文件 

注意。截至20240630 - Merriam-Webster的词典已得到改进 - 在此下载 

          或下载新的标题列表文件:HeadingList_AlphaOrder, HeadingList_ReverseOrder & (新的) HeadingList_AltSpellings.  [所有新文件都必须覆盖c:\Words_Dictionaries\MW2EDict\目录中的现有2个文件。

完成后,应该看起来像这样

给新手的一点提示

对于那些不清楚如何运行C#应用程序的人来说,别担心。这很简单。

  1. 下载源代码并将其从.zip文件中解压缩到你知道它在哪里存放的位置。
  2. 从Microsoft下载Visual Studio 2019,并按照说明安装这个必不可少的软件开发工具包(SDK)。
  3. 双击桌面上出现的新图标。
  4. 在提示时选择“打开解决方案”按钮 - 或使用文件菜单打开“解决方案”。
  5. 找到您下载的源代码。
  6. 选择words.sln文件并按确定
  7. 加载后,您可以
    • 通过按F5键以调试模式运行应用程序(比可执行文件稍慢)
    • 或者,通过按Ctrl-Shift-B组合键编译应用程序,然后找到源代码子目录c:/WhereverYouPutTheSourceCode/Bin/Debug/words.exe中的可执行文件。

今天以免费的价格提供的源代码是十年前我写的一个文字处理器,我用它写了我的第四本小说Cleats of the Counter-Revolution。我在这款应用程序上投入了大量时间,现在它看起来很不错。

键盘 - 抬头显示

 由于您有许多可用命令,HUD将帮助您在需要时找到工具,并在不需要时隐藏起来。

使用应用程序

这款文字处理器与其他大多数处理器略有不同。它的设计目的是让您的笔记、章节和故事保持井然有序。基本上,您创建一个“项目”,然后将您编写的文件添加到您的项目中。项目中的所有文件都可以在“笔记列表”选项卡中访问,您可以滚动浏览这些文件,并在文本编辑器中查看和编辑它们。当您以这种方式从项目的笔记列表中选择一个笔记时,该文件的内容将出现在“笔记编辑器”中。

Notes Editor(笔记编辑器)左下角的方形按钮(上面图片中用绿色圈出)允许您将 Notes Editor(笔记编辑器)移到 Main Editor(主编辑器)的上方,以便更好地查看它及其内容。单击此按钮会将 Notes Editor(笔记编辑器)移离其正常位置,并将其放置在 Main Editor(主编辑器)的前面(并隐藏它)。

您可以使用上下文菜单(右键单击 Notes-List 区域)来添加标题(称之为“笔记”或“文件”)。执行此操作时,会出现一个带有文本框的蓝色框区域,等待您为这个新的“笔记”命名或设置“标题”。有关如何创建新文件,请阅读下面的“Note-Pilot”部分。通过将标签拖到垃圾箱来处理编辑器。

设置您的项目目录

当您选择了正确的项目目录时,事情会运作得更好

移动标签页

您可以抓取任何标签页并将其从一个位置移动到另一个位置。要移动标签页,请确保它被选中,然后按住鼠标左键,将标签页移动到您想要放置的位置,并在屏幕左下角出现的垃圾箱区域释放鼠标按钮。

  

重音符号

Notes-Editor(笔记编辑器)和Main-Editor(主编辑器)都允许用户在文本中输入重音符号。截至本文撰写之时,包含的重音符号是主要的三个法语重音符号:

重音符           ì           (左侧的小帽子)

锐音符           í           (右侧的小帽子)

扬抑符      î           (标准的小帽子)

要输入带重音符号的元音,用户只需在目标元音前加上字符“\”(该字符在此应用程序中专门为此目的牺牲),然后在此字符后跟目标元音或位于该元音上方或下方的QWERTY键盘键。一旦应用程序识别出这两个字符(例如“\e”)的组合,这两个字符就会从文本中删除,并被相应的带重音符号的元音替换。上方的键产生重音符(左侧的小帽子),下方的键产生锐音符(右侧的小帽子),而元音本身则产生扬抑符(标准的小帽子)。

这些代码目前是硬编码在软件中的,可以在classKeyboard的实例化方法中轻松更改。

编辑

您可以通过在笔记列表中选择要编辑的笔记,然后使用 Notes-List 选项卡中的上下文菜单单击“编辑”来编辑正在处理的任何文件。您的故事、笔记或小说章节将出现在一个新的编辑器中。

快速编辑

您可以使用以下键命令“展开”文本,使每个子从句显示在单独的行上:

Shift-Alt + PageDown 

使用以下组合键删除空空格并合并相邻的思想(两行):

Ctrl + Delete

然后使用以下组合键将想法向上/向下移动一行:

Alt-Shift + Up arrow

 

Alt-Shift + Down arrow

编辑完文本后,使用以下命令:

Shift-Alt + PageUp

即可完成。

 

 

Polish Table

虽然您可以完成所有编辑工作而无需接触“Polish Table”功能,但您可能还是想看看这个奇妙之处。Polish-Table功能的确切作用是允许您在另一个“放大镜”编辑器中编辑文本,一次只关注一句话。
主编辑器中的Alt-Shift + PgUp / PgDown键已经可以让您处理“展开”的文本,这些文本可以“折叠”回其传统形式。然而,如果您编辑折叠的文本,它将不会记住“展开”的版本,并且会弄乱“展开文本”的操作。幸运的是,为了避免这个问题,您现在可以在Polish-Table编辑器中进行编辑。

如果您喜欢冒险并想尝试Polish-Table功能,它很新,需要一个四点式安全带才能坐稳。您可能需要备份您的工作,并顺便看看EditRecall功能。它不至于有bug或不正常,但它的概念非常不寻常,需要解释。您的文本仍然保存在Rtx编辑器中,格式为Microsoft RichTextFile(.rtf)。这个概念不变。但是您展开的诗句(跨越整页的句子)保存在一个单独的子目录中,格式为.xml文件(扩展名为.Expand的XML文档)。每个条目都有一个“密码”来访问它。所有“密码”都插入到二叉树(数据库)中,当您在主编辑器中选择一个新的句子时,如果“密码”正确,您将取回“展开的文本”。

好吧,我这么做是为了某个原因,但为了艺术,一个人必须受苦。

每次在主编辑器中“折叠”文本时,“展开”的文本都会保存到上述XML文档中,您作品的每个章节都会有一个。当您要求编辑器(主编辑器)“展开”文本(Alt-Shift + PgDown)时,它会查看您选择的文本,检查“密码”是否正确,并找到您上次折叠完全相同的句子时展开文本的确切方式。即使您不使用Polish Table,这也会发生。

要开始,您在主编辑器中的工作文本将复制到PolishTable,并在那里显示并带有边框。

在Polish-Table中按Ctrl-S,或单击“保存”按钮,会将Polish-Table编辑器的更改复制回主编辑器。当您在Polish Table中“保存”您的工作时,它不仅在那里保存文本,还会更改主编辑器中选定的文本。如果Polish-Table被“切换”(红色按钮),那么主编辑器中的每一次鼠标点击都会强制用户在Polish-Table中编辑相同的文本,当它找到一个时。

所以您写一行。在Polish-Table区域中编辑该一句子的内容。如果您想将句子分成两句,或者将两句合并成一句,您可以在主编辑器中展开相关句子,在那里编辑它们,然后主编辑器中折叠它们。应用程序会自动扫描您的文件,并删除在主文本中没有匹配“密码”的Polish Table条目。

 它仍然是新的,只有几个月大。我一直在使用它,所以还算不错。但请记住……如果您在保存工作之前加载了另一个条目,那么该工作将丢失。如果您确实保存了工作,但主编辑器的光标位置不同,那么您的“折叠文本”将覆盖主编辑器中选定的文本,无论如何。这就像开手动挡车,而引擎盖下有个曲柄,只是排气管的烟没那么浓烈。

一个很棒的事情是,在Polish-Table上,您文本的每一行都可以展示其曲线。您可以在上面的图片中看到,主编辑器位于下方,Polish-Table在上方。其思想是将您的文本进行排列,不仅增加其呈现方式的魅力,还通过隔离形容词和它们修饰的名词等词语集合来简化语言。将悬挂的同位语放在边缘,并将从句分列。通过缩进文本的各种从句,可以更容易地表达复杂的思想和晦涩的论点。这种方法模仿了大多数计算机常见的文件夹,或者使软件更易读的缩进。

好吧,这确实只是我自己的偏好。但仍然很有趣,看看这个Facebook帖子

 

 

工具栏

  1. 是您的下划线单词图标。  开启/关闭。  当开启时,所有拼写与鼠标光标下的单词相同的单词都将被下划线标出。这有助于发现您重复自己的次数。
  2.  是您的CopyCutter图标 - 开启/关闭一个数据收集工具,在进行在线研究时非常方便。CopyCutter会自动插入复制到Windows剪贴板的文本。当开启时,此图标会变为红色 ,并且在一段时间未使用后可以设置为自动关闭。见下文。
  3. WordColumn Tab功能,非常适合诗歌的排版,并允许您选择多行文本并将它们作为一个块移动,而不会改变它们之间的相对位置。  按F5键切换开关。
  4. Text Encapsulator(文本封装器)功能切换 - 在当前选定的文本周围画一个框。被封装的文本由选择的子句捕获类型定义。
  5. Defined Words(已定义词)功能切换 - 将用户当前选定的文本起始值设置为一个列表中的词,该列表由用户鼠标移动(不单击)触发。
  6.  插入图片 
  7. 调试 - 据说只存在于传闻中。

工具栏的其他UI 

您可以快速滚动浏览用户定义的各种高亮前景色/背景色组合,用于您的创意写作。该功能位于编辑器工具栏的右上角,目前有两个功能:Clause UI(从句UI)或 Font UI(字体UI),可以通过单击左侧的响应按钮列来设置。

Clause UI - 可以通过单击右侧的按钮列来选择从句类型。在clauseUI的中心使用鼠标滚轮可以滚动显示光标下方的文本:单词、子从句、句子、段落或诗句。在右侧的从句类型选择列上以类似的方式滚动,可以滚动鼠标滚轮下的高亮从句类型,而不会改变用户选择的从句类型(除非您操作太快,那么就另当别论)。

Font UI - 文本框的ZoomFactor(缩放因子)显示在此处。用户可以通过鼠标滚轮放大/缩小。或通过鼠标单击将缩放重置为1.0。

在任何“非按钮”区域双击鼠标左键相当于按一次Ctrl-Delete按键。

 

插入文本中的图像 

事实证明,在文档中添加大量图像会占用大量内存。上周,当我尝试围绕一个抓取并OCR(光学字符识别)的Perlego教科书构建一个项目时,情况变得危急。我插入了找到的每一个表格、图像和明信片,并使我的文档变得如此庞大,以至于应用程序崩溃、抽搐并退出了比赛。

因此,现在您插入的图像,无论是通过Ctrl-V还是工具栏按钮,都会被复制到您项目Images子目录下的硬盘上。图像不再存在于Rtf中,这让我CPU大大松了一口气,因为它无法处理过大的文件。

(为了获得最佳效果,您应该将单个“章节”的字数保持在4000字以下。)

该应用程序会在您的工作中插入一个文本标记,看起来像 (*+-]1[-+*),其中“1”是一个内部ID号,告诉它正在处理什么。更改此代码,应用程序就不知道您想要在那里插入图像。它不会尝试重新定位您的文本,这将在以后实现,但现在我有一本关于Principles And Applications Of Agricultural Meteorology的新教科书,并通过互动式教科书学习气候变化。太棒了。

 

下面的示例(文本来自National Post - Scams on Steroids article (20240303)

 

 

您可以使用鼠标移动文本中的图像,只需按住鼠标左键即可探索图像。

 

注意 - 您目前无法将这些图像从一个笔记复制到另一个笔记。如果您将图像粘贴到文本中,它会在Image目录中生成第二个、第三个…相同的文件,为了避免这种情况,您可以使用工具栏的ImageInsert按钮 来告诉它插入哪个文件(该文件会在上面提到的Rtx中绘制)。 我正在改进。

 

 

Word Column Tab

按F3键切换此功能,该功能允许您抓取整块诗歌并将它们作为一个单元移动,而不会干扰它们之间的相对位置。  切换开启时,文本区域的背景色会变为令人作呕的橙色,如果您还能忍受这种令人痛苦的体验,请使用鼠标选择您想要移动的文本左侧的区域。您选择区域的右侧会出现一条垂直的红线。然后,您可以通过抓取红线并移动文本来侧向滑动文本。

注意  您文本的标尺设置需要设置为零(如上图左上角的红色圆圈所示)。

注意B.  它大部分没有bug。  如果看起来不正常……按Escape键重新开始。

注意B.B.  关于花生及其谎言的真相,必须半信半疑。

 

在Highlighter标签上右键单击,将出现以下分组框:

您可以看到上图中有9种颜色组合及其标题列在Highlighter Color Sequence Editor(高亮颜色序列编辑器)中。当您滚动颜色时,编辑器将选择您序列中的下一个有效条目,并改变您选定文本的颜色。您可以通过单击每种颜色左侧的复选框来切换开启/关闭任何这些选择。要更改颜色,只需右键单击您想要更改的颜色的文本框即可。

Word Shift

您可以使用Ctrl-Shift-Alt 右/左箭头组合键将光标下的单词向前/向后移动。

Copy Cutter

Copy Cutter是一个很棒的在线研究工具。  两个RichTextBox都可以允许您独立切换CopyCutter功能,方法是单击工具栏图标 或通过上下文菜单。  切换开启后,Copy Cutter的工具栏图标会变为红色 ,并且每秒检查一次Microsoft的剪贴板内容。  当它检测到新文本或图像时,它会将其粘贴到RichTextBox中,就好像您自己粘贴一样。  这样,您就可以在不返回Word应用程序本身的情况下,在网站上选择文本并将其复制到MS剪贴板(通过Ctrl-C、Ctrl-X组合键或上下文菜单的“复制”菜单项)。  只需阅读、高亮和复制。    整个Wiki页面、Project Gutenberg eBooks或新闻文章都可以使用此功能快速概括到您的项目研究笔记中。  剪贴板中的每个项目都插入在一行上,前面有一个连字符。    您可以随时高亮或缩进。

Copy_Cutter-Auto-Shut-Off feature(Copy_Cutter-自动关闭功能)可在主编辑器的上下文菜单Options(选项)中找到,如下所述。  可以为Copy-Cutter功能设置延迟时间,使其在长时间未使用后自动关闭。

CopyCutter功能启用时,它将禁用选定的UseClipBoard(使用剪贴板)词典。

您可以通过常规的选项菜单(右键单击以打开内容菜单并选择“Options”)访问CopyCutter选项,方法是单击选项菜单底部的“Copy Cutter”按钮。

Reader

Reader”(阅读器)选项可以从RichTextBox的上下文菜单中切换开启/关闭。  切换开启后,用户输入将仅限于箭头键、Home键和End键,不允许对文本进行任何编辑。  无论您将光标移动到哪里,应用程序都会高亮显示整行文本,这应该有助于您进行公共朗读,而不会跳行或重复。  当您没有拇指来帮助引导眼睛移到下一行时,这种高亮显示文本的功能可能会很有用。

 

Definition Tracker

Definition Tracker(定义跟踪器)允许您滚动浏览所选词典中的所有单词条目。  如果您在这里使用上下文菜单,您将看到您计算机上安装的词典列表。  选择一个,该词典的整个标题列表将出现,供您使用鼠标滚轮滚动。  当您在Main-Editor(主编辑器)中键入时,Word-List(单词列表)将自动滚动到您在输入停止时,光标下文本最接近的单词。  这可能有助于您找到不确定如何拼写的单词,例如'hemorrhage'(出血),即使我输入了整个医学词典,我仍然无法正确拼写!

注意 alt-spellings(备用拼写)需要最新的MW Dictionary.7zip(2022/10/30之后)。

Main-Editor(主编辑器)中键入时,您可以使用三个快捷键来控制Headings-List(标题列表)。

  • Ctrl-Alt- A  向上滚动
  • Ctrl-Alt- Z  向下滚动
  • Ctrl-Alt- Q  将选定的标题从标题列表中插入到您的文本中。

Word-List(单词列表)文件可以从顶部的链接下载,或从此处下载。  此压缩下载中的每个文件都包含一个词典的Word-List文件。  每个词典都期望在其自己的目录中找到其自己的Word-List文件。  然而,如果您将所有文件解压缩到C:\Words_Dictionaries\目录,应用程序将在那里找到它们并将它们复制到需要的地方。  如果您在不将这些文件添加到C:\Words_Dictionaries\目录的情况下下载源代码,那么每次您选择一个以前未使用的词典Word-List时,应用程序都会生成一个新的……但这可能需要一些时间来构建。  较小的词典只需一分钟或更少时间,但一些较大的词典可能需要长达一小时。  您可以一边喝咖啡一边观看它工作,也可以直接下载它们……无论哪种方式都可以。

如果您让应用程序自己构建Word-Lists(按字母顺序和反向字母顺序),最好让它一旦开始就完成,因为如果它初始化最终输出文件而未完成任务,下次启动应用程序时,它会检测到该文件的存在,并认为它已完成,然后处理现有数据而不告知您存在问题(数据不完整)。 如果发生这种情况,请退出程序,然后转到该词典的主子目录,例如,对于MerriamWebster's English Dictionary,请转到

C:\Words_Dictionaries\MWENDict\

使用Windows资源管理器并删除半完成的文件

C:\Words_Dictionaries\MWENDict\HeadingList.fil

然后再次启动应用程序。

词典搜索

注意 词典搜索与下面解释的笔记标题搜索不同。

您可以通过转到顶部附近的菜单栏并选择Dictionary Selection(词典选择)来编程应用程序搜索您想要的任何词典组合。  执行此操作时,将出现Dictionary Selection(词典选择)窗体,如下图所示。

正如您从上图所见,所有词典都列在各个面板上。  每个面板都可以使用底部的滚动条向左/右滚动。  对于每个面板,您可以选择切换任何或所有可用的词典。  每个词典都可以设置为仅搜索词典条目的标题、其定义的内容标题和内容,或不搜索。    您会注意到Rhymer.com词典缺少两个按钮,这是因为它是一个非常棒的词典,不需要内容搜索,因为标题列表是详尽的。    您想为每个面板分配的组合键打印在顶部,并且,尽管Ctl-Shift键对所有这些面板都是通用的,但您可以编程您想与它们组合的字母或数字来调用该特定搜索。  在上图中,您可以看到最左边的第一个面板中,Merriam-Webster's English Dictionary将其标题搜索与Ctrl-Shift-W组合键匹配。  因此,无论光标在哪个编辑器中的哪个单词下,您都可以通过执行此组合键来搜索它在Merriam-Webster词典中的定义。  您可以使用此窗体顶部的Add(添加)按钮创建新面板,或使用位于您想删除的面板底部的Delete(删除)按钮删除任何面板。

每个面板的底部除了Delete(删除)按钮外,还有两个其他按钮。  这两个按钮都是切换开关。

  1. Use Clip Board (使用剪贴板)- 当此按钮切换开启时,其他任何具有相同按钮也切换开启的面板,其按钮将被切换关闭,并将最后选择的用于“Use Clip Board”功能。  此功能允许您从浏览器、其他文字处理器或任何Windows环境中突出显示文本,当您将选定的文本复制(使用鼠标或Ctrl-C或Ctrl-X组合键)到Microsoft的“剪贴板”内存空间时。  该应用程序每秒测试一次此内存的内容,如果找到新文本,它将运行该文本通过选定面板的搜索,并弹出结果,就好像您按下了该面板对应的Ctrl-Shift-Key组合键在编辑器工作区域的该单词上一样。  Use-Clip-Board(使用剪贴板)和CopyCutter(复制剪切器)选项都使用相同的MS-ClipBoard测试,并且如果CopyCutter功能已启用,则不会搜索选定的词典。
  2. Pop-Up Reference(弹出式参考) - Pop-Up-Reference(弹出式参考)切换按钮的选择与Use Clip Board(使用剪贴板)类似。    Pop-Up Reference(弹出式参考)功能适用于我将在下面进一步讨论的词典输出窗体。  当此功能启用时,将鼠标悬停在Dictionary Definition Output(词典定义输出)文本框中的一个单词上,将指示选定的词典搜索鼠标下方的单词,并在弹出窗口中提供其定义。

您可以设置当鼠标悬停在Dictionary Results(词典结果)文本框中时,弹出定义出现的延迟时间。  在下面的Dictionary Selection(词典选择)窗体中,顶部附近有一个“PopUpDelay Time”(弹出延迟时间)按钮。

当您将鼠标光标移到它上面时,会出现一个列表框,提供选项设置。

您可以设置鼠标在词典搜索结果文本框中静止悬停多长时间后,该单词的定义才会弹出。  单击词典结果文本框中的单词仍将启动对该单词的搜索,结果将显示为常规单词搜索,但可以选择最后一个选项“Right-Mouse Click”(右键单击),该单词的定义将显示在“Pop-Up”(弹出)窗口中(就像它是一个悬停搜索一样),使您原来的搜索结果保持不变,而不是生成一个完全不同的搜索和搜索结果。

这在您搜索押韵词典中的押韵词列表或同义词词典中的同义词列表时非常有用。您在定义中看到的单词在您的创意写作中可能听起来不错,但您可能不确定它的定义,拥有这种弹出窗口可以快速获取该单词的定义,从而节省大量时间。如果您明白我的意思,这可以为您省去因押韵不当而滥用读者的尴尬。

 

 

搜索结果

MultiPanelSearch_Sequential(多面板搜索_顺序)

您可以使用Ctrl-Shift-Q组合键告诉应用程序查找句子中所有单词或一系列单词的同义词条目。  它搜索的单词数量受您打开的Definition Ports(定义端口)(下文描述)数量限制,它们将搜索各自DefPort最后一次指定的单词。  为了帮助您轻松进行同义词研究,它将忽略句子中出现在DefPorts上方QuickInsert(快速插入)单词列表中的任何短常用词。

MultiPanelSearch_Single(多面板搜索_单项)

此命令与MultiWordSearch_Sequentiel类似,不同之处在于它将搜索用户光标下的同一个单词在所有DefPorts中。  这很方便,如果您有三个不同的同义词词典,并想在所有这些词典中搜索同一个单词。  Ctrl-Shift-W - (在Q键旁边)。

默认多面板搜索词典选择 

   当您执行MutiPanel Search Single(多面板搜索_单项)或Sequential(顺序)时出现的词典选择,可以通过单击DefPortList(定义端口列表)标题的右半部分来设置,当出现光标时,或者当光标看起来像这样时单击左半部分,一旦您决定了所需的面板数量,并设置了各自的词典首选项。当您对选择满意后,将鼠标移到defPorts(定义端口)列表的顶部边缘,当鼠标滚轮光标出现时单击标题。  这两个列表是独立的,所以您可以有3个不同的同义词词典用于单字搜索,并且当您进行精彩的五词联击时,有5个DefPorts,其中包含您最好的词典。

 

双击文本中的任何单词将启动MultiWordSearch(多单词搜索)- 如果用户光标在被单击单词的后半部分,应用程序将执行MultiWordSearch_Single,反之,当光标在单词前半部分时,则执行MultiWordSearch_Sequential。

在任何编辑器的编辑区域内,您都可以使用以下任何组合键来操作Dictionary Results Form(词典结果窗体)。

  • Ctrl-Shift-Z  向下滚动结果列表
  • Ctrl-Shift-A  向上滚动结果列表
  • Ctrl-Shift-X  删除所有副本并从屏幕上移除
  • Ctrl-Shift-S  删除最近的搜索结果

您可以通过左键单击panelDefinitionNavigator中的单词,在当前加载定义的同一词典中调出该单词的定义。  三个导航按钮

  1. ¤  主页
  2. <  后退
  3. >  前进 
  4. X 删除此定义导航器

可用于循环浏览特定panelDefinitionNavigator提供的定义。

 

注意  词典搜索结果的滚动快捷键与标题列表的滚动插入文本命令相同,以及高亮器的滚动。  它们都通过按键'A'向上滚动,通过按键'Z'向下滚动,其中

  1. 搜索             Ctrl-Shift          + A/Z
  2. 标题列表   Ctrl-Alt             + A/Z
  3. 高亮器     Ctrl-Shift-Alt    + A/Z

    - 您始终可以通过按F9键调用HUD

押韵词典

有一个独立的RhymeDictionary(押韵词典),与上面列出的词典分开。  您可能从我的GoogleDrive下载的Rhymer.com词典列出了太多与您试图押韵的单词只有单个尾音节相同的单词,迫使您筛选数千个实际上不太押韵的单词。  为了解决这个问题,我创建了一个使用三元搜索树的应用程序,以帮助减少无用的押韵单词数量。  您可以在CodeProject网站上阅读有关该应用程序的文章,并单独下载使用它,在其自己的Rhymes文章中。

由于它运行所使用的数据库为100MB,大于CodeProject网站的文件大小限制10MB。  您无法下载它,也不需要采取任何措施来拥有此功能,因为Words将在第一次发现数据库不存在时,在后台生成所需的数据库。  它会在表单的左上方横幅上显示消息,告知您这一点,并且只需要15-20分钟完成。    这发生在后台,因此您的写作体验不会受到此工作的影响。  准备就绪后,表单顶部的横幅将短暂显示最终消息,然后您就可以通过按Ctrl-Shift-R组合键来使用它,就像使用其他词典一样。  结果将出现在与其他搜索相同的DefinitionPilot框中,但它不允许您从中进行定义导航。

 

未搜索过的单词

在搜索结果列表下方、定义端口上方有一个区域,其中包含任意数量的按钮。  将鼠标移到这些按钮上,您会注意到光标在从左到右均匀划分的三个区域之间改变。

这些是:

  1.  -  插入此“单词”到您的文本中
  2.  -  将此“单词”替换为您文本中选定的单词
  3.  -  丢弃此按钮

如果您查看上面的列表,您会注意到其中大多数都是小说中常见的词。  然而,“cleric”(牧师)选项有点不寻常。  我创建它是因为我的小说中有一个教士,他在其他角色的狡猾计谋中扮演着核心角色。  这个按钮方便,不是用来在我的文本中插入“cleric”(牧师),而是用来调用“cleric”(牧师)的同义词条目并选择该单词的其他同义词。  同样,对于“reply”(回复)和“say”(说)或“call”(称呼)等词也是如此。

这样编辑有时会感觉像在玩电子游戏……  您可以一边喝咖啡一边使用鼠标进行更改。

这些按钮是通过文本编辑区域的上下文菜单“Words Never Searched”(未搜索过的单词)或WordsNeverSearched功能本身创建的,方法是右键单击该区域并调用其上下文菜单。

 

WordAnalyzer

WordAnalyzer(单词分析器)位于Notes(笔记)区域下方。  这个工具为您提供迄今为止您在文本中写下的所有单词的列表,并跟踪它们出现的次数。  这可以帮助您注意到是否使用了过多的不常用词,以便您可以从同义词词典中更好地选择替代的同义词。  您可以通过单击左上角的Alpha(字母)和Count(计数)按钮按字母顺序或按计数顺序重新排序列表。  Word Analyzer会在您打字时跟上,只落后半秒,然后在您停止打字时立即滚动列表到鼠标光标下的单词。  它会在您每次停止打字时计算单词,因此始终是最新的,顶部的数字反映了唯一单词的数量(左侧)、单词总数(右侧)以及唯一单词的整体比率,一个介于0.0和1.0之间的数字。

在此信息右侧是Search Textbox(搜索文本框)(这是WordListView_Search按钮从搜索结果复制选定单词的地方),您可以在此文本框中键入,Word Analyzer将滚动到它(如果它在您的文本中找到),或者滚动到字母顺序上最接近的单词。  通过双击一个单词,应用程序将在您的文本中进行单词搜索,并为每次在列表中双击该单词的次数选择下一个实例。

当您在两个编辑器(alt或main)之间切换时,Word Analyzer将自动分析新焦点RichTextBox的文本。

Lock(锁定)(在下面的图像中未显示)允许您在编辑文本时重新绘制相同“锁定”单词的WordMap。  当解锁时,选定的单词会随着用户编辑文本而改变,并且会为文本编辑光标下的当前单词绘制新的WordMap。

Defined Words

 工具栏上的图标 

Defined Words(已定义词)功能允许您将鼠标移到文本上(按住Shift键),光标将找到选定内容,告诉DefinitionTracker(定义跟踪器)跳转并为您和您的观众查找定义…… pronto。

 

Note Pilot 

Words应用程序中的笔记是存储在您的项目文件中的数据片段。  这些数据片段包含信息,如:

  1. 标题
  2. 视角(POV)
  3. 章节号
  4. 年/月/日 - 时 & 分 
  5. RichTextBox在硬盘上的位置(可选)

您会注意到选项(5)“RichTextBox在硬盘上的位置”是可选的。  这是因为当您首次创建这些“数据片段”时,它们实际上并不是写作项目,它们只是容器,可以选择引用您写入的文件。  这可能看起来很奇怪,但它允许您在这些单独的文件夹中组织信息。

您的项目可以有子文件夹,其中包含:

  • 章节
  • 角色描述
  • 历史信息
  • 技术研究
  • 大纲

以及您能想象到的任何其他内容。  您可以通过向上移动到父文件夹(显示其父列表,使当前文件夹显示在子列表中)或通过双击Notes List(笔记列表)中的某个选项“向下”移动到另一个文件夹。  上方的 和下方的 按钮允许您在列表中向上/向下移动当前选择(黑色文件)。  目前无法移出/移入不同的文件夹,因此现有文件会停留在原地,除非您按下上下文菜单的Note Delete(笔记删除)按钮将其从当前“文件夹”中删除,然后通过单击顶部的“<<<<< [dir name]”(<<<<< [目录名称])标签导航到要“向上”移动的文件夹,或通过双击下方Notes List(笔记列表)中的文件夹来“进入”文件夹。  类似于使用Microsoft的Windows文件资源管理器。

这看起来可能很复杂且违反直觉,但我广泛使用它,而且它非常棒。    

使用上下文菜单(在Note Pilot上右键单击) - 您可以创建一个文件夹(笔记),它将成为项目文件中的一个“笔记项”或“数据片段”。  此信息将告诉应用程序您的“文件夹”也是一个文件,并且当您在屏幕左上角的笔记列表中选择它时,该文件将加载。

 但它仍然只是一个“文件夹”,直到您单击,您将告诉Words您打算使用此笔记作为实际文件来撰写您的短篇故事、笔记、研究或大纲。  您单击的图标将变为,它右侧的Path(路径)标签将启用(您可以单击它,见下文),然后在Path指向的位置创建一个RichTextFile。  

您可以通过选择笔记(鼠标左键单击)然后右键单击您想编辑的区域来编辑笔记的标题、POV或日期/时间信息,这时会出现一个可编辑的UI文本框。

您的笔记的标题将是文件的名称。  更改笔记的标题时,其对应的文件(如果存在)也将随之更改。  您可以通过单击右侧的路径来重新定位文件,并告诉应用程序将其放在哪里,但如果您在外部移动文件(使用Windows资源管理器),您的项目将不知道在哪里找到它,并且您将无法再编辑它。(您的最佳选择是找到它并放回原处,或从您的项目中删除该笔记并创建一个新笔记)。

我想我会找时间制作一个视频来更好地解释如何使用 Notes 和 NotePilot,但……那只能等以后再说。

您可以通过按住鼠标右键单击要编辑的字段来编辑笔记信息。  日期字段用斜杠(年/月/日)分隔,时间需要用冒号分隔小时:分钟 - 在编辑章节(笔记)标题时,请不要使用Windows操作系统将拒绝用于文件名的字符……然后您就可以了。

备份文件 & 保留文本备份文件

您应该一如既往地备份自己的工作。  但是,如果您发现您的部分工作已消失,或者您想恢复EditRecall功能没有的备份,Wordinator确实会在单独的文件文件夹中记录您的工作。  F1选项菜单允许您更改保存的频率(最高每分钟一次)和保存的文件数量(最高100个以前的备份文件)。 

要查找这些创意写作的备份文件,请使用NotePilot跳转(或“向上”)一次一个文件夹,方法是单击上方的标题,然后双击找到的任何文件夹。

见下图: 

笔记标题搜索

您可以搜索Notes Headings(笔记标题)以查找特定文章或章节进行阅读、参考或编辑。  

Ctrl-Shift + F1   - 搜索光标下的单词

 

搜索结果可以在项目的Root(根目录)中找到,以及下面解释的Backup Files(备份文件)。

 

单词建议

单词建议是我为另一个项目Dlús : Irish Language Word Processor(Dlús:爱尔兰语文字处理器)请求构建的功能。  由于实现起来非常简单,所以我直接将其代码包含在这里。    它正如其名称所示——在您键入时建议单词。  它建议的单词取自您的文本,并且只提供以您当前键入的单词相同的开头拼写的单词。  此功能相对常见且易于使用,只需按键盘上的上/下箭头键进行选择,然后按Tab键将单词插入您的文本。  大多数时候它并没有那么必要,但如果您的小说中的某个角色有一个拼写奇怪或名字特别长的角色,这可以帮助您始终拼写正确。

对用两指打字的人也很有用。

内存恢复

由于平均高中数学计算器具有内存/恢复设置,您可能会觉得Words的Memory Restore(内存恢复)功能很熟悉,它与您高中时使用的功能非常相似……  只不过它用于存储/恢复文本而不是数字。

Memory Restore(内存恢复)类似于您的袖珍计算器的Memory-Store(内存存储)和Memory-Recall(内存恢复)功能,但具有无限内存,最多可分10个不同的文件夹。  您可以轻松地将您的工作分类到您想要的任何类别中,然后稍后使用它,方法是按[Alt]+[0-9数字键]。  您保存的文本将存储在您输入的MemoryRestore(内存恢复)文件夹中,例如,alt-3 将选定的文本存储在内存文件夹#3中。    使用文本框更改、编辑或重命名您的内存“调用签名”。  该文本将在您按住Alt键时显示在HUD面板上。  由于每个内存单元(0-9)可以存储任意数量的文本片段,您可以使用右侧的滚动条。

小说格式化

NovelFormatter(小说格式化器)选项卡将实时格式化您的PolishTable工作。

您还可以通过其窗口左下角的按钮将小说格式化为单个Rtf或Pdf文档。  格式化选项允许您包含(或排除)章节标题信息的不同组件:章节号、标题、日期、时间 & POV,以及它们各自的字体。

注意 PDF的ZoomFactor(缩放因子)是从用户的主章节编辑器复制的,页面大小是从NovelFormatter(小说格式化器)的标签大小测量的。 

地图功能 

您可以使用Map Feature(地图功能)添加图像来帮助您编写项目。

AnimationEditor 

您可以使用AnimationEditor(动画编辑器)创建“动画”。  这些动画附加到加载的PolishTable条目。

选项 

F3 - 切换选项面板的可见性 

   

您可以通过主编辑器的上下文菜单访问选项面板,然后单击Options(选项)菜单项。

界面用户友好且直观,尽管选项本身可能并不自明。  以下是一些快速说明,希望能帮助您理解它们。

  • Word Suggestion(单词建议) - 启用后,应用程序将建议文本中已有的、并且以您当前键入的单词相同的拼写开头的单词。  按键盘上的上/下箭头键进行选择,然后按Tab键将单词插入您的文本。
  • Rtx Message Scrolling(Rtx消息滚动) - 这是一个切换选项,启用后,应用程序将在用户的工作区域滚动显示消息。
  • Copy Cutter Auto Shut Off Delay(Copy Cutter自动关闭延迟) - 可以为Copy Cutter编程,使其在给定时间内未使用后自动关闭。  可用的设置是Copy Cutter自动禁用之前的15153060分钟。  您可以通过将此选项设置为Never(从不)来禁用自动关闭功能
  • AutoSave(自动保存) - 这是一个切换选项,设置为true时,您的主工作区域将每五分钟自动保存一次,并覆盖加载它的文件。  非常方便,如果您想要的话。
  • Backup Time Period(备份时间段) - 确定当前编辑器多久保存一次到单独的备份文件中。
  • Backup Files Total Number(备份文件总数) - 限制保留的单独备份文件的数量 - 用户可以随时通过回退(在Note Pilot中按左箭头)到根“目录”,然后双击“Backup”(备份)笔记来访问这些备份文件。

您可以通过单击选项列表底部的“CopyCutter”按钮来访问CopyCutter选项。

选项 - 功能

Features(功能)控件决定了应用程序的哪些“选项卡页面”可供用户使用,例如Rhymish(押韵)或Encryption(加密)。

用户密码 

您现在可以选择“登出” - 这可以让任何用户“摆弄”您的写作,但更改将不会保存到文件中,直到您重新登录。  使用主编辑区域的右键上下文菜单来登出,或稍后显示登录提示。  

如果您忘记了密码 - 您可以利用您编写的代码,使用提供的源代码来解密加密的密码。  

或者……您也可以转到与可执行文件相同的目录,删除加密的文本文件。    它的“文件名”与我的“Latin Project”(拉丁语项目)文章中的方案相同。

                                    "PassivePeriphrastic.txt"

代码

MultiButtonPictureBox

classMultiButtonPic基本上是一个图片框,上面绘制了矩形区域,用户可以通过鼠标光标与之交互。

add”(添加)和“hide”(隐藏)按钮下方的所有内容(除了带有“W”的textbox)都是绘制在公共图片框上的按钮。  Ctrl“按钮”是唯一不交互的按钮。  四行的“¤”为每个词典设置选定的搜索样式。  底部还有三个按钮:“Use Clip Board”(使用剪贴板)、“Pop Up Reference”(弹出式参考)和“Delete”(删除)。  响应时间很棒。  每个按钮都可以独立于其他按钮进行切换,并且可以通过覆盖小部件的内部鼠标事件来使用这些按钮,就像它们是通用面板上的单选按钮一样。

这是多按钮中的Mouse-click事件:

//

MouseEventHandler _eventHandler_MouseClick;
public MouseEventHandler eventHandler_MouseClick
{
  get { return _eventHandler_MouseClick; }
  set
  {
    if (_eventHandler_MouseClick != value)
    {
      if (_eventHandler_MouseClick != null)
        MouseClick -= _eventHandler_MouseClick;
      MouseClick -= Event_MouseClick;

      _eventHandler_MouseClick = value;
            
      if (_eventHandler_MouseClick != null)
        MouseClick += _eventHandler_MouseClick;
      else
        MouseClick += Event_MouseClick;
    }
  }
}

virtual public void Event_MouseClick(object sender, MouseEventArgs e)
{
  if (cButtonUnderMouse != null)
  {
    if (cButtonUnderMouse.CanBeToggled)
      cButtonUnderMouse.Toggle();
  }
}
//

通过将 MBP(classMultiButtonPic 的实例)的 _eventHandler_MouseClick 设置为应用程序中的一个事件,该事件将覆盖 MBP 的鼠标单击事件。此应用程序中的实现方式如下:

该事件在 panelSelectDictionary 类中设置。

//
cMBP.eventHandler_MouseClick = cMBP_HTMLTagList_Click;
//

然后,事件本身会接管切换所需内容的工作,以便一组按钮可以互斥地切换(类似于常见面板上的单选按钮),在本例中,即字典名称旁边的搜索类型行按钮。

//

private void cMBP_HTMLTagList_Click(object sender, EventArgs e)
{
classCK_Objects.classMultiButtonPic cMBPSender = (classCK_Objects.classMultiButtonPic)sender;
classCK_Objects.classMultiButtonPic.classButton cBtn = 
   (classCK_Objects.classMultiButtonPic.classButton)cMBPSender.cButtonUnderMouse;
if (cBtn != null)
{
  if (cBtn.Tag != null)
  {
    classButtonArray cBtnArray = (classButtonArray)cBtn.Tag;
    classBinTrees.classDictionary cDictionary = cBtnArray.cDictionary;
    int intIndex = cBtnArray.lstButtons.IndexOf(cBtn);
    if (intIndex < (int)enuSearchType._num)
    {
      cBtnArray.eSearchType = (intIndex >= 0 && intIndex < (int)enuSearchType._num)
                        ? (enuSearchType)intIndex
                        : enuSearchType._num;
      for (int intBtnCounter = 0; 
                intBtnCounter < (int)enuSearchType._num; intBtnCounter++)
      {
        cBtn = cBtnArray.lstButtons[intBtnCounter];
        cBtn.Toggled
            = cBtn.Highlight
            = intBtnCounter == intIndex;
      }
      cMBPSender.Refresh();
      if (cBtnPopupReference.Toggled)
        formDictionarySelection.instance.pnlPopUpReference = this;
    }
  }
  else
  {
    panelSelector.enuTypeButton eButtonType = (panelSelector.enuTypeButton)cBtn.obj;
    switch (eButtonType)
    {
      case panelSelector.enuTypeButton.UseClipBoard:
        {
          cBtn.Toggle();
          if (cBtn.Toggled)
          {
            for (int intPnlCounter = 0; intPnlCounter < 
                       formDictionarySelection.instance.lstPnlSelector.Count; intPnlCounter++)
            {
              panelSelector pnlSel = 
                           formDictionarySelection.instance.lstPnlSelector[intPnlCounter];
              if (pnlSel != this && pnlSel.cBtnUseClipBoard.Toggled)
              {
                pnlSel.cBtnUseClipBoard.Toggled = false;
                pnlSel.cBtnUseClipBoard.Highlight = false;
                pnlSel.cMBP.Refresh();
              }
            }
            formDictionarySelection.instance.pnlUseClipBoard = this;
          }
          else
          {
            formDictionarySelection.instance.pnlUseClipBoard = null;
          }
          formDictionarySelection.instance.TmrClipboard_Set();
        }
        break;

// some cases deleted for brevity

      default:
        {
        }
        break;
    }
  }
}

//

对于 UseClipBoard 按钮,它需要查看其他面板,以确保没有任何两个面板同时列出要搜索的字典,以便您的用户将文本复制到 MS 剪贴板(这对于在字处理器外部使用非常方便,例如在您的网页浏览器中)。

外观像 Painted Rtx 的 Picturebox UI

   用户键入的文本框实际上是不可见的。用户与之交互的是一个 Picturebox,它被绘制成看起来像背景中已聚焦的 Rtx。当用户放大/缩小 rtx 时,Picturebox 在屏幕上保持相同大小,但实际进行写入的 rtx 会被放大/缩小,以产生“缩放”的错觉。文字列标签功能(允许用户使用鼠标将文本行集合左右移动)存在一些问题,因此采用了这种替代缩放方法,以消除扭曲用户工作区域的固有 MS 缩放怪癖。

     两种方法    

       public Point ptConvert_PicVeneerToRtx(Point pt)
       {
           Point ptRetVal = new Point();

           ptRetVal.X =  (int)((float)pt.X / fltPicVeneerWidth_Over_RtxWidth);
           ptRetVal.Y = (int)((float)pt.Y / fltPicVeneerWidth_Over_RtxWidth);

           return ptRetVal;
       }
       
       public Point ptConvert_rtxToPicVeneer(Point pt)
       {
           Point ptRetVal = new Point();

           ptRetVal.X = (int)((float)pt.X * fltPicVeneerWidth_Over_RtxWidth);
           ptRetVal.Y = (int)((float)pt.Y * fltPicVeneerWidth_Over_RtxWidth);
           return ptRetVal;
       }

             在传递 Picturebox 的事件处理程序参数到相关的 RichTextBox 事件处理程序时,在 UI Picturebox 和隐藏的 Rtx 之间转换点。

 

panelSP - 一个带滚动条的面板

字典选择窗体和字典输出窗体的“已复制”结果列表都使用 panelSP 类,该类包含一对位于普通 Windows 面板上的滚动条。这是一种方便显示对象的方式,因为您可以将任意数量的面板(可能带有其他对象)添加到其中,并在一个任意大的内部区域中。它的工作原理是,通过将面板添加到其中,panelSP 会为您提供一个 SweepAndPruneElement(在此解释中我称之为 spEle)。然后,您可以设置每个 spEle 的位置,panelSP 会在称为 recArea 的内部假想空间中为其腾出空间。panelSP 还有另一个矩形属性称为 recVisible。此 recVisible 与屏幕上的面板大小相同,但其位置会随滚动条的值而变化。通过滑动滚动条,用户告诉 panelSPrecArea 的哪个区域将在屏幕上显示,然后 panelSP 会找出您的哪些面板(spEle)应该可见,然后根据滚动条的值将这些 MS 面板对象定位到屏幕上的正确位置。panelSP 允许您将许多对象(只要它们包含在 MS 面板中)分组到其中,并为用户提供滚动条以查看所有这些对象。您作为程序员,永远不会设置面板的位置(可以任意调整大小),而是将其放置在 panelSP 的假想 recArea 中,该数据将告知 panelSP 根据用户的滚动条值需要显示什么。

Sweep And Prune(扫描和修剪)

Sweep and Prune 算法实现为一个独立的类,可以与任何对象一起使用,从 string 中的字符(只需将 Y 值设置为常量,并使用字符索引作为 X)到 Britney Spears 世界巡演的城市地图。您创建元素,定义它们的区域,并将它们添加到地图中。然后,当您询问“Point(x, y) 下面是什么?”时,它会吐出您隐藏在下面的任何内容。 这里有一篇不错的文章可以帮助您理解该算法。MultiButtonPic 类、panelSP 类以及 SPObjects 类都使用类似的 Sweep and Prune 算法来跟踪它们正在处理的对象。

Defined Words

用于快速查找、绘制然后检测鼠标光标下出现的已定义词的 UI 需要五个步骤:

  1. 构建并排序每个已定义词在文本中出现的所有索引列表。
  2. 当用户滚动/文本更改稳定时 - 评估可见文本的开始/结束索引。
  3. 从排序列表中选择 - 显示在屏幕上的单词条目。
  4. 创建屏幕区域的 Sweep and Prune 地图以查找这些单词。
  5. 鼠标移动事件处理程序会查询 SP 地图并将 RTX.Select() 设置为触发的单词。

1) 构建并排序列表

它会扫描文本以查找用户单词列表中的条目,然后将它们与找到它们的索引匹配并放入列表中。然后,该列表按升序索引值排序。

public static void ResetToRtx_to_Rtx()
{
    Clear();
    if (rtx == null) return;
    string strValidChar = "'-";
    using (RichTextBox rtxTemp = new RichTextBox())
    {
        rtxTemp.Rtf = rtx.Rtf;
        rtxTemp.SelectAll();
        rtxTemp.Text = rtxTemp.Text.ToUpper();
        foreach (string word in lstWords)
        {
            int intFind = rtxTemp.Text.IndexOf(word);
            while (intFind >= 0)
            {
                char chrBefore = (intFind > 0 ? rtxTemp.Text[intFind - 1] : ' ');
                char chrAfter = (intFind + word.Length  < rtxTemp.Text.Length -2) 
                                                        ? rtxTemp.Text[intFind 
                                                                    + word.Length] 
                                                        : ' ';


                bool bolBefore = !char.IsLetter(chrBefore) 
                                  || strValidChar.Contains(chrBefore);

                bool bolAfter= !char.IsLetter(chrAfter) 
                                  || strValidChar.Contains(chrAfter );
                            
                if (bolBefore && bolAfter)
                {
                    new classIndexWord_Item(word, intFind);

                }
                intFind = rtxTemp.Text.IndexOf(word, intFind + 1);
            }
        }

    }

    IEnumerable<classIndexWord_Item> query = lst.OrderBy(DW => DW.Index);
    lst = (List<classIndexWord_Item>)query.ToList<classIndexWord_Item>();
}

  由于我只是在几天前才完成这项工作,并且尚未在比我的短篇章节(2500 字或更少)更大的文件上进行测试。很可能我很快就需要将这项任务分解成小任务,并在计时器上运行它们,以改善 UI 和用户体验。

2 & 3) 测量 rtx 可见索引

public static List<classIndexWord_Item> lstWordsVisible

属性使用用户文本的左上角(及稍上方)和右下角(及稍下方)的点来确定哪些字符索引是可见的。

// find start
int intBorder_Height = 256;
Point ptTL = new Point(0, -intBorder_Height);
Point ptBR = new Point(rtx.Width, rtx.Height + intBorder_Height);
int intIndex_TL = rtx.GetCharIndexFromPosition(ptTL);
int intIndex_BR = rtx.GetCharIndexFromPosition(ptBR);

然后使用“测试中途,半步检查并再次跳转”的方法来查找从开始 intIndex_TL 之后和结束 intIndex_BR 之前的单词。

int intStepSize = lst.Count;
int intTest = 0;
int intDir = 1;

int intFail = 0;
int intFaile_Max = 32;

int intWord_FirstFound_Index = 0;
do
{
    intStepSize /= 2;
    if (intStepSize < 1)
    {
        intStepSize = 1;
        intFail++;
    }

    intTest += intStepSize * intDir;
    if (intTest < 0)
        intTest = 0;
    if (intTest >= lst.Count)
        intTest = lst.Count - 1;
    classIndexWord_Item cWDI_Test = lst[intTest];

    intDir = (int)Math.Sign(intIndex_TL- cWDI_Test.Index);
    if (intDir > 0 && intTest > intWord_FirstFound_Index)
        intWord_FirstFound_Index = intTest;
} while (intFail < intFaile_Max);

然后返回屏幕上可见的单词列表。

4) 创建可见单词的 Sweep and Prune 地图 

如上一节所述 - SP_Build() 创建屏幕地图。

public static void SP_Build()
{
    cSP.lstElements.Clear();
    if (ckRtx_Focused == null) return;

    int intGuessedFontHeight = 20;
    int intTL = ckRtx_Focused.rtx.GetCharIndexFromPosition(new Point(0, 0));

    for (int intCounter = 0; 
         intCounter < lstItemsVisible.Count; 
         intCounter++)
    {
        classIndexWord_Item cWordItem = lstItemsVisible[intCounter];
        Point ptTL = ckRtx_Focused.rtx.
                          GetPositionFromCharIndex(cWordItem.Index);
        Point ptTemp = ckRtx_Focused.rtx.
                          GetPositionFromCharIndex(cWordItem.Index 
                                                   + cWordItem.Word.Length);
        Point ptBR = new Point(ptTemp.X, 
                               ptTL.Y + intGuessedFontHeight);
                
        if (ptBR.X < ptTL.X)
            ptBR.X = ptTL.X + intGuessedFontHeight;


        Ck_Objects.classSweepAndPrune.classElement 
                      cEle_New = new classSweepAndPrune.classElement();
        cEle_New.rec = new Rectangle(ptTL, 
                                     new Size(ptBR.X - ptTL.X, 
                                              ptBR.Y - ptTL.Y));
        cEle_New.obj = (object)cWordItem;

        cSP.Add(ref cEle_New);
    }
}

5) 鼠标移动轮询 SP 地图

然后 rtx.MouseMove() 事件处理程序测试用户鼠标下的单词。

private void rtxCK_MouseMove(object sender, MouseEventArgs e)
{
    if (groupboxDefinedWords.Toggle)
    {
        Point ptMouse = new Point(e.X, e.Y);
        groupboxDefinedWords.classIndexWord_Item 
              cItemUnderMouse = groupboxDefinedWords.cItemUnderPoint(ptMouse);
        if (cItemUnderMouse != null)
        {
            if (cItemUnderMouse.Index >= 0 
              && cItemUnderMouse.Index 
                 + cItemUnderMouse.Word.Length < rtx.Text.Length)
                rtx.Select(cItemUnderMouse.Index, 0);
        }
    }
}

询问 groupboxDefinedWords 在给定点下鼠标下的单词。

public static classIndexWord_Item cItemUnderPoint(Point pt)
{
    if (ckRtx_Focused == null) return null;

    if (ckRtx_Focused.CharIndex_TL_Changed)
    {
        List<classIndexWord_Item> lstVisible = classIndexWord_Item.lstWordsVisible;
        SP_Build();
        ckRtx_Focused.CharIndex_TL_Changed = false;
    }

    Ck_Objects.classSweepAndPrune.classElement cEleFound = cSP.Search(pt);
    if (cEleFound != null)
        return (classIndexWord_Item)cEleFound.obj;
    else
        return null;
}

定义端口 -

许多字典不存储在 RichTextFiles(.rtf) 中,但有些是普通的 TextFiles(.txt),没有字体或颜色的格式。这是因为我,相信拥有这些资源会帮助我写作(尽管我在输入医学词典时没有学到任何医学知识,但拥有这些工具极大地提高了我的写作才能),手工输入了十几个词典,逐页(并带有策略性插入的拼写错误供您阅读娱乐),然后在发疯之前……捅了我的邻居,并在监狱里度过了很多年,自豪地吹嘘我的犯罪记录上只有暴力。我出狱时,有一种叫做“互联网”的东西,从像 Merriam-Webster 这样的商业网站上抓取成千上万的文件,比每天花无数小时将单词定义输入计算机并在此过程中收集邮政蒸汽要酷得多。这次经历,以及在赤贫厨房里吃着饭,周围都是情绪不稳定的酒鬼和无家可归的吸毒者时,读了 Amy Vanderbilt : Complete Book of Etiquette,奇怪的是,这使我成为一名更好的作家。

我列出所有字典及其来源......仅供记录。

手工输入的词典 

  1. 词典:犯罪
  2. 词典:英语
  3. 词典:委婉语
  4. 词典:意大利语
  5. 词典:拉丁语(修订版)
  6. 词典:医学
  7. 词典:十九世纪俚语
  8. 词典:监狱俚语
  9. 词典:专有名词
  10. 词典:南方表达
  11. 词典:西班牙语
  12. 词典:法语
  13. 同义词词典:英语

从下载的 PDF 文件解析

  1. 词典:航海 

从互联网抓取

  1. 词典:英语 MW
  2. 词典:爱尔兰-英语
  3. 同义词词典:英语 MW
  4. 词典:词源 EtymOnline.com
  5. 同义词词典:法语 Usito 
  6. 词典:法语

这意味着上面列出的所有字典,除了最后三个,都是 TextFiles。为了美化这些文件的输出,该应用程序会加载 TextFile,找到标题(第一行文本),然后以与该单词条目其余部分的定义不同的字体/颜色打印标题。为了做到这一点,它必须添加标题,设置字体和颜色,然后添加定义。这样做导致 RichTextBox 顺序打印内容。这导致用户在观看定义被写入蓝色,然后重新格式化,然后设置为黑色时表现不佳……一团糟。可能需要几周时间才能让我的笔记本电脑将每个 TextFile 重建为合适的 RichTextFile,但这将等到我有了另一个旁边的机器来执行这些任务。

为了解决这个问题,我采用了类似于主编辑器 RichTextBox/PictureBox 组合的方案,即用户看到/与 Picturebox 交互,鼠标移动/单击活动在经过 Picturebox 后发送到 Rtx 事件处理程序。这意味着用户在 Rtx 加载时从未真正看到它,并且 Picturebox 仅在 Rtx 准备好进行特写并拍照后才显示 Rtx 的图像。

Definition Tracker 不使用普通“标题搜索”使用的相同二叉树。当在此字典的子目录中创建此功能的数据库文件时,列表构建器会加载每个 RTF 文件,然后不仅添加文件上的第一个单词条目的确切拼写,还在硬盘上的二叉树中添加“替代拼写”。然后,它按顺序遍历二叉树,以创建单独的文件,其中包含条目标题和相应根文件名的索引、大小相等的记录。此文件由 Definition Tracker 的 VerticalScroll 栏在其 VscBar_ValueChanged() 事件处理程序中索引,该处理程序已校准。更改 vsc.Value,MultiButtonPicturebox(可滚动单词列表)将绘制与用户请求匹配的单词。

定义导航器单击或双击

我曾遇到过这样的麻烦:MouseDoubleClick 事件(插入单词到文本)不会触发 MouseClick 事件(在鼠标下方显示选定单词的定义),直到我使用 Timer 延迟并仅在 MouseDoubleClick 不发生时执行 MouseClick。当用户只想通过单击导航器中的单词来探索定义时,导航器会加载一个新定义并将其显示在屏幕上。鼠标双击会告诉导航器将双击的单词插入用户正在处理的文本中。但是……双击事件的发生必须首先由第一次单击引起常规的单击事件。这导致用户单击一次(双击的第一次),加载一个新定义,然后双击新定义中的单词,从而将错误的单词插入用户的文本中。

为了解决这个问题,我添加了一个计时器。计时器有 500 毫秒的延迟,并在 MouseDown 事件中启用。

public static void RtxOutput_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Button == MouseButtons.Right)
    {
        WordUnderMouse_PopUpDefinition(sender);
    }
    else
    {
        rtxOutput_MouseClick_Sender = sender;
        rtxOutput_MouseClick_MouseEventArgs = e;
        tmrClick_WaitForDoubleClick.Interval = 500;
        tmrClick_WaitForDoubleClick.Enabled = !tmrClick_WaitForDoubleClick.Enabled;
    }
}

记录 MouseDown 事件的参数,并启用计时器。由于 MouseDoubleClick 会禁用计时器,因此当用户双击时,MouseClick 事件将被中止。

public static void RtxOutput_MouseDoubleClick(object sender, MouseEventArgs e)
{
    tmrClick_WaitForDoubleClick.Enabled = false;
    WordUnderMouse_Insert(sender, new Point(e.X, e.Y));
}

但是,如果用户花费的时间太长(500 毫秒)或者实际上只想单击一次,那么计时器的事件将被触发,并将执行单击所需的后续工作。

 
private void tmrClick_WaitForDoubleClick_Tick(object sender, EventArgs e)
{
    tmrClick_WaitForDoubleClick.Enabled = false;
    _RtxOutput_MouseClick(rtxOutput_MouseClick_Sender, rtxOutput_MouseClick_MouseEventArgs);
}



public static void _RtxOutput_MouseClick(object sender, MouseEventArgs e)
{
    if (bolIgnoreMouseUp)
    {
        bolIgnoreMouseUp = false;
        return;
    }
    rtxCalling = (RichTextBox)sender;
    switch (e.Button)
    {
        case MouseButtons.Left:
            {
                WordUnderMouse_Search(sender, new Point(e.X, e.Y));
            }
            break;

        case MouseButtons.Right:
            {
                WordUnderMouse_PopUpDefinition(sender);
            }
            break;

        case MouseButtons.Middle:
            break;
    }
}

更新

代码更新 - 最新更改

代码更新精华

 

 

      

 

 

© . All rights reserved.