---
# System prepended metadata

title: Qt Graphics 系列介紹
tags: [lion_1082]

---

---
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`