| Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
| Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Текст на QGraphicsScene |
| Автор: wowka19 22.4.2014, 13:23 |
| Необходимо размещать на сцене текст со следующим функционалом: 1. Редактировать сам текст на самой сцене (как в фотошопе: кликаешь на надпись и редактируешь) 2. Менять цвет, size, B, I и сам шрифт (Arial,...) - тут проблем возникнуть не должно 3. Менять расстояние между символами, не меняя других параметров 4. Изгибать надписи по дуге 5. Вращать надпись - тут тоже без проблем Вопрос: что брать QGraphicsSimpleTextItem или QGraphicsTextItem и как реализовать 1, 3 и 4 пункты? |
| Автор: Amp 22.4.2014, 15:34 |
| Писать свой рендер |
| Автор: Amp 22.4.2014, 17:50 |
| Задача ведь нетривиальная. QGraphicsTextItem рендерит через QTextLayout, там такой акробатики нет. Изначально я бы создавал QGraphicsTextItem, так как там, насколько я вижу, есть in-place редактирование. А после, если применяется преобразвание, подменял бы на свой наследник от QGraphicsItem. Впрочем говорю навскидку - со сценграфом этим плотно не работал. |
| Автор: wowka19 22.4.2014, 19:54 |
| Подскажи как мне в QGraphicsItem::paint() поворачивать символ ? не создавать же мне на каждый символ дочерний QGraphicsItem, чтобы только повернуть его штатным QGraphicsItem::rotate() ? |
| Автор: Amp 22.4.2014, 21:40 |
| Устанавливать нужную матрицу транформации у QPainter (через rotate/translate или setTransform) перед отрисовкой каждого символа. Посмотри, например, здесь пример http://stackoverflow.com/questions/17753657/how-to-write-a-text-around-a-circle-using-qpainter-class |
| Автор: wowka19 22.4.2014, 22:19 | ||||
| С матрицами в QPainter уже разобрался. Но уточню: это
и это
одно и тоже? т.е. painter1.transform() == painter2.transform() ??? не считая погрешности double конечно же Приведенный тобой пример уже видел. Но не пойму как мне гибко регулировать расстояние между символами, чтобы они не наезжали друг на друга в независимости от шрифта/размера и т.д? Т.е. за что мне уцепиться, за какой параметр QFont'а? |
| Автор: Amp 23.4.2014, 12:18 |
| Да, одно и то же. Причем второй вариант теоретически более предпочтителен, так как не нужно будет на отрисовку каждой буквы дергать save/restore - painter меньше лишних действий будет совершать. Цепляться надо к QFontMetrics, получая размер каждого отдельного символа и, исходя из этого, считать их положения. К тому же это потом поможет высчитать верно bounding rect итоговой надписи. |
| Автор: wowka19 25.4.2014, 01:29 | ||
Вот код рендера текста по дуге на QPixmap:
в итоге с учетом ширины символа стало лучше, но некоторые буквы всеравно немного "скачут", как по вертикали так и по горизонтали. Что не так? И сразу второй вопрос: как мне грамотно (без оверхеда) вычислить размеры области редеринга (QPixmap pixmap_(?,?)), если я уже рендерю в него, не имея данных о конечных размерах вплоть до конца рендеринга? И еще текст получается несглаженным, хотя все флаги стоят. Это из-за того, что я его при рендеринге перемножаю на матрицу textMatrix по нескольку раз. Т.е, "растеризовав" первый символ (тем самым превратив его в маленькую картинку), я перемножаю ее (картинку) на матрицу textMatrix еще несколько раз (кол-во символов - 1). Более того, итоговую надпись (т.е. полученный QPixmap) еще нужно будет вращать на сцене, что также плохо отразиться на качестве надписи. Глядя на неизменно отличное качество QGraphicsSimpleTextItem и QGraphicsTextItem при любых манипуляциях складывается подозрение, что символы рендерятся спец. встроенным движком, который принимает конечную матрицу преобразований (вплоть до матрицы вида), перемножает на нее символ еще в векторном виде, и только потом растеризует, выдавая его в том виде, в котором его должен увидеть пользователь. Отсюда вопрос как заполучить или реализовать (лучше заполучить) этот механизм себе в класс MMSpecialTextItem? |
| Автор: Amp 25.4.2014, 11:13 |
| 1. QFontMetrics лучше получать из текущего QPainter-а. 2. Трансформацию рассчитываешь очень странно. Угол зависит от длины текста (количества букв), радиуса окружности и текущего символа (его номера). 3. У setWorldTransform второй аргумент должен быть false Грамотно и точно без оверхеда не выйдет - придется выполнить холостой прогон без отрисовки, вычисляя границы. С другой стороны, если радиус окружности заранее известен, то на основе его и размера шрифта можно, хоть и не совсем точно, посчитать размер битмапа, который будет необходим для отрисовки. Не знаю что ты именно вкладываешь в понятие "несглаженный" (нет пока возможности собрать код) - приложи скриншот. |
| Автор: wowka19 26.4.2014, 13:32 |
| 1. Сомневаюсь, что что-то изменится, так как QPainter::fontMetrics возвращает параметры текущего шрифта, который устанавливаю я явным образом. Более того, от QFont можно получить QFontMetricsF, что точнее. Немного скачущий текст оказался следствием того, что почемуто QFontMetricsF::width("т") (именно русской наклонной жирной маленькой "т" шрифта Times New Roman) в полтора раза больше остальных (не всех) букв. Понятное дело что "т" шире чем например "к" но не в 1.5 раз. Но это мелочи - я забил. 2. Да, угол всей надписи действительно зависит от количества букв, но этот факт при вычислении позиции конкретного символа никак не поможет. Я высчитываю угол (дельту) для каждого символа так как их ширина различна для символов. И делаю это, исходя из, естественно, ширины символа (чем шире символ, тем больше угол) и из радиуса (чем больше радиус, тем меньше нужен угол для поворота). Отсюда и формула (немного школьной геометрии и алгебры): arctg( ширина_символа / радиус ) - в радианах. 3. У setWorldTransform второй аргумент не должен быть false, ведь иначе я буду отменять предыдущие повороты (для уже отрисованных символов) и рисовать примерно в том же месте все символы. По сути у меня остался один вопрос: как рисовать символы уже с учетом матричных преобразований, т.е. чтобы текстовый движок, который оперирует векторными данными шрифта (в моем случае Times New Roman) сначала учитывал матрицу преобразований, а потом уже проводил растеризацию. У меня же получается, что матрица накладывается уже на отрендеренный символ. Посмотри какие четкие шрифты выводят QGraphicsSimpleTextItem и QGraphicsTextItem. Подумываю просто сделать обычный QGraphicsItem и напихать в него коллекцию дочерних QGraphicsSimpleTextItem... |
| Автор: math64 27.4.2014, 13:25 |
| Для наклонного шрифта сумма ширин отдельных букв больше, чем ширина всего текста - отсюда и разница. Кстати, можно делать более точную транформацию - из прямоугольника в трапецию (матрица вычисляется с помощью quadToQuad() ) [для наклонного шрифта нужно преобразовывать параллелограмм] |
| Автор: Amp 28.4.2014, 12:20 | ||
Можешь попробовать глифы предварительно конвертировать в path и потом уже рисовать (выставляя QPen(Qt.NoPen)). Результат должен быть лучше.
|
| Автор: wowka19 29.4.2014, 05:11 |
| спасибо. Есть еще вопрос по расстоянию между символами. Я устанавливаю его так: font.setLetterSpacing(QFont::AbsoluteSpacing, 40); Все бы хорошо, но мне не нужен этот промежуток перед знаками препинания. Есть ли простое решение? |
| Автор: wowka19 4.5.2014, 19:56 |
| ап (предыдущий пост) и еще одна проблема: Текст на сцене в виде QPixmap отлично смотрится только если не использовать QGraphicsView::scale(), т.е. масштабирование вида. При увеличении видны пиксели - но не это меня волнует. Проблема возникает при уменьшении - тонкие элементы текста съедаются алгоритмом масштабирования. Как решить проблему (например с QGraphicsSimpleTextItem такого не происходит)? |
| Автор: Amp 4.5.2014, 20:17 | ||||
Рисуй кусками - слова отдельно от знаков препинания.
Масштабировать текст - плохая идея. Лучше его каждый раз перерисовывать в соответствии с новым масштабом. |
| Автор: wowka19 4.5.2014, 23:14 |
а как? если я перерендерю тест в QPixmap, то ничего не изменится - QPixmap будет тем же. |