【问题标题】:Get cursor position of winforms textbox获取winforms文本框的光标位置
【发布时间】:2015-08-18 08:29:23
【问题描述】:

如何在 .NET 中获取 winforms 文本框的当前光标(插入符号)位置? SelectionStart 仅返回所选文本的开头(选择的左侧)。表示如果光标位于所选内容的右侧,则此值错误。


澄清一下:在 .NET TextBox 中,SelectionStart 指向选择的左侧,当插入符号位于选择的右侧时也是如此。这意味着在两张图片中 SelectionStart 均为 2,但插入符号的位置在第一张图片中为 2,在右侧图片中为 7。

【问题讨论】:

  • “如果光标位于所选内容的右侧,则表示此值错误”是什么意思? SelectionStart + SelectionLength 有帮助吗?
  • @musefan:请阅读整个问题! SelectionStart 不能解决我的问题。
  • 对于那些不理解自己的问题的人(OP),请先阅读以下内容:当您选择文本并输入内容时会发生什么?它插入到选择的开头,因此它必须是插入符号的位置。无论您选择哪个方向,插入符号都将位于选择的开头
  • 什么?从技术上讲,光标始终位于选择的左侧,这就是您使用 SelectionLength 获取右侧位置的原因。

标签: c# .net winforms


【解决方案1】:

如前所述,SelectionStart 属性不能可靠地在选择活动的文本框中获取实际 CARET 位置。这是因为此属性始终指向选择开始处(提示:名称不会说谎),并且根据您使用鼠标选择文本的方式,插入符号可能位于选择的左侧或右侧.

此代码(使用 LinqPAD 测试)显示了替代方法

public class WinApi
{
    [DllImport("user32.dll")]
    public static extern bool GetCaretPos(out System.Drawing.Point lpPoint);
}

TextBox t = new TextBox();
void Main()
{
    Form f = new Form();
    f.Controls.Add(t);
    Button b = new Button();
    b.Dock = DockStyle.Bottom;
    b.Click += onClick;
    f.Controls.Add(b);
    f.ShowDialog();
}

// Define other methods and classes here
void onClick(object sender, EventArgs e)
{
    Console.WriteLine("Start:" + t.SelectionStart + " len:" +t.SelectionLength);
    Point p = new Point();
    bool result = WinApi.GetCaretPos(out p);
    Console.WriteLine(p);
    int idx = t.GetCharIndexFromPosition(p);
    Console.WriteLine(idx);
}

API GetCaretPos 返回 CARET 所在的客户端坐标点。您可以使用托管方法GetCharIndexFromPosition 在位置之后返回字符的索引。当然你需要在System.Runtime.InteropServices添加引用和使用。

不确定此解决方案是否存在一些缺点,并等待更多专家可以告诉我们是否有问题或下落不明。

【讨论】:

  • 不幸的是,这仅在 TextBox 具有焦点时才有效。因此,如果需要未聚焦的 TextBox 的插入符号位置,这将不起作用(除非您交换当前焦点以获取该位置,但这是一个丑陋的 hack)。
【解决方案2】:

有了史蒂夫的回答,这就是我现在的解决方案:

[DllImport("user32")]
private extern static int GetCaretPos(out Point p);

...

// get current caret position
Point caret;
GetCaretPos(out caret);
int caretPosition = tbx.GetCharIndexFromPosition(caret);

另外(不是我的问题的一部分)我可以使用以下代码设置插入符号和文本选择。 user32.dll 中还有一个对我不起作用的 SetCaret 函数。但令人惊讶的是,Select() 函数支持选择长度的负值。

// determine if current caret is at beginning
bool caretAtBeginning = tbx.SelectionStart == caretIndex;

...

// set text selection and caret position
if (caretAtBeginning)
    tbx.Select(selStart + selLength, -selLength);
else
    tbx.Select(selStart, selLength);

注意:这篇文章摘自问题并代表 OP 发布。

【讨论】:

    【解决方案3】:

    如果你想要左边的选择,你可以使用:

    int index = textBox.SelectionStart;
    

    如果你想要右边的选择,你可以使用:

    int index = textBox.SelectionStart + textBox.SelectionLength;
    

    如果您需要知道文本被选择的方向,那么您可以尝试跟踪鼠标向下和鼠标向上事件,并在事件触发时比较光标位置。

    例如:

    // On mouse down event.
    int mouseDownX = MousePosition.X;
    
    // On mouse up event.
    int mouseUpX = MousePosition.X;
    
    // Check direction.
    if(mouseDownX < mouseUpX)
    {
        // Left to Right selection.
        int index = textBox.SelectionStart;   
    }
    else
    {
        // Right to Left selection.
        int index = textBox.SelectionStart + textBox.SelectionLength;
    }
    

    【讨论】:

    • 好的,这可能是一种解决方法。所以我还必须跟踪键盘。如果没有更好的解决方案,我不得不接受这个。感谢这个想法。
    【解决方案4】:

    这可能对某人有用:

    int lastSelectionStart = 0;
    
    int getCaretPosition()
    {
        if (tbx.SelectionLength == 0)
        {
            lastSelectionStart = tbx.SelectionStart;
            return lastSelectionStart;
        }
        else
        {
            if (tbx.SelectionStart == lastSelectionStart)
            {
                return tbx.SelectionStart + tbx.SelectionLength;
            }
            else
            {
                return lastSelectionStart - tbx.SelectionLength;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-17
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 2010-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多