我通过为插入和覆盖模式创建插入符来扩展richtextbox。问题是测量的宽度太宽。这在较大的字体大小时最明显。
SelectionFont.Height
返回的高度是正确的。是否没有类似的Width属性?
如何准确测量指定字符ch
的宽度?任何人都可以提供一个例子吗?
下面是转换为C#的代码,下面是VB.NET中的代码:
using System;
public class RichTextBoxCaret : RichTextBox
{
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private extern static void CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
[DllImport("user32.dll", CharSet=CharSet.Auto)]
private extern static void ShowCaret(IntPtr hWnd);
private bool mInsertKeyState = true;
protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e)
{
base.OnKeyDown(e);
if (e.KeyCode == Keys.Insert)
{
mInsertKeyState = !mInsertKeyState;
}
this.DrawCaret();
}
protected override void OnMouseUp(System.Windows.Forms.MouseEventArgs mevent)
{
base.OnMouseUp(mevent);
this.DrawCaret();
}
public void DrawCaret()
{
Size sz = new Size(0, 0);
if (this.SelectionFont != null)
{
if (!mInsertKeyState && this.SelectionStart < this.TextLength)
{
using (Graphics g = this.CreateGraphics)
{
using (Font f = new Font(this.SelectionFont.FontFamily, this.SelectionFont.Size, this.SelectionFont.Style, GraphicsUnit.Pixel, Convert.ToByte(0), false))
{
char ch = this.Text[this.SelectionStart];
sz.Width = Convert.ToInt32(g.MeasureString(ch, f).Width * this.ZoomFactor);
}
}
}
sz.Height = Convert.ToInt32(this.SelectionFont.Height * this.ZoomFactor);
}
if (!sz.IsEmpty)
{
CreateCaret(this.Handle, IntPtr.Zero, sz.Width, sz.Height);
ShowCaret(this.Handle);
}
}
}
对于VB.NET:
Public Class RichTextBoxCaret
Inherits RichTextBox
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub CreateCaret(ByVal hWnd As IntPtr, ByVal hBitmap As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer)
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub ShowCaret(ByVal hWnd As IntPtr)
End Sub
Private mInsertKeyState As Boolean = True
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
MyBase.OnKeyDown(e)
If e.KeyCode = Keys.Insert Then
mInsertKeyState = Not mInsertKeyState
End If
Me.DrawCaret()
End Sub
Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseUp(mevent)
Me.DrawCaret()
End Sub
Public Sub DrawCaret()
Dim sz As New Size(0, 0)
If Me.SelectionFont IsNot Nothing Then
If Not mInsertKeyState AndAlso Me.SelectionStart < Me.TextLength Then
Using g As Graphics = Me.CreateGraphics
Using f As New Font(Me.SelectionFont.FontFamily, Me.SelectionFont.Size, Me.SelectionFont.Style, GraphicsUnit.Pixel, CByte(0), False)
Dim ch As Char = Me.Text.Chars(Me.SelectionStart)
sz.Width = CInt(g.MeasureString(ch, f).Width * Me.ZoomFactor)
End Using
End Using
End If
sz.Height = CInt(Me.SelectionFont.Height * Me.ZoomFactor)
End If
If Not sz.IsEmpty Then
CreateCaret(Me.Handle, IntPtr.Zero, sz.Width, sz.Height)
ShowCaret(Me.Handle)
End If
End Sub
End Class
答案 0 :(得分:1)
使用GetPositionFromCharIndex
解决了宽度问题。
最终实施:
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub CreateCaret(ByVal hWnd As IntPtr, ByVal hBitmap As IntPtr, ByVal nWidth As Integer, ByVal nHeight As Integer)
End Sub
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Sub ShowCaret(ByVal hWnd As IntPtr)
End Sub
Private mInsertKeyState As Boolean = True
Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
MyBase.OnKeyDown(e)
If e.KeyCode = Keys.Insert Then
mInsertKeyState = Not mInsertKeyState
End If
Me.DrawCaret()
End Sub
Protected Overrides Sub OnMouseUp(ByVal mevent As System.Windows.Forms.MouseEventArgs)
MyBase.OnMouseUp(mevent)
Me.DrawCaret()
End Sub
Public Sub DrawCaret()
Dim nHeight As Integer = 0
Dim nWidth As Integer = 0
If Me.SelectionFont IsNot Nothing Then
nHeight = CInt(Me.SelectionFont.Height * Me.ZoomFactor)
Else
nHeight = CInt(Me.Font.Height * Me.ZoomFactor)
End If
If Not mInsertKeyState AndAlso Me.SelectionStart < Me.TextLength Then
Dim p1 As Point = MyBase.GetPositionFromCharIndex(Me.SelectionStart)
Dim p2 As Point = MyBase.GetPositionFromCharIndex(Me.SelectionStart + 1)
nWidth = p2.X - p1.X
End If
CreateCaret(Me.Handle, IntPtr.Zero, nWidth, nHeight)
ShowCaret(Me.Handle)
End Sub