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