知道Winforms TextBox中插入符号的点位置?

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

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

但是,GetPositionFromCharIndex总是为TextBoxes返回(0,0)(显然它没有像RichTextBox那样实现)。 虽然这个函数(和这个代码)适用于RichTextBoxes,但我不想将我的其余代码从TextBox迁移到RichTextBox,除非是绝对的LAST度假胜地。 与RichTextBox / TextBox有很多不兼容的地方,我必须重写我的代码中的大部分代码才能做到这一点。

是否有任何Winforms巫师知道如何做到这一点?

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

我发现了文本框控件的一些特殊行为。 当您在文本框的末尾键入文本时,GetPositionFromCharIndex仍为0,0。 但是,如果在文本框中的最后一个字符之前插入文本,则会更新GetPositionFromCharIndex。

不知道你是否可以利用它,但我想你可能想知道这一点。

编辑:好的,大声笑,这似乎工作,它可能是多么丑陋……:

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

编辑2:回想起来,我认为行为并不那么奇怪,因为文本框末尾的SelectionStart会返回下一个字符将被输入的索引,而不是最后一个字符的实际位置。 由于GetPositionFromCharIndex将返回一个字符位置,因此尚未存在的char的索引显然返回0,0。

编辑3:随着我和MikeJ的代码组合并略微重新设计,您可以获得插入符号的确切位置:

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

我承认,我输入它的方式真是太可怕了,但是通过一些编辑,你应该可以从中获得一些不错的代码。

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会延迟而不会立即更新。 这部分是由于文本框控件如何处理键盘输入。

  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轴。

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

试试这个。

在`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(); } 

这是我的解决方案:

 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; }