最后一个char的GetCharIndexFromPosition()

时间:2014-07-10 17:21:11

标签: c# .net winforms

我想在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

我希望在这种情况下它会返回空。它看起来像一个bug。见http://www.pcreview.co.uk/forums/problem-getcharindexfromposition-t4037504.html

3 个答案:

答案 0 :(得分:4)

这怎么一个错误?如果您查看描述,它会获得最接近的字符。与您单击的位置最接近的字符确实是最后一个字母。我没有看到来源,但根据描述,它正在按预期工作。

在我简要介绍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;
}

要“修复”这个,您可以创建一个以相同方式实现它的扩展方法,但删除有关检查索引是否大于文本长度的位:

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即可按预期工作。

答案 1 :(得分:0)

另一个(简单)解决方案。
我有同样的问题,只有在我的情况下,富文本框位于自定义透明面板下方,点击透明面板时我必须将光标放在右侧富文本框中的位置。这是我决定使用的解决方案,因为所有其他解决方案看起来更复杂。只需获取富文本框中最后一个字符的点即可。然后将其与您点击的位置进行比较,并根据比较结果进行适当的调整。看看我用于我的应用程序的代码。请注意'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();
                }
            }
        }

答案 2 :(得分:0)

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

  

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