在Winforms文本框中如何知道插入符的位置?

7

我需要知道插入符号当前所在窗口的确切点位置,以便我可以在文本下方弹出一个小窗口(类似于Intellisense或拼写检查器)。问题在于,GetPositionFromCharIndex 在 TextBoxes 上似乎不起作用。这就是我想做的:

Point pt = mTextBox.GetPositionFromCharIndex(mTextBox.SelectionStart);
pt.Y = (int)Math.Ceiling(mTextBox.Font.GetHeight());
mListBox.Location = pt;

然而,对于文本框(显然它没有像RichTextBox一样实现),GetPositionFromCharIndex始终返回(0, 0)。虽然这个函数(和这段代码)可以在RichTextBox中正常工作,但我不想除非万不得已,否则将我的代码从TextBox迁移到RichTextBox。RichTextBox/TextBox有太多的不兼容性,我必须重写很大一部分代码才能实现这个目标。
有没有Winforms专家知道如何做到这一点?
7个回答

7
如果您不介意使用 Win32-API,请使用 GetCaretPos 获取精确位置。

5

我发现了文本框控件的一些奇怪行为。当你在文本框末尾输入文本时,GetPositionFromCharIndex仍然是0,0。但是,如果你在文本框中插入最后一个字符之前的文本,GetPositionFromCharIndex会被更新。

不知道你是否能够利用这个特性,但我认为你可能想知道这个。

编辑:好吧,哈哈,这似乎可行,无论它多丑陋...

Point pt = textBox1.GetPositionFromCharIndex(textBox1.SelectionStart > 0 ? textBox1.SelectionStart - 1 : 0);

编辑2:回顾来看,我认为这种行为并不奇怪,因为文本框末尾的SelectionStart返回下一个字符将被键入的索引,而不是实际上字符所在的位置。由于GetPositionFromCharIndex将返回字符位置,因此尚不存在的字符的索引显然返回0,0。

编辑3:通过我的代码和MikeJ的代码组合并稍作修改,您可以获得插入符号的确切位置:

SizeF size = g.MeasureString(textBox1.Text.Substring(textBox1.SelectionStart - 1, 1), textBox1.Font);
pt.X += (int)size.Width;

我承认,我打的方式非常丑陋,但经过一些编辑,您应该能够得到一些漂亮的代码。


1

将以下代码片段附加到TextBox.KeyDown事件中,以定位文本框控件内光标的屏幕点:

using (Graphics g = Graphics.FromHwnd(textBox1.Handle))
{
    SizeF size = g.MeasureString(textBox1.Text.Substring(0, textBox1.SelectionStart), textBox1.Font);

Point pt = textBox1.PointToScreen(new Point((int)size.Width, (int)0));
    label1.Text = "Manual: " + pt.ToString();
}

上面的代码片段考虑了TextBox控件使用的字体,以正确计算控件内光标位置之前字符串的实际长度。在执行“智能感知”样式的自动完成弹出窗口时,重要的是要知道实际屏幕位置,以便弹出“自动完成”列表。
这就是代码片段所做的。它计算文本的宽度,然后将其转换为TextBox控件的“本地”坐标,并从那里将该点转换为相关的屏幕坐标。
需要考虑的一个注意事项:选择的起始位置SelectionStart会有延迟并且不会立即更新。这部分原因是由于文本框控件如何处理键盘输入。

0

这是我的解决方案:

private Point GetCaretPosition()
{
    Point result = TextBox.GetPositionFromCharIndex(TextBox.SelectionStart);


    if (result.X == 0 && TextBox.Text.Length > 0)
    {
        result = TextBox.GetPositionFromCharIndex(TextBox.Text.Length - 1);
        int s = result.X / TextBox.Text.Length;
        result.X = (int)(result.X + (s * 1.3));
    }


    return result;
}

0
尝试这个。
在`Control.KeyPress`事件下,
我使用`Control.GetPositionFromCharIndex(Control.SelectionStart)`来获取与控件相关的插入符位置。然后将这个位置转换为窗体的新位置,在屏幕上进行翻译。
private void aTextBox_KeyPress(object sender, KeyPressEventArgs e)
{
    SuperComboForm supcomboF = new SuperComboForm();
    supcomboF.StartPosition = FormStartPosition.Manual;
    var caret_pos = aTextBox.GetPositionFromCharIndex(aTextBox.SelectionStart);
    supcomboF.Location = PointToScreen(new Point(caret_pos.X, caret_pos.Y));
    supcomboF.ShowDialog();
}

0
 TextBox lbl = new TextBox(); 
                 lbl.Text = Build("20000", i);
                 lbl.Location = new Point(30, 25 * i);
                 lbl.Width = 350;
                 lbl.MouseHover += new EventHandler(lbl_MouseHover);

   void lbl_MouseHover(object sender,
 EventArgs e)
         {
             TextBox t = (TextBox)sender;
             ListBox lb = new ListBox();
             for (int i = 0; i < 10; i++)
             {
                 lb.Items.Add("Hej");
             }
             int x = t.Location.X; 
             int y = t.Location.Y + t.Height;
             lb.Location = new Point(x, y);
             panel1.Controls.Add(lb);
             lb.BringToFront(); 
         }

请注意以下代码片段: int y = t.Location.Y + t.Height; 将文本框的高度添加到y轴上。

0
MessageBox.Show(textBox1.SelectionStart.ToString());

不是SelectionStart属性出了问题,而是GetPositionFromCharIndex的行为很奇怪。 - Webleeuw
尝试使用 mListBox.Location = Cursor.Position; - KMån

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接