QGraphicsView und QGraphicsScene
Im Qt-Designer wählt man ein QGraphicsView aus und positioniert das Element. Für eine QGraphicsView realisiert QGraphicsScene das Modell. Eine Scene kann auch für verschiedene Views als Modell dienen.QGraphicsScene wiederum dient als Container für Grafikobjekte, die von QGraphicsItem abgeleitet werden. Dazu dient die Funktion QGraphicsItem::addItem(). Allerdings gibt es noch ein paar spezialisierte Funktionen, die mit add beginnen und dann die Art des Grafikobjekts nennen, wie beispielsweise addLine, um eine Linie zu ziehen.
Alternativ kann mit addWidget der QGraphicsScene ein Element der Klasse QWidget übergeben werden. Dann wird vergleichbar mit klassischen Oberflächen die Funktion paintEvent überschrieben und über einen Painter die Zeichenprimitive aufgerufen.
Der Unterschied zwischen diesen Ansätzen ist, dass im ersten Ansatz die gezeichneten Items als Objekte nach dem Zeichnen zur Verfügung stehen und eigene Objekte sind. Der zweite Ansatz eignet sich eher bei einfachen Grafiken.
Einbau eines 2-D-Widgets im Qt-Designer
Im Qt-Creator kann ein Element vom Typ QGraphicsView eingefügt werden. Das Objekt erhält beispielsweise den Namen graphview. Nun kann im Konstruktor des Hauptfensters eine eigene Scene mit der folgenden Zeile eingebettet werden:QGraphicsScene *scene = new MeinGraphScene(this); ui->graphview->setScene(scene);MeinGraphScene wird von QGraphicsScene abgeleitet. Wenn mit diesen Parametern eine neue Klasse über den Qt-Creator angelegt wird, wird automatisch eine solche Headerdatei angelegt:
#ifndef MEINGRAPHSCENE_H #define MEINGRAPHSCENE_H #include <QGraphicsScene> class MeinGraphScene : public QGraphicsScene { Q_OBJECT public: explicit MeinGraphScene(QObject *parent = 0); protected: void paint(QPainter *painter, const QRectF &rect); signals: public slots: }; #endif // MEINGRAPHSCENE_H
Items in der Scene
Im Konstruktor von MeinGraphScene wiederum können nun die einzelnen Elemente eingebettet werden. Im folgenden Beispiel wird ein Rechteck angelegt.MeinGraphScene::MeinGraphScene(QObject *parent) : QGraphicsScene(0,0,1000,500) { QColor color(255, 0, 0); QBrush brush(color); QPen pen(color); QGraphicsRectItem *rect = addRect(10, 10, 100, 100, pen, brush); }Der Aufruf des Konstruktors hinter dem Doppelpunkt bewirkt, dass die Scene auf ein Koordinatensystem von 1000x500 definiert wird.
Über den Zeiger rect kann das Item später jederzeit zugegriffen werden.
Neben dem Rechteck gibt es verschiedene weitere Elemente .
Verwendung eines QWidgets
Statt die Scene mit Items zu füllen, kann ihr mit der Funktion addWidget auch ein von QWidget abgeleitetes Objekt übergeben werden.MeinGraphScene::MeinGraphScene(QObject *parent) : QGraphicsScene(0,0,1000,500) { addWidget(new BelegWidget()); }Nun wird eine neue Klasse erzeugt und man gibt dem Qt-Creator an, dass er eine Klasse erzeugt, die von QWidget abgeleitet wird. Er erstellt daraufhin Header und CPP-Datei mit einem Rahmen.
Das neue QWidget kann nun die Funktion paintEvent überschreiben, um die Grafik aufzubauen und beispielsweise mousePressEvent überschreiben, um die Mausaktionen zu überwachen.
#ifndef BELEGWIDGET_H #define BELEGWIDGET_H #includeDie Funktion paintEvent wird immer dann aufgerufen, wenn der Widget-Inhalt dargestellt wird. Das ist das erste Mal dann, wenn das Widget angelegt wird und später bei jeder aufgedeckten Überlappung durch andere Fenster.class BelegWidget : public QWidget { Q_OBJECT public: explicit BelegWidget(QWidget *parent = 0); signals: public slots: void paintEvent(QPaintEvent *event); protected: void mousePressEvent(QMouseEvent *event); }; #endif // BELEGWIDGET_H
void BelegWidget::paintEvent(QPaintEvent *event) { QPainter painter(this); QFontMetrics metrics = painter.fontMetrics(); int boxwidth = metrics.width('0')*2 + 2; int boxheight = metrics.height() + metrics.descent(); // Farbenvorbereitungen für Brush und Pen QColor brushcolor(0, 255, 255); QBrush brush(brushcolor); QColor pencolor(0,0,0); QPen pen(pencolor); painter.setPen(pen); for (int tag=0; tag<monatsTage; ++tag) { painter.fillRect(tag*boxwidth, 0, boxwidth, boxheight, brush); painter.drawRect(tag*boxwidth, 0, boxwidth, boxheight); QString str = QString::number(tag+1); painter.drawText(tag*boxwidth+1, boxheight-1, str); } ... }
Mausklick in der Scene
Damit eine Scene einen Mausklick auswerten kann, wird die die virtuelle Funktion mouseDoubleClickEvent, mouseMoveEvent, mousePressEvent oder mouseReleaseEvent überschrieben. Über den Parameter vom Typ QGraphicsSceneMouseEvent erhält die Funktion alle Informationen über das eingetretene Mausereignis.event->scenePos() liefert QPointF, dessen Funktionen x() und y() die Position der Maus angeben.
void MeinGraphScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { QPointF pos = event->scenePos(); Qt::MouseButton button = event->button(); switch (button) { case Qt::LeftButton: butStr = "left"; break; case Qt::RightButton: butStr = "right"; break; } std::cout << "mouse" << pos.x() <<", " << pos.y() << " button: " << butStr.toStdString() << std::endl; }
Mausklick auf ein QWidget
Ein QWidget empfängt die Mausereignisse über eigene mousePressEvents. Der Parameter ist hier ein Zeiger auf QMouseEvent.void BelegWidget::mousePressEvent(QMouseEvent *event) { QPointF pos = event->pos(); Qt::MouseButton button = event->button(); QString butStr; switch (button) { case Qt::LeftButton: butStr = "left"; break; case Qt::RightButton: butStr = "right"; break; } std::cout << "widget mouse" << pos.x()<<","<<pos.y() << " button: " << butStr.toStdString() << std::endl; }