---
title: Qt Graphics 系列介紹
description: 常見 QGraphics 系列元件介紹與使用示範
---
# <img src="https://upload.wikimedia.org/wikipedia/commons/0/0b/Qt_logo_2016.svg" width="8%" alt="Qt" /> Graphics 系列介紹
:::warning
講解影片:https://youtu.be/B4J64NmlWVA
:::
## :question: QGraphics
QGraphics 是 Qt 中的一種框架,可以管理大量的自製的圖形單元,支援以下功能:
* 座標變換
* 碰撞檢測
* 滑鼠事件
* 鍵盤事件
我們可以使用多重繼承搭配一系列 QGraphics 與其他的 class 組合出功能複雜的視窗程式與遊戲。
### 用 QGraphics 所設計的遊戲範例:
<details>
<summary>西洋棋</summary>
<center>
<img src="https://i.imgur.com/0CFAGRI.gif" width="50%" />
</center>
</details>
<details>
<summary>小精靈</summary>
<center><img src="https://i.imgur.com/67TJ9qa.gif" width="50%" /></center>
</details>
## :bulb: 相關模型
基本的 QGraphics class 如下:
- QGraphicsView - 觀看視角
- QGraphicsScene - 場景
- QGraphicsItem - 物件主體
- QGraphicsRectItem
- QGraphicsPixmapItem
- QGraphicsObject
- QGraphicsItem
![](https://hackmd.io/_uploads/rkzb-XSV2.png)
## :camera: [QGraphicsView](https://doc.qt.io/qt-5/qgraphicsview.html)
視角,支援視角縮放等等功能
需要加入 `<QGraphicsView>`
有兩種使用的方法:
1. 直接在 mainwindow 中建立 QGraphicsView
2. 使用 QGraphicsView 作為視窗主體
```cpp
QGraphicsView *view = new QGraphicsView();
view->setScene(scene); // 與 QGraphicsScene 綁定
view->setFixedSize(500, 400); // 設定 QGraphicsView 的大小
view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff) // 設定滾動條的顯示方式
view->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff)
```
## :star: [QGraphicsScene](https://doc.qt.io/qt-5/qgraphicsscene.html)
場景,將物件與圖片擺放的位置,定義在 `<QGraphicsScene>` 中
```cpp
QGraphicsScene *scene = new QGraphicsScene();
scene->setSceneRect(0, 0, 500, 400); // 設定 scene 在 view 中的位置與大小
```
## :8ball: [QGraphicsItem](https://doc.qt.io/qt-5/qgraphicsitem.html)
基本的 QGraphics 物件 (定義在 `<QGraphicsItem>`),接下來要介紹的 QGraphicsRectItem, QGraphicsPixmapItem, QGraphicsTextItem 全部都是從它延伸擴充而成
```cpp
QGraphicsItem *item = new QGraphicsItem();
item->setPos(x, y); // 設定物件在 scene 中的座標
item->setX(x); // 設定物件的 x 座標
item->setY(y); // 設定物件的 y 座標
double x = item->x(); // 取得物件的 x 座標位置
double y = item->y(); // 取得物件的 y 座標位置
```
## :white_large_square: [QGrphicsRectItem](https://doc.qt.io/qt-5/qgraphicsrectitem.html)
就是一個正方形,定義在 `<QGraphicsRectItem>`
```cpp
QGraphicsRectItem *rect = new QGraphicsRectItem();
rect->setRect(0, 0, 50, 50); // 設定 rect 在 scene 中的座標位置與大小
rect->setPos(100, 200); // 設定 rect 在 scene 中的座標位置
scene->addItem(rect); // 將 rect 加入 scene 中顯示
```
### 使用 [`QBrush`](https://doc.qt.io/qt-5/qbrush.html) 與 [`QPen`](https://doc.qt.io/qt-5/qpen.html) 改變外觀
- `QBrush`: 著色
- `QPen`: 畫外框
```cpp
QPen pen;
pen.setColor(color); // 可以使用 QColor 內建的顏色,也可以利用 RGB 色彩設定比列
pen.setWidth(width); // 設定畫筆寬度
rect->setPen(pen); // 指定外框的設定
rect->setBrush(Qt::red); // 指定塗色的設定
```
## :frame_with_picture: [QGraphicsPixmapItem](https://doc.qt.io/qt-5/qgraphicspixmapitem.html)
可以使用圖片的物件,記得引用 `<QGraphicsPixmapItem>` 。
```cpp
QGraphicsPixmapItem *pic = new QGraphicsPixmapItem();
pic->setPixmap(QPixmap(path_to_your_picture));
scene->addItem(pic);
```
## :abc: [QGraphicsTextItem](https://doc.qt.io/qt-5/qgraphicstextitem.html)
QGraphics 的文字物件,定義在 `<QGraphicsTextItem>`
```cpp
QGraphicsTextItem *text = new QGraphicsTextItem();
text->setFont(QFont(font_family, font_size)); // 利用 QFont 設定字型與字體大小
text->setPlainText("Hello World"); // 設定要顯示的文字
text->setDefaultColor(Qt::red); // 設定字體顏色
scene->addItem(text);
```
## :open_file_folder: [QGraphicsItemGroup](https://doc.qt.io/qt-5/qgraphicspixmapitem.html)
將多個物件包裝在一起,類似 Word 與 PowerPoint 群組化物件的功能,使用前記得在 header 加入 `<QGraphicsItemGroup>`。
<img src="https://hackmd.io/_uploads/BycGZQHE3.png" width="45%" />
<img src="https://hackmd.io/_uploads/BJlVbQr43.png" width="45%" />
```cpp
QGraphicsItemGroup *group = new QGraphicsItemGroup();
group->addToGroup(rect);
group->addToGroup(pic);
scene->addItem(group);
```
## :collision: [QGraphicsItem::collidesWithItem](https://doc.qt.io/qt-5/qgraphicsitem.html#collidesWithItem)
可以用來判斷兩個物件有沒有碰撞的函式
```cpp
bool isCollided = item1->collidesWithItem(item2, mode);
```
Qt 提供下列等碰撞的模式供我們使用 (詳細的描述可以參考[官方文件](https://doc.qt.io/qt-5/qt.html#ItemSelectionMode-enum))
1. `Qt::ContainsItemShape` : 判斷物件是否包覆
2. `Qt::IntersectsItemShape` : 判斷物件是否相交、包覆(預設)
3. `Qt::ContainsItemBoundingRect` : 判斷最小外接矩形是否包覆
4. `Qt::IntersectsItemBoundingRect` : 判斷最小外接矩形是否相交、包覆
## :pencil: 設計思維
1. 思考要建立的物件需要使用到哪些功能
- 使用鍵盤移動
- 加入圖片
- 使用動畫
2. 決定使用哪個 class 作為模板,疊加出你所需要的功能
- ex:以 QGraphicsPixmapItem 作為基底,使用 QTimer 做成動畫等等
3. 利用 constructor 做初始的設定
- ex:載入圖片,設定起始位置,一開始要顯示還是隱藏等等
5. 使用成員函式定義行為
- ex:定義物體運動,按下鍵盤對應的動作
7. 加入 QGraphicsScene 中並依照用途進行操作
## :information_desk_person: 餐餐自由配
- QGraphicsItem + QKeyEvent
- QGraphicsItem + QTimer + QObject
- QGraphicsItem + QPropertyAnimation
## :movie_camera: 參考影片
- [C++ Qt Game Tutorial](https://www.youtube.com/playlist?list=PLyb40eoxkelOa5xCB9fvGrkoBf8JzEwtV)
###### tags: `lion_1082`