В данный момент работаю с SVG-графикой в Qt и чтобы не забыть того, что узнал из работы с Graphics View Framework хочу написать данный цикл статей, пока эти знания у меня из головы не вылетели. Возможно кому-то кроме меня он окажется полезен, и я буду только рад этому. Сразу хочу сказать что, где-то могут быть ошибки и неточности. Я не профи в этом и только учусь.
Не хочу расписывать подробно "что это такое", это уже давно сделали до меня. Приведу лишь одну схему, поясняющую модель взаимодействия объектов:
И по отдельности хочу рассказать про каждый класс, и те нюансы с которыми мне пришлось столкнуться.
QGraphicsScene - класс сцены, хранит в себе элементы, и это самое главное и понятное. Может быть привязан к нескольким сценам.
QGraphicsItem - класс элемента, все элементы сцены должны быть потомками от этого класса. Сам класса QGraphicsItem является абстрактным, от него нужно создать собственный класс и переопределить в нем хотя бы методы paint() и boundingRect(). Но обычно этого не требуется ведь есть много уже готовых классов, например, прямоугольники (QGraphicsRectItem), эллипсы (QGraphicsEllipseItem) и текстовые элементы (QGraphicsTextItem). Проще отнаследоваться от них переопределив нужные методы. Да, кстати, данный класс не наследуется от QObject, а это значит, что нем не реализован сигнально-слотовый механизм. Но есть прекрасный класс QGraphicsObject, в котором это есть, но использовав его вы жертвуете производительностью.
Поподробней про элементы сцены. У них есть собственные локальные координаты и координаты сцены (как минимум, есть правда еще, но пока что забудем о них).
Под локальными понимается координаты внутри данного объекта. Т.е. его начало координат будет в левом верхнем углу. Для преобразования из одной системы в другую - используются методы элемента mapTo...() и mapFrom...()
Например, нужно узнать середину квадрата в координатах сцены внутри класса предка QGraphicsRectItem. Объект этого класса назовем myRect.
Внутри каждого класса наследуемого от QGraphicsItem имеются методы transform() и setTransform(). Метод transform() возвращает объект класса QTransform, который позволяет выполнять различные преобразования над элементом (масштабирование, перемещение, поворот). Факт в том, что преобразованию подвергается локальная система координат. Т.е. все его характеристики внутри нее, будь то длина, ширина или конечные точки - остаются без изменений. Еще одна особенность в том, поворот (метод QTransform::rotate()) осуществляется вокруг локальной точки точки 0;0, причем вне зависимости от установки transformOriginPoint() у элемента. Если хочется вращать вокруг определенной точки нужно задать эту точку методом QGraphicsItem::setTransformOriginPoint() и затем вызвать QGraphicsItem::setRotation(). Пример:
Для каждого элемента можно задать элемент, который будет его "родителем", и тогда все действия трансформации (поворот, масштабирование и пр.), которые будут производиться над основным элементом произойдут и над "дочерним" элементом, но только в системе координат "родителя". Весьма запутанная система получается. Задать "родителя" можно методом setParentItem().
Теперь немного про флаги у элементов.
Устанавливаются они через метод setFlag() или setFlags(). Первый - устанвливает только один флаг, второй метод - одновременно несколько, разделенные "|". Например:
Теперь о работе с SVG в Qt.
Для простой работы достаточно класса QSvgWidget
У каждого объекта в SVG свой ID по которому можно к нему обратиться. Рендерер же создается один раз для SVG-картинки. А с помощью метода setPos() изменяется положение элемента на сцене в соответствии с картинкой, иначе элемент будет располагаться в точке 0;0 на сцене.
Пока что это всё, будет что-то новое - добавлю.
Используемый материал:
Qt 5. Graphics View Framework
Qt 4. Graphics View Framework
Каркас Графического представления
Красота и мощь Qt Graphics View Framework на примере
Программирование графического интерфейса с помощью Qt 4, Часть 4
При копировании статьи просьба указывать источник и автора.
С уважением, GRomR1.
Не хочу расписывать подробно "что это такое", это уже давно сделали до меня. Приведу лишь одну схему, поясняющую модель взаимодействия объектов:
И по отдельности хочу рассказать про каждый класс, и те нюансы с которыми мне пришлось столкнуться.
Краткое описание каждого из них.
QGraphicsView - класс представления, он отвечает за отрисовку всех элементов, и именно его нужно добавлять внутрь ваших виджетов. В QtDesigner имеется. Наследуется от QAbstractScrollArea, а это означает, что, если отображение не помещается внутрь заданной области, то будут добавлены полосы прокрутки.QGraphicsScene - класс сцены, хранит в себе элементы, и это самое главное и понятное. Может быть привязан к нескольким сценам.
QGraphicsItem - класс элемента, все элементы сцены должны быть потомками от этого класса. Сам класса QGraphicsItem является абстрактным, от него нужно создать собственный класс и переопределить в нем хотя бы методы paint() и boundingRect(). Но обычно этого не требуется ведь есть много уже готовых классов, например, прямоугольники (QGraphicsRectItem), эллипсы (QGraphicsEllipseItem) и текстовые элементы (QGraphicsTextItem). Проще отнаследоваться от них переопределив нужные методы. Да, кстати, данный класс не наследуется от QObject, а это значит, что нем не реализован сигнально-слотовый механизм. Но есть прекрасный класс QGraphicsObject, в котором это есть, но использовав его вы жертвуете производительностью.
Теперь об основах работы с ними.
Допустим, что объект QGraphicsView уже добавлен в виджет, и мы хотим его связать со сценой:QGraphicsScene *scene = new QGraphicsScene;или можно так
graphicsView->setScene(scene);
QGraphicsScene scene(QRectF(-100, -100, 300, 300));Чтобы добавить элемент на сцену, например линию:
graphicsView->setScene(&scene);
QGraphicsLineItem *pLineItem =Дальше обращаясь к объекту pLineItem мы можем его менять, прямо на сцене.
scene.addLine(
QLineF(-10, -10, -80, -80),
QPen(Qt::red, 2)
);
Поподробней про элементы сцены. У них есть собственные локальные координаты и координаты сцены (как минимум, есть правда еще, но пока что забудем о них).
Под локальными понимается координаты внутри данного объекта. Т.е. его начало координат будет в левом верхнем углу. Для преобразования из одной системы в другую - используются методы элемента mapTo...() и mapFrom...()
Например, нужно узнать середину квадрата в координатах сцены внутри класса предка QGraphicsRectItem. Объект этого класса назовем myRect.
void showMiddlePoint()Удобно вызывать внутри этого метода сигнал, который связать со слотом отрисовки этой точки. Дополним.
{
qDebug() <<
mapToScene(QPointF(boundingRect().width()/2, boundingRect().height()/2));
}
void showMiddlePoint()
{
qDebug() << mapToScene(QPointF(width()/2, height()/2));
emit needDrawPoint(
mapToScene(QPointF(width()/2, height()/2) );
}
connect( myRect, SIGNAL(needDrawPoint(QPointF())),
this, SLOT(drawPoint(QPointF())));
void drawPoint(QPointF p)Так же удобно отображать клик мыши на сцене создав предка от QGraphicsScene и переопределив метод mousePressEvent().
{
scene->addEllipse(
QRectF(p.x(),p.y(),1,1),
QPen(Qt::NoPen),
QBrush(Qt::black)
);
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)
{
emit clicked(event->scenePos()); event->accept();
}
connect(scene, SIGNAL(clicked(QPointF())),Теперь про трансформацию элементов.
this, SLOT(drawPoint(QPointF())));
Внутри каждого класса наследуемого от QGraphicsItem имеются методы transform() и setTransform(). Метод transform() возвращает объект класса QTransform, который позволяет выполнять различные преобразования над элементом (масштабирование, перемещение, поворот). Факт в том, что преобразованию подвергается локальная система координат. Т.е. все его характеристики внутри нее, будь то длина, ширина или конечные точки - остаются без изменений. Еще одна особенность в том, поворот (метод QTransform::rotate()) осуществляется вокруг локальной точки точки 0;0, причем вне зависимости от установки transformOriginPoint() у элемента. Если хочется вращать вокруг определенной точки нужно задать эту точку методом QGraphicsItem::setTransformOriginPoint() и затем вызвать QGraphicsItem::setRotation(). Пример:
void rotateAroundMiddle(qreal angle)Немного про "родитей" у элементов.
{
QPointF p(boundingRect().width()/2,
boundingRect().height()/2);
setTransformOriginPoint(p);
setRotation(angle);
}
Для каждого элемента можно задать элемент, который будет его "родителем", и тогда все действия трансформации (поворот, масштабирование и пр.), которые будут производиться над основным элементом произойдут и над "дочерним" элементом, но только в системе координат "родителя". Весьма запутанная система получается. Задать "родителя" можно методом setParentItem().
Теперь немного про флаги у элементов.
Устанавливаются они через метод setFlag() или setFlags(). Первый - устанвливает только один флаг, второй метод - одновременно несколько, разделенные "|". Например:
item1->setFlag(QGraphicsItem::ItemStacksBehindParent);Подробнее о представленных флагах. Флаг ItemStacksBehindParent - делает так чтобы родитель был позади (на заднем плане) потомка, флаг ItemIsMovable - позволяет перемещать элементы мышью, флаг ItemSendsGeometryChanges - позволяет отхватывать события методом QGraphicsItem::itemChange().
item2->setFlags(QGraphicsItem::ItemStacksBehindParent
| QGraphicsItem::ItemIsMovable);
item3->setFlags(QGraphicsItem::ItemStacksBehindParent
| QGraphicsItem::ItemSendsGeometryChanges
| QGraphicsItem::ItemIsMovable);
Теперь о работе с SVG в Qt.
Для простой работы достаточно класса QSvgWidget
QSvgWidget svg(":/motion.svg");Но мне этого было мало и я создал свой класс-потомок QGraphicsSvgItem. Объекты этого класса можно добавлять на сцену, и работать с ними как QGraphicsItem. Прежде всего их нужно правильно создать и связать с нужным объектом SVG. Я делаю это так:
svg.show();
QSvgRenderer *renderer = new
QSvgRenderer(QString(":/motion.svg"));
QGraphicsSvgItem *item = new QGraphicsSvgItem();
item->setSharedRenderer(renderer);
item->setElementId("rect1");
item->setPos(renderer->boundsOnElement("rect1").topLeft());
scene->addItem(item);
У каждого объекта в SVG свой ID по которому можно к нему обратиться. Рендерер же создается один раз для SVG-картинки. А с помощью метода setPos() изменяется положение элемента на сцене в соответствии с картинкой, иначе элемент будет располагаться в точке 0;0 на сцене.
Пока что это всё, будет что-то новое - добавлю.
Используемый материал:
Qt 5. Graphics View Framework
Qt 4. Graphics View Framework
Каркас Графического представления
Красота и мощь Qt Graphics View Framework на примере
Программирование графического интерфейса с помощью Qt 4, Часть 4
При копировании статьи просьба указывать источник и автора.
С уважением, GRomR1.
В данный момент работаю с SVG-графикой в Qt и чтобы не забыть того, что узнал из работы с Graphics View Framework хочу написать данный цикл статей, пока эти знания у меня из головы не вылетели. Возможно кому-то кроме меня он окажется полезен, и я буду только рад этому. Сразу хочу сказать что, где-то могут быть ошибки и неточности. Я не профи в этом и только учусь.
Не хочу расписывать подробно "что это такое", это уже давно сделали до меня. Приведу лишь одну схему, поясняющую модель взаимодействия объектов:
И по отдельности хочу рассказать про каждый класс, и те нюансы с которыми мне пришлось столкнуться.
QGraphicsScene - класс сцены, хранит в себе элементы, и это самое главное и понятное. Может быть привязан к нескольким сценам.
QGraphicsItem - класс элемента, все элементы сцены должны быть потомками от этого класса. Сам класса QGraphicsItem является абстрактным, от него нужно создать собственный класс и переопределить в нем хотя бы методы paint() и boundingRect(). Но обычно этого не требуется ведь есть много уже готовых классов, например, прямоугольники (QGraphicsRectItem), эллипсы (QGraphicsEllipseItem) и текстовые элементы (QGraphicsTextItem). Проще отнаследоваться от них переопределив нужные методы. Да, кстати, данный класс не наследуется от QObject, а это значит, что нем не реализован сигнально-слотовый механизм. Но есть прекрасный класс QGraphicsObject, в котором это есть, но использовав его вы жертвуете производительностью.
Поподробней про элементы сцены. У них есть собственные локальные координаты и координаты сцены (как минимум, есть правда еще, но пока что забудем о них).
Под локальными понимается координаты внутри данного объекта. Т.е. его начало координат будет в левом верхнем углу. Для преобразования из одной системы в другую - используются методы элемента mapTo...() и mapFrom...()
Например, нужно узнать середину квадрата в координатах сцены внутри класса предка QGraphicsRectItem. Объект этого класса назовем myRect.
Внутри каждого класса наследуемого от QGraphicsItem имеются методы transform() и setTransform(). Метод transform() возвращает объект класса QTransform, который позволяет выполнять различные преобразования над элементом (масштабирование, перемещение, поворот). Факт в том, что преобразованию подвергается локальная система координат. Т.е. все его характеристики внутри нее, будь то длина, ширина или конечные точки - остаются без изменений. Еще одна особенность в том, поворот (метод QTransform::rotate()) осуществляется вокруг локальной точки точки 0;0, причем вне зависимости от установки transformOriginPoint() у элемента. Если хочется вращать вокруг определенной точки нужно задать эту точку методом QGraphicsItem::setTransformOriginPoint() и затем вызвать QGraphicsItem::setRotation(). Пример:
Для каждого элемента можно задать элемент, который будет его "родителем", и тогда все действия трансформации (поворот, масштабирование и пр.), которые будут производиться над основным элементом произойдут и над "дочерним" элементом, но только в системе координат "родителя". Весьма запутанная система получается. Задать "родителя" можно методом setParentItem().
Теперь немного про флаги у элементов.
Устанавливаются они через метод setFlag() или setFlags(). Первый - устанвливает только один флаг, второй метод - одновременно несколько, разделенные "|". Например:
Теперь о работе с SVG в Qt.
Для простой работы достаточно класса QSvgWidget
У каждого объекта в SVG свой ID по которому можно к нему обратиться. Рендерер же создается один раз для SVG-картинки. А с помощью метода setPos() изменяется положение элемента на сцене в соответствии с картинкой, иначе элемент будет располагаться в точке 0;0 на сцене.
Пока что это всё, будет что-то новое - добавлю.
Используемый материал:
Qt 5. Graphics View Framework
Qt 4. Graphics View Framework
Каркас Графического представления
Красота и мощь Qt Graphics View Framework на примере
Программирование графического интерфейса с помощью Qt 4, Часть 4
При копировании статьи просьба указывать источник и автора.
С уважением, GRomR1.
Не хочу расписывать подробно "что это такое", это уже давно сделали до меня. Приведу лишь одну схему, поясняющую модель взаимодействия объектов:
И по отдельности хочу рассказать про каждый класс, и те нюансы с которыми мне пришлось столкнуться.
Краткое описание каждого из них.
QGraphicsView - класс представления, он отвечает за отрисовку всех элементов, и именно его нужно добавлять внутрь ваших виджетов. В QtDesigner имеется. Наследуется от QAbstractScrollArea, а это означает, что, если отображение не помещается внутрь заданной области, то будут добавлены полосы прокрутки.QGraphicsScene - класс сцены, хранит в себе элементы, и это самое главное и понятное. Может быть привязан к нескольким сценам.
QGraphicsItem - класс элемента, все элементы сцены должны быть потомками от этого класса. Сам класса QGraphicsItem является абстрактным, от него нужно создать собственный класс и переопределить в нем хотя бы методы paint() и boundingRect(). Но обычно этого не требуется ведь есть много уже готовых классов, например, прямоугольники (QGraphicsRectItem), эллипсы (QGraphicsEllipseItem) и текстовые элементы (QGraphicsTextItem). Проще отнаследоваться от них переопределив нужные методы. Да, кстати, данный класс не наследуется от QObject, а это значит, что нем не реализован сигнально-слотовый механизм. Но есть прекрасный класс QGraphicsObject, в котором это есть, но использовав его вы жертвуете производительностью.
Теперь об основах работы с ними.
Допустим, что объект QGraphicsView уже добавлен в виджет, и мы хотим его связать со сценой:QGraphicsScene *scene = new QGraphicsScene;или можно так
graphicsView->setScene(scene);
QGraphicsScene scene(QRectF(-100, -100, 300, 300));Чтобы добавить элемент на сцену, например линию:
graphicsView->setScene(&scene);
QGraphicsLineItem *pLineItem =Дальше обращаясь к объекту pLineItem мы можем его менять, прямо на сцене.
scene.addLine(
QLineF(-10, -10, -80, -80),
QPen(Qt::red, 2)
);
Поподробней про элементы сцены. У них есть собственные локальные координаты и координаты сцены (как минимум, есть правда еще, но пока что забудем о них).
Под локальными понимается координаты внутри данного объекта. Т.е. его начало координат будет в левом верхнем углу. Для преобразования из одной системы в другую - используются методы элемента mapTo...() и mapFrom...()
Например, нужно узнать середину квадрата в координатах сцены внутри класса предка QGraphicsRectItem. Объект этого класса назовем myRect.
void showMiddlePoint()Удобно вызывать внутри этого метода сигнал, который связать со слотом отрисовки этой точки. Дополним.
{
qDebug() <<
mapToScene(QPointF(boundingRect().width()/2, boundingRect().height()/2));
}
void showMiddlePoint()
{
qDebug() << mapToScene(QPointF(width()/2, height()/2));
emit needDrawPoint(
mapToScene(QPointF(width()/2, height()/2) );
}
connect( myRect, SIGNAL(needDrawPoint(QPointF())),
this, SLOT(drawPoint(QPointF())));
void drawPoint(QPointF p)Так же удобно отображать клик мыши на сцене создав предка от QGraphicsScene и переопределив метод mousePressEvent().
{
scene->addEllipse(
QRectF(p.x(),p.y(),1,1),
QPen(Qt::NoPen),
QBrush(Qt::black)
);
}
virtual void mousePressEvent(QGraphicsSceneMouseEvent *event)
{
emit clicked(event->scenePos()); event->accept();
}
connect(scene, SIGNAL(clicked(QPointF())),Теперь про трансформацию элементов.
this, SLOT(drawPoint(QPointF())));
Внутри каждого класса наследуемого от QGraphicsItem имеются методы transform() и setTransform(). Метод transform() возвращает объект класса QTransform, который позволяет выполнять различные преобразования над элементом (масштабирование, перемещение, поворот). Факт в том, что преобразованию подвергается локальная система координат. Т.е. все его характеристики внутри нее, будь то длина, ширина или конечные точки - остаются без изменений. Еще одна особенность в том, поворот (метод QTransform::rotate()) осуществляется вокруг локальной точки точки 0;0, причем вне зависимости от установки transformOriginPoint() у элемента. Если хочется вращать вокруг определенной точки нужно задать эту точку методом QGraphicsItem::setTransformOriginPoint() и затем вызвать QGraphicsItem::setRotation(). Пример:
void rotateAroundMiddle(qreal angle)Немного про "родитей" у элементов.
{
QPointF p(boundingRect().width()/2,
boundingRect().height()/2);
setTransformOriginPoint(p);
setRotation(angle);
}
Для каждого элемента можно задать элемент, который будет его "родителем", и тогда все действия трансформации (поворот, масштабирование и пр.), которые будут производиться над основным элементом произойдут и над "дочерним" элементом, но только в системе координат "родителя". Весьма запутанная система получается. Задать "родителя" можно методом setParentItem().
Теперь немного про флаги у элементов.
Устанавливаются они через метод setFlag() или setFlags(). Первый - устанвливает только один флаг, второй метод - одновременно несколько, разделенные "|". Например:
item1->setFlag(QGraphicsItem::ItemStacksBehindParent);Подробнее о представленных флагах. Флаг ItemStacksBehindParent - делает так чтобы родитель был позади (на заднем плане) потомка, флаг ItemIsMovable - позволяет перемещать элементы мышью, флаг ItemSendsGeometryChanges - позволяет отхватывать события методом QGraphicsItem::itemChange().
item2->setFlags(QGraphicsItem::ItemStacksBehindParent
| QGraphicsItem::ItemIsMovable);
item3->setFlags(QGraphicsItem::ItemStacksBehindParent
| QGraphicsItem::ItemSendsGeometryChanges
| QGraphicsItem::ItemIsMovable);
Теперь о работе с SVG в Qt.
Для простой работы достаточно класса QSvgWidget
QSvgWidget svg(":/motion.svg");Но мне этого было мало и я создал свой класс-потомок QGraphicsSvgItem. Объекты этого класса можно добавлять на сцену, и работать с ними как QGraphicsItem. Прежде всего их нужно правильно создать и связать с нужным объектом SVG. Я делаю это так:
svg.show();
QSvgRenderer *renderer = new
QSvgRenderer(QString(":/motion.svg"));
QGraphicsSvgItem *item = new QGraphicsSvgItem();
item->setSharedRenderer(renderer);
item->setElementId("rect1");
item->setPos(renderer->boundsOnElement("rect1").topLeft());
scene->addItem(item);
У каждого объекта в SVG свой ID по которому можно к нему обратиться. Рендерер же создается один раз для SVG-картинки. А с помощью метода setPos() изменяется положение элемента на сцене в соответствии с картинкой, иначе элемент будет располагаться в точке 0;0 на сцене.
Пока что это всё, будет что-то новое - добавлю.
Используемый материал:
Qt 5. Graphics View Framework
Qt 4. Graphics View Framework
Каркас Графического представления
Красота и мощь Qt Graphics View Framework на примере
Программирование графического интерфейса с помощью Qt 4, Часть 4
При копировании статьи просьба указывать источник и автора.
С уважением, GRomR1.
0 коммент.:
Отправить комментарий