GetCharIndexFromPosition()获取最后一个字符

本文关键字:最后一个 字符 获取 GetCharIndexFromPosition | 更新日期: 2023-09-27 18:12:27

我想在RichTextBox中获得光标下的子字符串。

private void richTextBox1_MouseDown(object sender, MouseEventArgs e)
{
    if (e.Clicks == 1 && e.Button == MouseButtons.Left)
    {
        string wholeText = richTextBox1.Text;
        // Obtain the character index where the user clicks on the control. 
        int positionBegin = richTextBox1.GetCharIndexFromPosition(new Point(e.X, e.Y));
        SelectedText = wholeText.Substring(positionBegin);
    }

例如,如果我键入字符串World,然后将光标放在ld之间,则子字符串应该是d。到目前为止,我的代码是工作的,但是如果我把光标放在字符串的末尾,它仍然返回d

我期望在这种情况下它将返回空的then。它看起来像一只虫子。见http://www.pcreview.co.uk/forums/problem-getcharindexfromposition-t4037504.html

GetCharIndexFromPosition()获取最后一个字符

怎么会是bug?如果您查看描述,它会得到最接近的字符。最接近你点击的位置的字符实际上是最后一个字母。我没有看到源代码,但根据描述,它是按预期工作的。

在我对RichTextBox可用的方法的简要查看中,我没有看到一个可以轻松解决问题的方法。你可以做的是用一个实际的字符填充文本的结尾,例如:一个空格。

//...
string originalText = richTextBox1.Text;
richTextBox1.Text += " ";
//Your code to get the index and substring
//Return the textbox to its original state
richTextBox1.Text = originalText;
richTextBox1.SelectionLength = 0;
richTextBox1.SelectionStart = positionBegin;

应该做你正在寻找的,但它是相当简单的,将是低效的取决于你正在处理的文本量。如果您想创建一个功能类似GetCharIndexFromPosition(Point pt)的方法,您可能会在非托管代码领域结束。


编辑:因为我很好奇(扩展方法解决方案)

我开始查看RichTextBox控件的源代码,它确实阻止你选择文本长度的最大长度以外的字符,如下所示:

public override int GetCharIndexFromPosition(Point pt) {
    NativeMethods.POINT wpt = new NativeMethods.POINT(pt.X, pt.Y);
    int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.EM_CHARFROMPOS, 0, wpt);
    string t = this.Text;
    //This bit is stopping you from getting an index outside the length of the text
    if (index >= t.Length) {
        index = Math.Max(t.Length - 1, 0);
    }
    return index;
}

"fix"你可以创建一个扩展方法,以同样的方式实现它,但删除检查索引是否大于文本长度的部分:

public static class RichTextBoxExtensions
{
    private const int EM_CHARFROMPOS = 0x00D7;
    public static int GetTrueIndexPositionFromPoint(this RichTextBox rtb, Point pt)
    {
        POINT wpt = new POINT(pt.X, pt.Y);
        int index = (int)SendMessage(new HandleRef(rtb, rtb.Handle), EM_CHARFROMPOS, 0, wpt);
        return index;
    }
    [DllImport("User32.dll", EntryPoint = "SendMessage", CharSet = CharSet.Auto)]
    private static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, POINT lParam);
}
[StructLayout(LayoutKind.Sequential)]
internal class POINT
{
    public int x;
    public int y;
    public POINT()
    {
    }
    public POINT(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

这样你就回到了原来的代码!只需将GetCharIndexFromPosition更改为GetTrueIndexPositionFromPoint,它将按预期工作

另一个(简单的)解决方案。
我也有同样的问题,只有在我的情况下,富文本框在自定义透明面板下面,在单击透明面板后,我必须将光标放在富文本框内的正确位置。这是我决定使用的一个解决方案,因为所有其他解决方案看起来都更复杂。只需获得富文本框中最后一个字符的点。然后将其与您单击的位置进行比较,并根据比较结果进行适当的调整。看看我在应用程序中使用的代码。注意'GetCharIndexFromPosition()''GetPositionFromCharIndex()'。我希望这能帮助下一个人,或者至少激发他们的创造力,想出一个更聪明的解决方案。

private void transparentPanel_Click(object sender, System.EventArgs e)
        {
            var mouseEventArgs = e as MouseEventArgs;
            if (mouseEventArgs.Button == MouseButtons.Left)
            {
                // If currently in text editing mode
                if (m_currentSelectedControl == e_SelectedControl.TEXT)
                {
                    Point capturedPoint = new Point(mouseEventArgs.X, mouseEventArgs.Y);
                    int charIndex = richTextBox.GetCharIndexFromPosition(capturedPoint);
                    int lastChar = richTextBox.TextLength;
                    Point lastCharPoint = richTextBox.GetPositionFromCharIndex(lastChar);
                    if (lastCharPoint.X == capturedPoint.X ||
                        lastCharPoint.Y < capturedPoint.Y)
                    {
                        charIndex++;
                    }
                    richTextBox.SelectionStart = charIndex;
                    richTextBox.SelectionLength = 0;
                    richTextBox.Select();
                    transparentPanel.Refresh();
                }
            }
        }

这是已知的记录行为。GetCharIndexFromPosition方法文档的备注部分包含以下重要说明:

如果指定的位置不在客户端矩形内控件,或者超出控件中的最后一个字符,返回Value是最后一个字符的索引。