Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Текст на QGraphicsScene 
:(
    Опции темы
wowka19
Дата 22.4.2014, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Необходимо размещать на сцене текст со следующим функционалом:

1. Редактировать сам текст на самой сцене (как в фотошопе: кликаешь на надпись и редактируешь)
2. Менять цвет, size, B, I и сам шрифт (Arial,...) - тут проблем возникнуть не должно
3. Менять расстояние между символами, не меняя других параметров
4. Изгибать надписи по дуге
5. Вращать надпись - тут тоже без проблем

Вопрос: что брать QGraphicsSimpleTextItem или QGraphicsTextItem и как реализовать 1, 3 и 4 пункты?
PM MAIL   Вверх
Amp
Дата 22.4.2014, 15:34 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



Писать свой рендер smile  Пункты 3, 4 и 5 - это по сути отрисовка текста посимвольно по заданному path с дополнительной опцией в виде шага. Различия только в шаге и самой кривой, которая в 3 и 4 пунктах является прямой.  Ты хочешь чтобы эти пункты были доступны после ввода текста или непосредственно в процессе редактирования его? 

Это сообщение отредактировал(а) Amp - 22.4.2014, 15:36
PM MAIL   Вверх
wowka19
Дата 22.4.2014, 17:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Цитата(Amp @  22.4.2014,  15:34 Найти цитируемый пост)
Ты хочешь чтобы эти пункты были доступны после ввода текста или непосредственно в процессе редактирования его? 

после ввода.
А без своего рендера никак? Неужели QGraphicsTextItem нельзя согнуть по дуге?

И если все-таки писать рендер, то что брать за основу - QGraphicsItem?

Это сообщение отредактировал(а) wowka19 - 22.4.2014, 17:13
PM MAIL   Вверх
Amp
Дата 22.4.2014, 17:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



Задача ведь нетривиальная. QGraphicsTextItem рендерит через QTextLayout, там такой акробатики нет. Изначально я бы создавал QGraphicsTextItem, так как там, насколько я вижу, есть in-place редактирование. А после, если применяется преобразвание, подменял бы на свой наследник от QGraphicsItem. Впрочем говорю навскидку - со сценграфом этим плотно не работал. 
PM MAIL   Вверх
wowka19
Дата 22.4.2014, 19:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Подскажи как мне в QGraphicsItem::paint() поворачивать символ ? не создавать же мне на каждый символ дочерний QGraphicsItem, чтобы только повернуть его штатным QGraphicsItem::rotate() ?
PM MAIL   Вверх
Amp
Дата 22.4.2014, 21:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



Устанавливать нужную матрицу транформации у QPainter (через rotate/translate или setTransform) перед отрисовкой каждого символа. Посмотри, например, здесь пример http://stackoverflow.com/questions/1775365...-qpainter-class
PM MAIL   Вверх
wowka19
Дата 22.4.2014, 22:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



С матрицами в QPainter уже разобрался. Но уточню:
это
Код

QPainter painter1;
painter1.rotate(15);

и это
Код

QTransform matrix;
matrix.rotate(15);

QPainter painter2;
painter2.setWorldTransform(matrix)

одно и тоже? т.е. painter1.transform() == painter2.transform() ??? не считая погрешности double конечно же

Приведенный тобой пример уже видел. Но не пойму как мне гибко регулировать расстояние между символами, чтобы они не наезжали друг на друга в независимости от шрифта/размера и т.д? Т.е. за что мне уцепиться, за какой параметр QFont'а?

Это сообщение отредактировал(а) wowka19 - 22.4.2014, 22:22
PM MAIL   Вверх
Amp
Дата 23.4.2014, 12:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



Да, одно и то же. Причем второй вариант теоретически более предпочтителен, так как не нужно будет на отрисовку каждой буквы дергать save/restore - painter меньше лишних действий будет совершать.

Цепляться надо к QFontMetrics, получая размер каждого отдельного символа и, исходя из этого, считать их положения. К тому же это потом поможет высчитать верно bounding rect итоговой надписи.
PM MAIL   Вверх
wowka19
Дата 25.4.2014, 01:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



Вот код рендера текста по дуге на QPixmap:

Код

void MMSpecialTextItem::render()
{
    QFontMetricsF fm(font_);

    QTransform textMatrix;

    QPainter painter(pixmap_);
    painter.setFont(font_);

    foreach (QChar var, text_)
    {
        textMatrix.reset();
        textMatrix.translate(0, radius_);
        textMatrix.rotate(atan(fm.width(var) / radius_) * 180 / M_PI); // рассчитываю угол исходя из ширины текущего символа и радиуса
        textMatrix.translate(0, -radius_);

        painter.drawText(0, 0, var);
        painter.setWorldTransform(textMatrix, true);
    }
}


в итоге с учетом ширины символа стало лучше, но некоторые буквы всеравно немного "скачут", как по вертикали так и по горизонтали. Что не так?

И сразу второй вопрос: как мне грамотно (без оверхеда) вычислить размеры области редеринга (QPixmap pixmap_(?,?)), если я уже рендерю в него, не имея данных о конечных размерах вплоть до конца рендеринга?

И еще текст получается несглаженным, хотя все флаги стоят. Это из-за того, что я его при рендеринге перемножаю на матрицу textMatrix по нескольку раз. Т.е, "растеризовав" первый символ (тем самым превратив его в маленькую картинку), я перемножаю ее (картинку) на матрицу textMatrix еще несколько раз (кол-во символов - 1). Более того, итоговую надпись (т.е. полученный QPixmap) еще нужно будет вращать на сцене, что также плохо отразиться на качестве надписи. Глядя на неизменно отличное качество QGraphicsSimpleTextItem и QGraphicsTextItem при любых манипуляциях складывается подозрение, что символы рендерятся спец. встроенным движком, который принимает конечную матрицу преобразований (вплоть до матрицы вида), перемножает на нее символ еще в векторном виде, и только потом растеризует, выдавая его в том виде, в котором его должен увидеть пользователь. Отсюда вопрос как заполучить или реализовать (лучше заполучить) этот механизм себе в класс MMSpecialTextItem?

Это сообщение отредактировал(а) wowka19 - 25.4.2014, 09:10
PM MAIL   Вверх
Amp
Дата 25.4.2014, 11:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



1. QFontMetrics лучше получать из текущего QPainter-а. 
2. Трансформацию рассчитываешь очень странно. Угол зависит от длины текста (количества букв), радиуса окружности и текущего символа (его номера). 
3. У setWorldTransform второй аргумент должен быть false

Грамотно и точно без оверхеда не выйдет - придется выполнить холостой прогон без отрисовки, вычисляя границы. С другой стороны, если радиус окружности заранее известен, то на основе его и размера шрифта можно, хоть и не совсем точно, посчитать размер битмапа, который будет необходим для отрисовки. Не знаю что ты именно вкладываешь в понятие "несглаженный" (нет пока возможности собрать код) - приложи скриншот.
PM MAIL   Вверх
wowka19
Дата 26.4.2014, 13:32 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



1. Сомневаюсь, что что-то изменится, так как QPainter::fontMetrics возвращает параметры текущего шрифта, который устанавливаю я явным образом. Более того, от QFont можно получить QFontMetricsF, что точнее. Немного скачущий текст оказался следствием того, что почемуто QFontMetricsF::width("т")  (именно русской наклонной жирной маленькой "т" шрифта Times New Roman) в полтора раза больше остальных (не всех) букв. Понятное дело что "т" шире чем например "к" но не в 1.5 раз. Но это мелочи - я забил.

2. Да, угол всей надписи действительно зависит от количества букв, но этот факт при вычислении позиции конкретного символа никак не поможет. Я высчитываю угол (дельту) для каждого символа так как их ширина различна для символов. И делаю это, исходя из, естественно, ширины символа (чем шире символ, тем больше угол) и из радиуса (чем больше радиус, тем меньше нужен угол для поворота). Отсюда и формула (немного школьной геометрии и алгебры): arctg( ширина_символа / радиус ) - в радианах.

3.  У setWorldTransform второй аргумент не должен быть false, ведь иначе я буду отменять предыдущие повороты (для уже отрисованных символов) и рисовать примерно в том же месте все символы.


По сути у меня остался один вопрос: как рисовать символы уже с учетом матричных преобразований, т.е. чтобы текстовый движок, который оперирует векторными данными шрифта (в моем случае Times New Roman) сначала учитывал матрицу преобразований, а потом уже проводил растеризацию. У меня же получается, что матрица накладывается уже на отрендеренный символ. Посмотри какие четкие шрифты выводят QGraphicsSimpleTextItem и QGraphicsTextItem. Подумываю просто сделать обычный QGraphicsItem и напихать в него коллекцию дочерних QGraphicsSimpleTextItem...
PM MAIL   Вверх
math64
Дата 27.4.2014, 13:25 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 23
Всего: 72



Для наклонного шрифта сумма ширин отдельных букв больше, чем ширина всего текста - отсюда и разница.

Кстати, можно делать более точную транформацию - из прямоугольника в трапецию (матрица вычисляется с помощью quadToQuad() )
[для наклонного шрифта нужно преобразовывать параллелограмм]
PM   Вверх
Amp
Дата 28.4.2014, 12:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 886
Регистрация: 17.2.2009

Репутация: 7
Всего: 17



Можешь попробовать глифы предварительно конвертировать в path и потом уже рисовать (выставляя QPen(Qt.NoPen)). Результат должен быть лучше.
Код

painter.setPen(QPen(Qt.NoPen))

for n in xrange(0, len(str)):
    angle = start_angle + n * step

    transform = QTransform()
    transform.translate(center.x() + radius * cos(radians(angle)), center.y() + radius * sin(radians(angle)))
    transform.rotate(90.0 + angle)
    
    painter.setWorldTransform(transform)

    glyph_path = QPainterPath()
    glyph_path.addText(0, 0, font, str[n])

    painter.drawPath(glyph_path)


Присоединённый файл ( Кол-во скачиваний: 8 )
Присоединённый файл  2014_04_28_13_19_09_python.png 21,75 Kb
PM MAIL   Вверх
wowka19
Дата 29.4.2014, 05:11 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



спасибо.
Есть еще вопрос по расстоянию между символами. Я устанавливаю его так: font.setLetterSpacing(QFont::AbsoluteSpacing, 40);
Все бы хорошо, но мне не нужен этот промежуток перед знаками препинания. Есть ли простое решение?


Это сообщение отредактировал(а) wowka19 - 30.4.2014, 13:46
PM MAIL   Вверх
wowka19
Дата 4.5.2014, 19:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 285
Регистрация: 30.11.2011

Репутация: нет
Всего: нет



ап (предыдущий пост) и еще одна проблема:

Текст на сцене в виде QPixmap отлично смотрится только если не использовать QGraphicsView::scale(), т.е. масштабирование вида. При увеличении видны пиксели - но не это меня волнует. Проблема возникает при уменьшении - тонкие элементы текста съедаются алгоритмом масштабирования. Как решить проблему (например с QGraphicsSimpleTextItem такого не происходит)?
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С/С++: Кроссплатформенное программирование, QT/Gtk+/wxWidgets"
JackYF
Любитель
  • В заголовке темы в квадратных скобках обозначьте используемую вами библиотеку, например: [QT],[GTK],[wx].
  • Если вопрос актуален только для некоторой версии библиотеки, либо, если вы пользуетесь не самой последней версией, укажите это. Например: [QT4], [GTK2].
  • Все начинающие изучать Qt - не забудьте зайти сюда.
  • Проставьте несколько ключевых слов темы, чтобы её можно было легче найти.
  • В вопросе укажите полную версию версию библиотеки, а также все дополнительные используемые программные пакеты.
  • Не забывайте пользоваться кнопкой "Код".
  • Телепатов на форуме нет! Задавайте чёткий, конкретный и полный вопрос. Указывайте полностью ошибки компилятора и компоновщика.
  • Новое сообщение должно иметь прямое отношение к тематике этого раздела. Флуд, флейм, оффтопик запрещены.
  • Категорически запрещается обсуждение вареза, "кряков", взлома программ и т.д.

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, Любитель.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets | Следующая тема »


 




[ Время генерации скрипта: 0.0531 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.