NHunspellToolTip - 使用 Hunspell for .NET 的拼写检查 ToolTip






4.86/5 (13投票s)
此 ToolTip 允许您在看不到全部文本时,对项目或控件的文本进行拼写检查。
- 下载 NHunspellToolTip 源代码 (VS2010) - 600 KB
- 下载 NhunspellToolTip DLL (适用于 .NET 4.0 Framework) - 1.12 MB
- 下载 NhunspellToolTip DLL (适用于 .NET 3.5 Framework) - 1.12 MB
背景
作为程序员,我们经常被要求开发一个界面来方便地访问数据库。在我的例子中,我处理的是一个使用雪花模型设计的数据库。某些表包含与其他包含数据的表相关的索引。例如,有三个级别的“操作”:“目标”、“恢复操作”和“操作步骤”。其中任何一个都可以包含优先级、成本、持续时间、恢复合作伙伴和评论的信息,以及操作文本。在人眼看来,数据库是无法阅读的。
在开发用户访问的 GUI 时,用户无需从一个屏幕修改所有信息。相反,我想向用户提供数据的快照,并使用 ToolTip
提供更详细的信息,使用 ContextMenu
编辑这些信息。提供信息的控件是一个自定义的 ListView
(如下所示)。
这效果很好,用户发现使用 GUI 浏览数据库很容易。然而,我很快意识到我们的用户在输入时不够小心,产生了大量的拼写错误。因此,我想提供一种方法,让用户获得一个视觉提示,表明他们犯了拼写错误。
为此,我开发了一个 IExtenderProvider
,它将扩展 TextBox
以提供类似 Microsoft Word 的即时拼写检查功能。我使用了 Hunspell for .NET 并创建了 NHunspellTextBoxExtender
。我可以在用户编辑文本时使用 TextBox
扩展程序,但这仍然没有为主窗体上的信息(由 ListView
提供)提供任何拼写检查功能。
那么,问题来了,我如何提供这个视觉提示,表明信息中有拼写错误呢?我已经在使用 ToolTip
提供信息了,为什么不创建一个可以拼写检查其文本并以这种方式提供视觉提示的 ToolTip
呢?这样,用户就可以看到拼写错误,并进去修复它。这个自定义 ToolTip
提供了如下所示的功能:
拼写检查 ToolTip
与我之前的控件(NHunspellTextBoxExtender
)不同,对于这个控件,我不需要使用 IExtenderProvider
,因为我只改变了一个 ToolTip
。相反,我选择创建一个继承自 ToolTip
的新控件。拼写检查与 TextBox
版本非常相似。但因为我将其限制为仅显示,并且因为控件的文本只会设置,而不会追加或截断,所以我可以精简 SpellCheckControl
。
SpellCheckControl
SpellCheckControl
负责所有拼写检查。当 ToolTip
收到 Draw
命令时,它会调用 SpellCheckControl
的 SetText
方法。SetText
方法会遍历所有文本,查找任何拼写错误的单词,并使用 CharacterRange
来识别它们。
类结构如下所示
Imports System.Drawing
Imports System.IO
Imports System.Windows.Forms
Imports System.Reflection
Public Class SpellCheckControl
Private FullText As String
Private _Text(,) As String
Public myNHunspell As Object = Nothing
Private _spellingErrors() As String
Private _spellingErrorRanges() As CharacterRange
Public Sub New(ByRef HunspellObject As Object)
Public Sub SetText(ByVal Input As String)
Private Function FindFirstLetterOrDigitFromPosition(_
ByVal SelectionStart As Long) As Long
Private Function FindLastLetterOrDigitFromPosition(_
ByVal SelectionStart As Long) As Long
Public Function GetSpellingErrorRanges() As CharacterRange()
Public Function HasSpellingErrors() As Boolean
Public Sub SetSpellingErrorRanges()
End Class
ToolTip Draw
一旦识别出拼写错误(由于 NHunspell,速度非常快),ToolTip
就需要被绘制。要做到这一点,我只需要处理 ToolTip_Draw
方法。此时,我已经使用 e.DrawBackground()
命令绘制了背景。下一步是绘制红色的波浪线。要做到这一点,我们首先必须识别出拼写错误的位置,并确定红色线条应该绘制在哪里。这有点棘手,因为我们必须跟踪当前文本所在的行。
但是,一旦我们确定了绘制线条的位置,我们就必须实际绘制它。我使用了一些可以在这个 博客 上找到的代码。Draw
事件的完整代码如下所示:
Private Sub NHunspellToolTip_Draw(ByVal sender As Object, _
ByVal e As System.Windows.Forms.DrawToolTipEventArgs) _
Handles Me.Draw
e.DrawBackground()
mySpellCheckControl.SetText(e.ToolTipText)
'Now we do the custom drawing
myBitmap = New Bitmap(e.Bounds.Width, e.Bounds.Height)
bufferGraphics = Graphics.FromImage(myBitmap)
bufferGraphics.Clip = New Region(e.Bounds)
Dim currentRange As CharacterRange
For Each currentRange In mySpellCheckControl.GetSpellingErrorRanges
Dim startPoint, endPoint As Point
Dim bottom, left, right As Integer
'Determine which line the current word is on
Dim lastNewline As Integer = 1
For i = 1 To currentRange.First
If Mid(e.ToolTipText, i, 1) = vbLf Then
lastNewline = i + 1
End If
Next
'Get the text of the line to the end of the word
Dim lineToEndofWord As String = Mid(e.ToolTipText, lastNewline, _
((currentRange.First - lastNewline) + _
currentRange.Length + 1))
'Figure out how wide and tall the text before this is word is
'Measure the text starting from the beginning
'to the end of the word to get the borrom coordinates
Dim newSize As SizeF = _
TextRenderer.MeasureText(Microsoft.VisualBasic.Strings.Left(e.ToolTipText, _
(currentRange.First + currentRange.Length)), _
e.Font, e.Bounds.Size, TextFormatFlags.Left)
bottom = newSize.Height - 2
'Now measure the text from the beginning of the current line
'to the end of the word to get the right coordinates
newSize = TextRenderer.MeasureText(lineToEndofWord, e.Font, _
e.Bounds.Size, TextFormatFlags.Left)
right = newSize.Width
endPoint = New Point(right, bottom)
'Now we can backtrack and find out how wide that text is
newSize = TextRenderer.MeasureText(Mid(e.ToolTipText, _
currentRange.First + 1, currentRange.Length), _
e.Font, e.Bounds.Size, TextFormatFlags.Left)
left = right - newSize.Width
startPoint = New Point(left, bottom)
startPoint.X += 2
endPoint.X -= 4
DrawWave(startPoint, endPoint)
Next
toolTipGraphics = e.Graphics
toolTipGraphics.DrawImageUnscaled(myBitmap, 0, 0)
e.DrawBorder()
Dim stringFlags As New StringFormat()
stringFlags.Alignment = StringAlignment.Near
stringFlags.LineAlignment = StringAlignment.Near
TextRenderer.DrawText(e.Graphics, e.ToolTipText, e.Font, _
e.Bounds, Color.Black, flags:=TextFormatFlags.Left)
End Sub
Using the Code
就是这样!这个工具非常简单易用……只需从上面的链接下载 DLL,并将其添加到您的工具箱之一。拼写检查会自动完成,并且这个 ToolTip
可以像标准的 ToolTip
一样使用。
关注点
我能够用这个 ToolTip
实现一些不同的东西。我不确定为什么我无法在 NHunspellTextBoxExtender
中让它工作,但我可以在没有 NHunspell.dll 文件的情况下加载这个 ToolTip
。这意味着当我打包这个工具时,我不需要包含 NHunspell.dll。为了做到这一点,我将 NHunspell.dll 文件嵌入到项目中。然后,当我创建 Hunspell
对象时,我使用原始程序集来创建它。
这需要一些工作,而且你必须预先知道参数。首先,我必须加载程序集。这只需要一行代码
Dim a As Assembly = Assembly.Load(My.Resources.NHunspell)
然后我必须获取我试图创建的对象的 Type
,并创建一个 ConstructorInfo
类。Hunspell
对象的构造函数接受两个字符串。执行此操作的代码需要更多几行代码,但仍然相对简单:
Dim type_l As Type = a.GetType("NHunspell.Hunspell")
Dim types(1) As Type
types(0) = GetType(String)
types(1) = GetType(String)
Dim ctor As ConstructorInfo = type_l.GetConstructor(types)
最后要做的是 Invoke
构造函数,它将返回一个 Object
。要做到这一点,我必须设置将要传递的参数。Invoke
方法接受一个 Objects
数组。Hunspell
的第一个参数是 .aff 文件,第二个参数是 .dic 文件。不进行任何错误检查的实现如下所示:
Dim params(1) As Object
params(0) = USaff
params(1) = USdic
Dim result As Object = Nothing
result = ctor.Invoke(params)
当我实际执行此操作时,我会将 result = ctor.Invoke(params)
放入一个 Try
/Catch
块中,因为我必须确保几个非托管 DLL 可用。我已在我的 NHunspellTextBoxExtender 文章 中提供了更多相关信息。
这种方法唯一的问题是 Visual Studio 的 IntelliSense 将无法按此方式工作。这就是为什么这个步骤要到最后才实现。在此之前,我包含对 NHunspell DLL 的引用,这为我提供了 IntelliSense。然后,在最终确定之前,我只需注释掉那个 Import
语句,并将 Hunspell
对象更改为 Object
。
历史
- 2010 年 2 月 17 日:创建文章。