Qt之QGraphicsView進階篇

作者:billy
版權聲明:著作權歸作者所有,商業轉載請聯繫作者獲得授權,非商業轉載請註明出處

前言

上一章節介紹了 QGraphicsView 中的基礎內容,具體請參考 Qt之QGraphicsView入門篇。這一章節我們來具體瞭解一下 GraphicsView 框架中有哪些特性。

縮放與旋轉

QGraphicsView 通過 QGraphicsView::setMatrix() 支持和 QPainter 一樣的仿射變換,通過對一個視圖應用變換,你可以很容易地支持普通的導航特性如縮放與旋轉。

示例:

#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsRectItem>
#include <QDialog>
#include <QVBoxLayout>
#include <QPushButton>

class MyGraphicsView : public QGraphicsView	// 自定義視圖類,實現對視圖的縮放和旋轉
{
public:
    MyGraphicsView() {}

public slots:
    void zoomIn() { scale(1.2, 1.2); }
    void zoomOut() { scale(1/1.2, 1/1.2); }
    void rotateLeft() { rotate(-30); }
    void rotateRight() { rotate(30); }
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QGraphicsScene scene;   // 定義一個場景,設置背景色爲紅色
    scene.setBackgroundBrush(Qt::red);

    QPen pen;   // 定義一個畫筆,設置畫筆顏色和寬度
    pen.setColor(QColor(0, 160, 230));
    pen.setWidth(10);

    QGraphicsRectItem *m_rectItem = new QGraphicsRectItem();   // 定義一個矩形圖元
    m_rectItem->setRect(0, 0, 80, 80);
    m_rectItem->setPen(pen);
    m_rectItem->setBrush(QBrush(QColor(255, 255, 255)));
    m_rectItem->setFlag(QGraphicsItem::ItemIsMovable);
    scene.addItem(m_rectItem);      // 把矩形圖元添加到場景

    QDialog *dialog = new QDialog(nullptr, Qt::CustomizeWindowHint | Qt::WindowTitleHint);
    dialog->setWindowOpacity(0.8);
    dialog->setWindowTitle("operation");
    dialog->setLayout(new QVBoxLayout);
    QPushButton *m_zoomInBtn = new QPushButton("zoomIn");
    QPushButton *m_zoomOutBtn = new QPushButton("zoomOut");
    QPushButton *m_rotateLeftBtn = new QPushButton("rotateLeft");
    QPushButton *m_rotateRightBtn = new QPushButton("rotateRight");
    dialog->layout()->addWidget(m_zoomInBtn);
    dialog->layout()->addWidget(m_zoomOutBtn);
    dialog->layout()->addWidget(m_rotateLeftBtn);
    dialog->layout()->addWidget(m_rotateRightBtn);
    scene.addWidget(dialog);

    MyGraphicsView view; // 定義一個視圖,並把場景添加到視圖
    view.setScene(&scene);
    view.resize(1024, 768);
    view.show();

    // 點擊按鈕實現視圖的縮放和旋轉
    QObject::connect(m_zoomInBtn, &QPushButton::clicked, [&]() { view.zoomIn(); });
    QObject::connect(m_zoomOutBtn, &QPushButton::clicked, [&]() { view.zoomOut(); });
    QObject::connect(m_rotateLeftBtn, &QPushButton::clicked, [&]() { view.rotateLeft(); });
    QObject::connect(m_rotateRightBtn, &QPushButton::clicked, [&]() { view.rotateRight(); });

    return a.exec();
}

在這裏插入圖片描述

打印

Qt中對打印的支持是有一個獨立的 printsupport 模塊來完成的,所以要想在程序中使用Qt的打印功能,必須先在pro文件中添加:
QT += printsupport

圖形視圖通過它的展示函數:QGraphicsScene::render() 和 QGraphicsView::render() 提供單線(single-line)打印。這些函數提供相同的API,通過將 QPainter 傳遞給展示函數,你可以打印場景、視圖的全部或部分內容。

場景和視圖的渲染函數的不同在於 QGraphicsScene::render() 使用場景座標,而 QGraphicsView::render() 使用視圖座標。QGraphicsScene::render() 經常用於打印未變換場景中的整塊,例如一塊圖形數據或是打印一個文本文檔。 QGraphicsView::render() 適合用於打印屏幕快照(screenshots),缺省情況下它展示視圖端口中的當前內容。

官方示例:在這裏插入圖片描述在這裏插入圖片描述

拖拽和碰撞檢測

由於 QGraphicsView 繼承自 QWidget,所以 GraphicsView 同樣提供了拖拽功能。此外,GraphicsView 框架也爲場景、圖元提供拖拽支持。當視圖接收到拖拽事件,GraphicsView 框架會將拖拽事件翻譯爲 QGraphicsSceneDragDropEvent 事件,再發送到場景,場景接管事件,再把事件發送到光標下接受拖拽的第一個圖元

爲了在場景中獲取拖拽事件,你需要重新實現QGraphicsScene::dragEnterEvent() 和在 QGraphicsItem 的子類裏任何與你特定場景需要的事件處理器。items 也可以通過調用 QGraphicsItem::setAcceptDrops() 獲得拖拽支持,爲了處理將要進行的拖拽,你需要重新實現 dropEvent、dragdragEnterEvent、dragLeaveEvent、dropMoveEvent、mousePressEvent、mouseReleaseEvent 和 mouseMoveEvent

爲了處理碰撞時的行爲,我們需要創建 QGrahicsItem 的一個子類,然後重新實現 boundingRect 和 paint。boundingRect 用於返回圖元繪製所需要的估測區域,而 paint 實現實際的繪圖操縱

這裏展示一個小例子,外面一圈是 colorItem 實現了拖拽,中間是個 dropItem 實現了碰撞檢測。當我把某個 colorItem 拖拽並觸碰到 dropItem 時,dropItem 的顏色就會變成 colorItem 的顏色。代碼太多就不放了,感興趣的小夥伴可以在最下面示例中下載源代碼。

在這裏插入圖片描述

光標與工具提示

像QWidget一樣,QGraphicsItem也支持光標 QgraphicsItem::setCursor() 與工具提示 QGraphicsItem::setToolTip()。當光標進入到item的區域,光標與工具提示被 QGraphicsView 激活,通過調用 QGraphicsItem::contains()來檢測。你也可以直接在視圖上設置一個缺省光標 QGraphicsView::setCursor()。

動畫

GraphicsView 框架支持多種層次的動畫,使用動畫框架可以很容易製作出動畫。GraphicsView 框架支持的動畫實現種類如下:

  • 圖元需要繼承自 QGraphicsObject,並且需要聯結 QPropertyAnimation屬性
  • 創建繼承自 QObject 和 QGraphicsItem 的圖元,圖元可以設置自己的定時器,通過在QObject::timeEvent() 中增加步進的方式來控制動畫
  • 通過調用 QGraphicsScene::advance() 來推進場景,依次調用QGraphicsItem::advance()

OpenGL渲染

爲了使用 OpenGL 渲染,你要設置一個新的 QGLWidget 作爲QGraphicsView 的視口 QGraphicsView::setViewPort()。假如你讓 OpenGL 提供反鋸齒功能,你需要 OpenGL 採樣緩衝支持。

QGraphicsView view;
view.setViewport(new QGLWidget(QGLFormat(QGL::SampleBuffers)));
view.setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
view.setScene(new OpenGLScene);
view.show();

Item組

通過把一個圖元做爲另一個圖元的孩子,可以得到圖元組的大多數本質特性:所有圖元會一起移動,所有變換會從父到子傳遞

另外,QGraphicsItemGroup 是一個特殊的圖元。爲了增加和刪除圖元,它使用一個有用接口合併了子圖元的事件處理。把一個圖元加到QGraphicsItemGroup 仍會保留圖元的原始位置與變換,而給一個圖元重新指定父圖元則會讓圖元根據其新的父親重新定位。可以用QGraphicsScene::createItemGroup() 創建圖元組。

圖形組件和佈局

QT4.4 通過 QGraphicsWidget 支持圖形和圖元佈局。QGraphicsWidget 類似於 QWidget,但 QGraphicsWidget 並不從 QPaintDevice 繼承,而是繼承自 QGraphicsItem。QGraphicsWidget 支持事件、信號與槽、大小和策略。通過 QGraphicsLinearLayout、QGraphicsGridLayout 可以對圖形組件進行佈局管理。

QGraphicsWidget 繼承了 QWidget 和 QGraphicsItem 的優點,如 QWidget的樣式、字體、調色板、佈局方向以及 QGraphicsItem 的圖形、獨立精度和變換支持。

QGraphicsLayout 是專爲 QGraphicsWidget 特殊設計的第二代佈局框架。QGraphicsLayout 的API類似於 QLayout。通過 QGraphicsLinearLayout 和QGraphicsGridLayout 可以管理組件與子佈局。

嵌入組件

圖形視圖框架爲嵌入任何組件到場景提供了無縫支持。可以嵌入簡單的組件,如 QLineEdit、QPushButton,或是複雜的組件如 QTableWidget,甚至是主窗口。

要嵌入組件到場景,只需要調用 QGraphicsScene::addWidget(),或是創建一個 QGraphicsProxyWidget 實例,手動嵌入組件。通過 QGraphicsProxyWidget,圖形視圖框架可以深度整合客戶組件特性,如光標、工具提示、鼠標、平板和鍵盤事件、子組件、動畫、彈拉框、組件輸入焦點和激活。QGraphicsProxyWidget 甚至整合了嵌入組件的 tab 順序,可以通過 tab 選擇嵌入的組件。甚至可以嵌入一個 QGraphicsView 到場景。

示例

  1. 拖拽和碰撞檢測示例
    github 源代碼下載

  2. 網上的一個3D模型示例
    github 源代碼下載

在這裏插入圖片描述

更多請參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章