На этом шаге рассмотрим пример обработки событий.
Создадим программу, окно которой показано на рис. 1. В ней используются:
Рис.1. Графическое представление, отображающее элементы сцены
/*собственный класс представления MyView, который наследуется от класса QGraphicsView, предоставляет слоты для уменьшения, увеличения и поворота, которые соединим с сигналами соответствующих кнопок*/ class MyView: public QGraphicsView { Q_OBJECT public: MyView(QGraphicsScene* pScene, QWidget* pwgt = 0) : QGraphicsView(pScene, pwgt) { } public slots: void slotZoomIn() { scale(1.1, 1.1); } void slotZoomOut() { scale(1 / 1.1, 1 / 1.1); } void slotRotateLeft() { rotate(-5); } void slotRotateRight() { rotate(5); } }; //класс SimpleItem является реализацией собственного элемента class SimpleItem : public QGraphicsItem { private: enum {nPenWidth = 6}; public: /*метод boundingRect() необходим представлению для определения невидимых элементов и неперекрытых областей, которые должны быть нарисованы, этот метод возвращает прямоугольную область, в которую вписывается прямоугольник, с учетом толщины линии (penWidth)*/ virtual QRectF boundingRect() const { QPointF ptPosition(-10 - nPenWidth, -10 - nPenWidth); QSizeF size(20 + nPenWidth * 2, 20 + nPenWidth * 2); return QRectF(ptPosition, size); } /*метод paint() отвечает за отображение элемента - прямоугольник, который рисуется зеленым пером толщиной 5 пикселей. Т.к. мы изменяем настройки объекта QPainter с помощью метода setPen(), то его состояние предварительно сохраняется методом save(), а в конце рисования восстанавливается в первоначальное состояние методом restore()*/ virtual void paint(QPainter* ppainter, const QStyleOptionGraphicsItem*, QWidget* ) { ppainter->save(); ppainter->setPen(QPen(Qt::green, nPenWidth)); ppainter->drawRect(-10, -10, 20, 20); ppainter->restore(); } /*при нажатии на кнопку мыши вызывается метод mousePressEvent(), который изменяет указатель мыши на изображение, сигнализирующее о том, что элемент может быть перемещен, а затем передает указатель на объект события в метод mousePressEvent() унаследованного класса*/ virtual void mousePressEvent(QGraphicsSceneMouseEvent* pe) { QApplication::setOverrideCursor(Qt::PointingHandCursor); QGraphicsItem::mousePressEvent(pe); } /*метод mouseReleaseEvent() вызывается сразу после отпускания кнопки мыши. Он восстанавливает исходное изображение курсора мыши и передает объект события дальше на обработку методу mouseReleseEvent() унаследованного класса*/ virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent* pe) { QApplication::restoreOverrideCursor(); QGraphicsItem::mouseReleaseEvent(pe); } }; /*в функции main() создаются объекты сцены (scene), представления (указатель pView), элементы (указатели pSimpleItem и pPixmapItem) и кнопки, предназначенные для поворота (указатели pcmdRotateLeft и pcmdRotateRight), увеличения и уменьшения (указатели pcmdZoomIn и pcmdZoomOut)*/ int main(int argc, char** argv) { QApplication app(argc, argv); app.setApplicationDisplayName("Элементы сцены"); QWidget wgt; QGraphicsScene scene(QRectF(-100, -100, 640, 480)); MyView* pView = new MyView(&scene); QPushButton* pcmdZoomIn = new QPushButton("&Увеличение"); QPushButton* pcmdZoomOut = new QPushButton("У&меньшение"); QPushButton* pcmdRotateLeft = new QPushButton("&Поворот налево"); QPushButton* pcmdRotateRight = new QPushButton("П&оворот направо"); /*вызов метода setRenderHint() из объекта представления устанавливает в нем режим сглаживания, что необходимо для более мягкого отображения контуров элементов (на растровые изображения это не распространяется)*/ pView->setRenderHint(QPainter::Antialiasing, true); /*элемент определенного класса SimpleItem добавляется в сцену при помощи метода QGraphicsScene::addItem(), а метод setPos() устанавливает его положение на сцене. Даем возможность изменения местоположения элемента на сцене, для чего в метод setFlags() передается значение QGraphicsItem::ItemIsMovable*/ SimpleItem* pSimpleItem = new SimpleItem; scene.addItem(pSimpleItem); pSimpleItem->setPos(0, 0); pSimpleItem->setFlags(QGraphicsItem::ItemIsMovable); SimpleItem* pSimpleItem1 = new SimpleItem; scene.addItem(pSimpleItem1); pSimpleItem1->setParentItem(pSimpleItem); pSimpleItem1->setPos(147, 0); pSimpleItem1->setFlags(QGraphicsItem::ItemIsMovable); SimpleItem* pSimpleItem2 = new SimpleItem; scene.addItem(pSimpleItem2); pSimpleItem2->setParentItem(pSimpleItem); pSimpleItem2->setPos(147, 110); pSimpleItem2->setFlags(QGraphicsItem::ItemIsMovable); SimpleItem* pSimpleItem3 = new SimpleItem; scene.addItem(pSimpleItem3); pSimpleItem3->setParentItem(pSimpleItem); pSimpleItem3->setPos(0, 110); pSimpleItem3->setFlags(QGraphicsItem::ItemIsMovable); /*созданному элементу растрового изображения (указатель pPixmapItem) с помощью метода setParentItem() присваивается предок, которым является элемент, произведенный от созданного нами класса SimpleItem. Вызов метода setFlags() разрешает перемещение элемента при помощи мыши. Это мы сделали умышленно, для того, чтобы продемонстрировать взаимосвязь группировки элементов отношением "предок-потомок". Итак, обратите внимание, что когда мы перемещаем растровое изображение, то перемещается только оно, но если мы попытаемся переместить элемент прямоугольника, то растровое изображение будет перемещаться вместе с ним, т. к. оно является его потомком*/ QGraphicsPixmapItem* pPixmapItem = scene.addPixmap(QPixmap("image.png")); pPixmapItem->setParentItem(pSimpleItem); pPixmapItem->setFlags(QGraphicsItem::ItemIsMovable); //кнопки соединяются с соответствующими слотами созданного класса MyView QObject::connect(pcmdZoomIn, SIGNAL(clicked()), pView, SLOT(slotZoomIn()) ); QObject::connect(pcmdZoomOut, SIGNAL(clicked()), pView, SLOT(slotZoomOut()) ); QObject::connect(pcmdRotateLeft, SIGNAL(clicked()), pView, SLOT(slotRotateLeft()) ); QObject::connect(pcmdRotateRight, SIGNAL(clicked()), pView, SLOT(slotRotateRight()) ); /*элементы при помощи вертикальной компоновки QVBoxLayout размещаются на поверхности виджета wgt*/ QVBoxLayout* pvbxLayout = new QVBoxLayout; pvbxLayout->addWidget(pView); pvbxLayout->addWidget(pcmdZoomIn); pvbxLayout->addWidget(pcmdZoomOut); pvbxLayout->addWidget(pcmdRotateLeft); pvbxLayout->addWidget(pcmdRotateRight); wgt.setLayout(pvbxLayout); wgt.show(); return app.exec(); }
Файлы приложения можно взять здесь.
На следующем шаге рассмотрим размещение виджетов в графическом представлении.