【问题标题】:GetCharIndexFromPosition() for the last charGetCharIndexFromPosition() 获取最后一个字符
【发布时间】:2016-02-04 12:29:43
【问题描述】:

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

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

【问题讨论】:

  • 调试确定positionBegin的值。
  • @EvanMulawski,不,调试不起作用。好像是GetCharIndexFromPosition的bug。
  • 空白空间没有字符索引。您将需要使用 GetPositionFromCharIndex() 并查看您已关闭了多少。
  • @HansPassant,困难的部分是GetPositionFromCharIndex() 在我提到的位置返回相同的索引。
  • 它不返回索引,它返回一个点。将其与鼠标位置进行比较。

标签: c# .net winforms


【解决方案1】:

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

在简要了解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 即可按预期工作。

【讨论】:

  • @Love 查看我的更新。这应该比操纵RichTextBox 控件更适合您的需求。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-07-07
      • 2011-08-17
      • 1970-01-01
      • 1970-01-01
      • 2021-09-18
      相关资源
      最近更新 更多