Qt

A Very Quick Overview
 
Eddy @ NCKU CSIE 
 


可用方向鍵操作


Qt做遊戲懶人包

 

簡介

  • Qt專案與QtCreator
  • QObject物件系統
  • Event事件系統
  • Signal & Slot事件系統
  • QPainter

Qt專案與QtCreator




Project檔

# ← 註解開頭

# Qt 組件
QT +=  core gui
TEMPLATE = app

#欲編譯的檔案,每次編譯前可用下頁指令生成
SOURCES += \
    main.cpp \
    MyWidget.cpp \
    ... (and others)
HEADERS += \
    MyWidget.h \
    ... (and others)


  • 用來製作Makefile的專案資訊檔

生成Project檔--2 Ways

  • qmake -project
  • QtCreator
    • 建立一個Qt Widget Application
    • 是做遊戲入門最簡便的作法
    • 取消勾選產生表單(遊戲用不到)
    • 其他應該不需解釋

編譯與執行     

1.使用command line  

qmake-project # 更新project檔
qmake # 生成makefile 
make # 編譯 
./程式名稱 

2.使用Qt Creator

  • 尋找三角形執行按紐


→QObject物件系統

QOject物件系統     




 




  • 繼承QObject的class的泛稱
  • QObject才能使用signal等機制
  • 有特定的記憶體管理方式
  • (繼承時)有固定特殊寫法

QObject

 

使用QObject -記憶體

  • Stack:自動配置記憶體
    • 不需設定parent
    • 區塊結尾自動清除
    • 記憶體方面跟普通物件一樣

void some_function(){
    QObject object;
} // ← 於此清除

 

使用QObject -記憶體

QObject *object = new QObject( parent );
  • 動態配置:
    • 設定parent 
      • (parent必須也是個QObject)
      • 當parent消失時跟著消失
      • 不需手動清除
    • 沒設定parent
      • 對要刪除的物件呼叫deleteLater
QObject *object = new QObject();
object -> deleteLater(); 

繼承QObject

  • 待會兒會解釋為何會需要繼承
  • 以QWidget為例 
class MyWidget : public QWidget {
    Q_OBJECT // 固定寫法,記得要補上,讓QT能在compile之前生成必要的程式碼
public:
    MyWidget(QWidget *parent = 0)  //讓此物件預設沒有parent,但可以明確指定
        : QWidget(parent)   
    {
        //...
    }
  //以下選擇性
signals:  //接下來會解釋
public slots:  //接下來會解釋
private:
protected:
  //...
};

→Event事件實作

兩種事件系統之前...

用Qt寫程式用的是事件驅動,
也就是說,並不是一直線的執行程式,
而是「有事件時,處理該個事件」的作法。
進入事件循環→ app.exec();
初始化物件→
QApplication app; 
MyWidget *widget = new Mywidget;
widget -> show(); 
Qt事件循環丟出事件
處理事件
main↓
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    MyWidget *w = new MyWidget();
    w -> show();

    return a.exec();
}



MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent)
{// signal&slot 機制,每隔一段時間得到timeout()事件,觸發Tick()這個自己寫的function
    QTimer* timer = new QTimer( this );
    connect( timer, SIGNAL( timeout() ), this, SLOT( Tick() ) );
    timer->start( 10 );
}
    


Event事件 




 

Event?

  • Qt內建之訊息機制,利用繼承
  • 透過Override來接收事件,並進行處理
  • 用滑鼠事件示範,使用前面的MyWidget
//class宣告內加上

protected: 
    mousePressEvent(QMouseEvent *event); //Override

//CPP檔案實作

MyWidget::mousePressEvent(QMouseEvent *event){
   cout << "Click : " 
        << event -> x() << "," 
        << event -> y() << endl;
}
於是就會在滑鼠點擊MyWidget時,
輸出點擊的座標。

有哪些事件可以接收?


  • QWidget
http://qt-project.org/doc/qt-4.8/qwidget.html#protected-functions

Event會放在class的protected區段,
且是virtual function

→Signal & slot

Signals & Slots 




 

特性

  • 送出訊號(signal)端必須是QObject的一種
  • 可使兩個不相干的物件進行溝通
  • 跟event不同的是,我們可以自行產生signals

寫法

宣告
◎ 在送出事件的class:signals:
void SomethingHappened(); //沒有實作,僅需要被呼叫
接收事件的class (直接使用public的function亦可)
public slots: void SomethingToDo(); //其實跟普通的function沒有區別
實作
//Signal只代表事件發生,不做處理,故沒有內容//Slot做處理,但不知道是什麼事件
void MyQObjectClass::SomethingToDo(){
    // do something...
}


 connect( 來源物件,SIGNAL( SomethingHappened() ), 目標物件, SLOT( SomethingToDo() )); // 是 QObject 的static function

觸發signal
連結
  • 來源物件發生某事(Signal)時,呼叫目標物件的某Slot
 emit 來源物件 -> SomethingHappened();
//emit可省略
 

實例

Child *child =  new Child();
ScoreBoard *scoreBoard = new ScoreBoard();

QObject::connect( child , SIGNAL( beingAttack() ),
                   scoreBoard, SLOT( decreaseScore() ) );
//-----------
當執行child->beingAttack();時,會呼叫所有它連結到的slot

(Qt官方文件寫的是emit child->beingAttack(); , 但作用其實一模一樣)
MyWidget *widget = new MyWidget();
QTimer *timer = new QTimer();
QObject::connect( timer , SIGNAL( timeout() ),
                   widget, SLOT( repaint() ) );
timer -> start(10); //開始每0.01秒送出一個timeout()的signal
//每0.01秒重繪一次畫面

 
注意事項:
  • 連結的Signal和Slot的參數要相同
  • Slot和Signal的連結關係可以是多對多
  • 若Slot是普通function,不需要目標物件
  • connect( source , SIGNAL( s() ), DoSomething ) 

→QPainter

QPainter




可繪製物件

  • QPaintDevice
    • QWidget是他的子類別

藉由Override paintEvent來繪製圖形

void MyWidget::paintEvent( QPaintEvent * event ) {  //當畫面需要重繪時
    /* 繪出所有要出現在畫面上的東西,然後QWidget會把繪製出的圖片貼到畫面 */
    QPainter painter;
    painter.begin(this); //表示要在這個Widget上繪圖
                         // (Widget是一個QPaintDevice)
    painter.fillRect( QRect(10,10,30,30) //x,y,寬,高
                      QColor(0,255,255,255) //yellow (RGB A) 
                    );

}

參考資料

  • QPainter
http://qt-project.org/doc/qt-4.8/qpainter.html

  • drawPicture(畫出圖片)
    • 有範例可參考
http://qt-project.org/doc/qt-4.8/qpainter.html#drawPicture

呼叫重繪

記得呼叫重繪,否則只有開啟視窗那一刻繪圖,
(或是畫面大小變動時)
平常畫面不會主動更新。




參考作法
MyWidget *widget = new MyWidget();
QTimer *timer = new QTimer();
QObject::connect( timer , SIGNAL( timeout() ),
                   widget, SLOT( repaint() ) );
timer -> start(10);
//每0.01秒重繪一次畫面

遊戲Loop作法參考

class Game : public QObject{ Q_OBJECT
public:
    Game(){
        QTimer *timer = new QTimer(this);
        QObject::connect( timer , SIGNAL( timeout() ),
                          this  , SLOT( Tick() )  );         MakeNewWindow;
    }
    void Tick() {
        UpdateGameObject();
        window_ -> repaint();
    }
private:
    //...
    MyWidget *window_;
}
int main(int argc,char **argv){

    QApplication app(argc,argv);
    Game game;
    return app.exec();
}


 Example by KTYeh

End

有任何問題或錯誤歡迎在底下討論與指正
或是寄信給我

Copy of Qt

By aben20807

Copy of Qt

對於使用Qt製作2D遊戲做簡單的介紹

  • 190