0

挿入モードと上書きモード用のキャレットを作成して、リッチテキスト ボックスを拡張しています。問題は、測定された幅が広すぎることです。これは、大きなフォント サイズで最も顕著です。

から返された高さ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
4

1 に答える 1

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
于 2012-08-19T20:46:15.803 に答える