Russian Qt Forum
Сентябрь 30, 2024, 14:43 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: [РЕШЕНО] Определить QRect для слова в QLabel  (Прочитано 9215 раз)
Alp
Гость
« : Сентябрь 11, 2009, 18:56 »

Надо сделать (точнее, он уже сделан, надо подумать как его улучшить) виджет на базе QLable с "активными зонами". Ну, например, какое-то слово подсвечено и при клике на нем появляется окошко редактора прямо поверх слова (то, что называют in-place редактирование), после чего юзер вбивает туда что-то и завершает работу с этим редактором (нажатие Enter, потеря фокуса - неважно). Содержимое эдита после этого замещает слово на котором был произведен клик. И второй случай - с менюшками (с ними проще)

В принципе, такой код есть, писанный мной, но под кайро. Там сначала бьется по словам весь текст, потому считается прямоугольник для каждого слова, проверяются границы окна и список хот-ректов запоминается для дальнейшего использования. В общем сложно для чтения, но работает.

Сейчас думаю как бы это попроще реализоваться средствами Qt. Пока в голову пришло QLabel + хтмл-ссылки (и подсветка и стили и передача типа поля/кода поля впо ссылке). Проблема одна: как попроще получить список прямоугольников для слов. Или хотя бы определить QRect для кликнутого слова.

С меню проблем особых нет - взял координаты клика по OnLinkActivated, показал меню, заместил нужное, показал на лейбле, то с редактирование сложнее.

Есть какие-нибудь мысли или пинки в нужном направлении?
« Последнее редактирование: Сентябрь 23, 2009, 19:45 от alp » Записан
Rcus
Гость
« Ответ #1 : Сентябрь 11, 2009, 19:15 »

Я думаю нужно скорее смотреть в сторону классов Rich Text Processing - эта часть управляет текстом в стандартных текстовых виджетах и имеет довольно развитый публичный API.
Записан
SABROG
Гость
« Ответ #2 : Сентябрь 11, 2009, 20:59 »

По идее можно подсмотреть в коде QLineEdit, он же с точностью определяет между какими буквами был сделан клик, чтобы установить курсор ввода.
Записан
Alp
Гость
« Ответ #3 : Сентябрь 12, 2009, 07:02 »

Я думаю нужно скорее смотреть в сторону классов Rich Text Processing - эта часть управляет текстом в стандартных текстовых виджетах и имеет довольно развитый публичный API.
Думаю, это будет уже оверхэд. Проще тогда использовать описанный мной алгоритм.
Записан
Alp
Гость
« Ответ #4 : Сентябрь 12, 2009, 07:36 »

По идее можно подсмотреть в коде QLineEdit, он же с точностью определяет между какими буквами был сделан клик, чтобы установить курсор ввода.
Посмотрел. Определение позиции курсора по QPoint реализуется через вызов QLineEditPrivate::xToPos(const QPoint&). А вот имплементацию этого метода в /qt/qt/src  почему-то найти не могу. Точнее, вобще не могу найти имплементацию QLineEditPrivate. Может у тебя получится?

Но в целом идея здравая. Попробую сделать невидимый QLineEdit, по точке определять позицию курсора (она же - индекс символа в тексте), и по ней определять границы слова. Затем немного магии: ставим курсов в начало слова, дергаем за cursorRect(), затем переставляем курсор в конец слова и снова дергаем за тот же метод. В итоге имеем два прямоугольника описывающих _курсор_ в начале слова и в конце. Оттуда получаем координаты нужного QRect для слова целиком.

Попробую реализовать.
Записан
Rcus
Гость
« Ответ #5 : Сентябрь 12, 2009, 09:00 »

Думаю, это будет уже оверхэд. Проще тогда использовать описанный мной алгоритм.
/* sigh */ Знаете что идея высказанная в последнем посте тоже использует классы обработки текста (QTextLayout в частности). Давайте поговорим об оверхеде, да.
Записан
Alp
Гость
« Ответ #6 : Сентябрь 12, 2009, 12:28 »

Думаю, это будет уже оверхэд. Проще тогда использовать описанный мной алгоритм.
/* sigh */ Знаете что идея высказанная в последнем посте тоже использует классы обработки текста (QTextLayout в частности). Давайте поговорим об оверхеде, да.
Почитал раздел связанный с Rich Text. Нет там ничего особенного за исключением мыслей высказанных выше.

Надо ведь не только определить "вот слово, по которому кликнули", надо еще хранить информацию о типе поля, о текстовом его содержимом. В итоге: тип входных данных тот же.
Начальная обработка текста: построение коллекции прямоугольников и типов данных для каждого из них
Обработчик клика: определить какой прямоугольник содержит точку и вывести необходимые данные.

Единственная мысль хоть как-то связанная с RT-работой - использовать не QLineEdit, QTextEdit? т.к. первый не умеет перенос строк. В остальном удобных методов получения чего надо в общем-то и нет.
Записан
SABROG
Гость
« Ответ #7 : Сентябрь 12, 2009, 12:36 »

QLineEdit использует публичный класс QTextLine. А именно метод:
int QTextLine::xToCursor ( qreal x, CursorPosition cpos = CursorBetweenCharacters ) const

Возможно даже, что все уже есть. Остается только это применить, в документации класс описан. И где-то я в QQ видел применение этого класса для отрисовки текста.
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #8 : Сентябрь 12, 2009, 12:41 »

А если просто создать "сверху" нужные QLineEdit'ы и замаскировать их под static text ?
Записан
Alp
Гость
« Ответ #9 : Сентябрь 12, 2009, 12:59 »

QLineEdit использует публичный класс QTextLine. А именно метод:
int QTextLine::xToCursor ( qreal x, CursorPosition cpos = CursorBetweenCharacters ) const

Возможно даже, что все уже есть. Остается только это применить, в документации класс описан. И где-то я в QQ видел применение этого класса для отрисовки текста.
Пришлось отказаться от столь подходящего QLineEdit, т.к. в легенде (отображаемом тексте с хотспотами) могут быть символы перевода строки. Методы переводящие точку в позицию курсора и наоборот уже нашел.
Записан
Alp
Гость
« Ответ #10 : Сентябрь 12, 2009, 13:00 »

А если просто создать "сверху" нужные QLineEdit'ы и замаскировать их под static text ?
Была мысль. Но что делать если длина строки превышает ширину виджета? Вручную бить на несколько QLineEdit? =)
Записан
Alp
Гость
« Ответ #11 : Сентябрь 12, 2009, 13:22 »

К сожалению, проблема решена. Точнее, придется использовать старый алгоритм с разбивкой по словам и подсчетом размеров каждого слова.

Использовать для этих целей QTextEdit и QLineEdit не получится, т.к. метод cursorRect возвращает именно rect, а не геометрию. Т.е. начальная точка курсора всегда будет (0,0).

У QLineEdit cursorRect вообще защищеный, так что при всем желании не взять координаты каретки.

Далее, не совсем понятно как использовать QTextEdit, в отсутствии нормальных программных методов перемещения по тексту. Либо вызывать в цикле moveCursor(NextChar), либо никак. Других методов программно переместить курсор-каретку, похоже, нет. Аналогичные методы у QTextCursor'а не перемещают каретку.
« Последнее редактирование: Сентябрь 12, 2009, 13:37 от alp » Записан
Alp
Гость
« Ответ #12 : Сентябрь 23, 2009, 19:45 »

В результате получилось вот что:

Код
C++ (Qt)
QVector<QRectF> CalcRectsForLines(QRect boundingRect,
                                 const QFontMetrics& fm, const QString& source )
{
   QVector<QRectF> result;
 
   double xPos = 0, yPos = 0;
   int lineCount = 0;
 
   const double lineHeight = fm.height();
   const double spaceWidth = fm.width(" ");
 
   QStringList lineBreakList = source.split("\n");
   foreach(QString line, lineBreakList)
   {
       double leftWidth = 0;
       xPos = 0, yPos = lineCount*lineHeight;
 
       QStringList spacesList = line.split(" ", QString::SkipEmptyParts);
       foreach(QString word, spacesList)
       {
           double wordWidth = fm.width(word);
 
           if( leftWidth + wordWidth >= boundingRect.width() )
           {
               ++lineCount;
               xPos = 0;
               yPos = lineCount*lineHeight;
               leftWidth = 0;
           }
 
           QRectF wordRect = QRectF(xPos, yPos, wordWidth, lineHeight);
           result.push_back(wordRect);
 
           leftWidth += wordWidth + spaceWidth;
           xPos += wordWidth + spaceWidth;
       }
 
       ++lineCount;
   }
 
   double heightDispl = (boundingRect.height() - lineCount*lineHeight)/2;
 
   for( int i = 0; i < result.size(); ++i )
       result[i].moveTop(result[i].y() + heightDispl);
 
   return result;
}
 

На вход получает Rect виджета, на котором рисуется текст (для верного расставления переносов), метрика выбранного шрифта и строку (допускаются символы перевода строки, по умолчанию считается, что wordWrap включен).
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.076 секунд. Запросов: 23.