Qt提供了圖形視圖架構(Graphics View Framework)、動畫架構(The Animation Framework)和
參考文獻:《Qt Creator 快速入門》第三版 霍亞飛編著
狀态機架構(The State Machine Framework)來實作更加進階的圖形和動畫應用。
一、圖形視圖架構的結構
圖形視圖架構提供了一個居于圖形項的模型視圖程式設計方法,主要由場景、視圖和圖形項三部分組成,這三部分分别由QGraphicsScene、QGraphicsView和QGraphicsItem這3個類來表示。多視圖可以看成一個場景,場景中包含各種各樣幾何形狀的圖形項。
1.1場景QGraphicsScene
QGraphicsScene提供了圖形視圖架構中的場景,場景有以下功能:
- 提供用于管理大量圖形的告訴接口;
- 傳播事件到某一個圖形項
- 管理圖形項的狀态,比如選擇和處理焦點
- 提供五變換的渲染功能,主要用于列印
場景是圖形項QGraphicsItem對象的容器,可以調用QgraphicsScenen::addItem()函數将圖形項添加到場景中,然後調用任意一個圖形項發現函數(QgraphicsScenen::items()、QgraphicsScenen::itemAt()、QgraphicsScenen::foucusItem()等)來檢索添加的圖形項,調用QgraphicsScenen::removeItem()函數删除圖形項。
1.2視圖QGraphicsView
QGraphicsView提供了視圖部件,它用來使場景中的内容可視化。預設的QGraphicsView提供了一個QWidget作為視口部件,如果要使用OpenGL進行渲染,則可以調用QGraphicsView::setViewPort()函數設定QOpenGLWidget作為視口。可以對視圖設定前景色和背景色(也可以對整個場景設定)。
場景和視圖的示例代碼如下
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QDebug>
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
//建立場景
QGraphicsScene scene;
//建立矩形圖形項
QGraphicsItem* item=new QGraphicsRectItem(0,0,100,100);
//将圖形添加到場景中
scene.addItem(item);
//輸出(50,50)點處的圖形項
qDebug()<<scene.itemAt(50,50,QTransform());
//為場景建立視圖
QGraphicsView view(&scene);
//設定場景的前景色
view.setForegroundBrush(QColor(255,255,0,100));
//設定場景的背景圖檔
view.setBackgroundBrush(QPixmap("../myscene/background.jpg"));
view.resize(400,300);
view.show();
return app.exec();
}
運作效果
![](https://img.laitimes.com/img/_0nNw4CM6IyYiwiM6ICdiwiIwczX0xiRGZkRGZ0Xy9GbvNGL2EzXlpXazxCMNpXT0kEVPhXU6hFMG1mYw50MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL1MTM4UzMyYTM0ETMxAjMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
1.3圖形項
QGraphicsItem是圖形項的基類,主要支援如下功能:
- 滑鼠按下、移動、釋放、輕按兩下、懸停、滾輪和右鍵菜單。
- 鍵盤輸入焦點和鍵盤事件。
- 拖放事件。
- 分組,使用QGraphicsItemGroup通過parent-child關系來實作。
- 碰撞檢測。
- 使用setData()和data接口進行資料存儲和擷取。
要實作自定義的圖形項,首先定義一個QGraphicsItem的子類,然後重新實作它的兩個純虛公共函數boundingRect()和paint(),前者用來傳回要繪制圖形項的矩形區域,後者用來執行實際的繪圖操作。
實列代碼如下,類頭檔案
#ifndef MYITEM_H
#define MYITEM_H
#include <QGraphicsItem>
class MyItem:public QGraphicsItem
{
public:
MyItem();
QRectF boundingRect() const;
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget = Q_NULLPTR);
};
#endif // MYITEM_H
類實作
#include "myitem.h"
#include <QPainter>
MyItem::MyItem()
{
}
QRectF MyItem::boundingRect() const
{
qreal penWidth=1;
return QRectF(0-penWidth/2,0-penWidth/2.0,200+penWidth,200+penWidth);
}
void MyItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
painter->setBrush(Qt::red);
painter->drawRect(0,0,200,200);
}
二、圖形視圖架構的坐标系統和事件處理
2.1圖形項坐标
圖形項使用自己的本地坐标系統,坐标通常是以它們的中心為原點(0,0),而這也是所有變換的中心。圖形項預設位置是父圖形項或者場景的原點處,可以使用setPos函數指定其位置。使用setZvalue設定顯示層級,Z越大顯示層級越高。
2.2場景坐标
場景坐标是所有圖形項的基礎坐标吸引。描述了每一個頂層圖形項的位置,也用于處理所有從視圖傳到場景上的事件。場景坐标的原點在場景的中心,x和y坐标分别向右和下增大。
2.3視圖坐标
視圖的坐标就是部件的坐标。視圖坐标的每一個機關對應一個像素,原點(0,0)在QGraphicsView視口的左上角。所有的滑鼠事件和拖放事件最初都是使用視圖坐标接收的。
2.4坐标映射
映射函數 | 描述 |
QGraphicsView::mapToScene() | 從視圖坐标系統映射到場景坐标系統 |
QGraphicsView::mapFromScene() | 從場景坐标系統映射到視圖坐标系統 |
QGraphicsItem::mapToScene() | 從圖形項的坐标系統映射到場景的坐标系統 |
QGraphicsItem::mapFromScene() | 從場景的坐标系統映射到圖形項的坐标系統 |
QGraphicsItem::mapToParent() | 從本圖形項的坐标系統映射到父圖形項的坐标系統 |
QGraphicsItem::mapFromParent() | 從父圖形項的坐标系統映射到本圖形項的坐标系統 |
QGraphicsItem::mapToItem() | 從本圖形項的坐标系統映射到另一個圖形項的坐标系統 |
QGraphicsItem::mapFromItem() | 從另一個圖形項的坐标系統映射到本圖形項的坐标系統 |
示例代碼
myView類定義及實作
#ifndef MYVIEW_H
#define MYVIEW_H
#include <QGraphicsView>
class MyView:public QGraphicsView
{
Q_OBJECT
public:
explicit MyView(QWidget* parent=0);
protected:
void mousePressEvent(QMouseEvent *event);
};
#endif // MYVIEW_H
#include "myview.h"
#include <QMouseEvent>
#include <QGraphicsItem>
#include <QDebug>
MyView::MyView(QWidget *parent):QGraphicsView(parent)
{
}
void MyView::mousePressEvent(QMouseEvent *event)
{
//分别擷取單擊處在視圖、場景和圖形中的坐标,并輸出
QPoint viewPos=event->pos();
qDebug()<<"viewPos:"<<viewPos;
QPointF scenePos=mapToScene(viewPos);
qDebug()<<"scenePos:"<<scenePos;
QGraphicsItem* item=scene()->itemAt(scenePos,QTransform());
if(item)
{
QPointF itemPos = item->mapFromScene(scenePos);
qDebug()<<"itemPos:"<<itemPos;
}
}
mian函數
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QGraphicsView>
#include <QDebug>
#include "myitem.h"
#include "myview.h"
int main(int argc,char* argv[])
{
QApplication app(argc,argv);
//建立場景
QGraphicsScene scene;
//建立自定義圖形項
QGraphicsItem* item=new MyItem;
//将圖形添加到場景中
scene.addItem(item);
item->setPos(10,10);
QGraphicsItem* rectItem=scene.addRect(QRect(0,0,100,100),QPen(Qt::blue),QBrush(Qt::green));
rectItem->setPos(20,20);
rectItem->setParentItem(item);
rectItem->setRotation(45);
MyView view;
view.setScene(&scene);
view.setForegroundBrush(QColor(255,255,0,100));
view.setBackgroundBrush(QPixmap("../myscene/background.jpg"));
view.resize(400,300);
view.show();
return app.exec();
}
運作,點選圖示輸出資訊
2.5事件處理與傳播
圖形視圖架構中的事件都是先由視圖接收,然後傳遞給場景,再由場景傳遞給相應的圖形項。對于鍵盤事件會傳遞給獲得焦點的圖形項。