Зная местоположение точки каретки в текстовом поле Winforms? - PullRequest
7 голосов
/ 02 декабря 2009

Мне нужно знать точное местоположение точки в моем окне, где в данный момент находится каретка, чтобы я мог открыть маленькое окно под текстом (похоже на intellisense или проверку орфографии). Проблема в том, что GetPositionFromCharIndex не работает с TextBox. Вот что я пытаюсь сделать:

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

Однако GetPositionFromCharIndex всегда возвращает (0, 0) для TextBoxes (очевидно, это не реализовано, как это делается для RichTextBox). Хотя эта функция (и этот код) отлично работает для RichTextBoxes, я не хочу переносить остальную часть моего кода из TextBox в RichTextBox, за исключением случаев, когда используется абсолютный LAST курорт. Существует так много несовместимостей с RichTextBox / TextBox, что мне придется переписать очень большой кусок моего кода, чтобы сделать это.

Есть ли мастера Winforms, которые знают, как это сделать?

Ответы [ 7 ]

7 голосов
/ 02 декабря 2009

Если вы не возражаете против использования Win32-API, используйте GetCaretPos для получения точной позиции.

5 голосов
/ 02 декабря 2009

Я обнаружил странное поведение элемента управления textbox. Когда вы вводите текст в конце текстового поля, GetPositionFromCharIndex остается 0,0. Однако если вы вставите текст перед последним символом в текстовом поле, GetPositionFromCharIndex IS обновится.

Не знаю, можете ли вы использовать это в своих интересах, но я думаю, вы, возможно, хотели бы это знать.

Редактировать: Хорошо, LOL, это похоже на работу, как ужасно это может быть ...:

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 голос
/ 02 декабря 2009

Прикрепите следующий фрагмент кода в событии 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 для правильного вычисления фактической длины строки до положения курсора в элементе управления. При выполнении всплывающего окна «Автозаполнение» в стиле «Intellisense» важно знать фактическую позицию на экране, чтобы открыть список «Автозаполнение».

Это то, что делает фрагмент. Он вычисляет ширину текста, затем преобразует ее с помощью «локальной» координаты в элемент управления TextBox и оттуда преобразует эту точку в соответствующую экранную координату.

Одно замечание: SelectionStart задерживается и не обновляется немедленно. Отчасти это связано с тем, как элемент управления текстового поля обрабатывает ввод с клавиатуры.

0 голосов
/ 08 сентября 2018

Вот мое решение:

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 голосов
/ 03 июля 2017

Попробуйте это.

Под событием 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 голосов
/ 02 декабря 2009
MessageBox.Show(textBox1.SelectionStart.ToString());
0 голосов
/ 02 декабря 2009
 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.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...