顯示具有 Qt4 標籤的文章。 顯示所有文章
顯示具有 Qt4 標籤的文章。 顯示所有文章

2011年10月7日 星期五

[Qt] How to load HTMLs to QWebView from resource

  • Example1:
    • In HTML file, some resource file is loaded from qt resource.

  • Example2:
    • Loading a HTML file from a resource file.

  • PS: It is not working by using - QWebView::setUrl(QUrl("qrc:/resource/path"))

2011年9月22日 星期四

Build qjson with Qt4 for ARM

Build qjson (JSON Library for Qt4) with Qt4 for ARM

1. download qjson source code from official website
    - http://gitorious.org/qjson

2. set cmake configure file to find a specific Qt4 source
    - extract file and enter the folder
    - edit CMakeList.txt and add the following sentence before FIND_PACKAGE( Qt4 REQUIRED )
set( DESIRED_QT_VERSION 4 )
set( QT_QMAKE_EXECUTABLE "/home/qt-everywhere-opensource-src-4.7.4-Embedded/bin/qmake" ) - set this by your environment
set( QT_QMAKE_LOCATION "/home/qt-everywhere-opensource-src-4.7.4-Embedded/bin" ) - set this by your environment
FIND_PACKAGE( Qt4 REQUIRED )
3. compile qjson source code
    - cmake -DCMAKE_INSTALL_PREFIX=path_to _install_qjson/
    - make
    - make install

2011年9月21日 星期三

Build SDK - qt-everywhere-opensource-src-4.7.4 for ARM


How to Build SDK - qt-everywhere-opensource-src-4.7.4 for ARM

Prepare working - Dependency Libraries

(download them from official website)
1. tslib - https://github.com/kergoth/tslib
2. openssl-1.0.0e - http://www.openssl.org/source/
3. libpng-1.2.46 - http://www.libpng.org/pub/png/libpng.html

compile them and put them to your cross compiler library directory.


Building Qt-4.7.4 SDK

1. download Qt libraries 4.7.4 for embedded Linux (202 MB) from http://qt.nokia.com/downloads
2. extract file and enter the folder
3. If you want to compile some plugin libraries together, please put them into qt library plugin folder.
    (Qt library plugin folder  "./qt-everywhere-opensource-src-4.7.4-Embedded/src/plugins")
4. setting configure - my setting parameters
./configure -prefix /usr -xplatform qws/linux-arm-g++ -embedded arm -developer-build -opensource -confirm-license -fast -qt-sql-sqlite -no-qt3support -no-phonon -no-phonon-backend -qt-freetype -system-libpng -no-libmng -qt-libjpeg -no-rpath -no-nis -no-cups -separate-debug-info -openssl -no-opengl -little-endian -nomake examples -nomake demos -accessibility -plugin-gfx-liunxfb -plugin-mouse-tslib -L/usr/local/arm/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/lib/ -I/usr/local/arm/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/include -L/usr/local/arm/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/usr/lib/ -I/usr/local/arm/gcc-4.1.2-glibc-2.5-nptl-3/arm-none-linux-gnueabi/usr/include -D QT_KEYPAD_NAVIGATION -verbose
5. make
6. make install ( Qt will be installed into prefix path that you set )

2010年12月3日 星期五

Qt Memory Management & Signal and Slots

Check out this SlideShare Presentation:

2010年11月1日 星期一

Qt: QRegion Class 圖形交疊的四種取出作法

Creating and Using Regions

當在Qt使用QPainter繪圖時,常常會遇到所需繪出圖形並非單純的長方形(Rectangle)或多邊形(polygon),可能是多種圖形的交錯合體情況,以下說明當圖形重疊時,可取得相交區域的四種情形。

General Usage:
void MyWidget::paintEvent(QPaintEvent *)
{
    QRegion r1(QRect(100, 100, 200, 80), QRegion::Ellipse);
    // r1: elliptic region
    QRegion r2(QRect(100, 120, 90, 30));    // r2: rectangular region
    QRegion r3 = r1.intersected(r2);        // r3: intersection
    QPainter painter(this);
    painter.setClipRegion(r3);
    ...                                     // paint clipped graphics
    painter.drawrect(QRect(100, 100, 200, 80));
}

  1. 交集-僅取出兩者相疊區域(intersected):
    • QRegion QRegion::intersected ( const QRegion & r ) const
    • 圖例:
  2. 僅取出前者未與後者重疊區域(subtracted):
    • QRegion QRegion::subtracted ( const QRegion & r ) const
    • 圖例:
  3. 聯集-合併取出兩者所有區域(united):
    • QRegion QRegion::united ( const QRegion & r ) const
    • 圖例:
  4. 取出兩者不重疊的區域(xored):
    • QRegion QRegion::xored ( const QRegion & r ) const
    • 圖例:



更詳細資料請參考:Qt4.6 QRegion Class Reference

2010年9月17日 星期五

Qt4 學習筆記(九):循序容器 (QVector、QLinkedList、QList) 與迭代器 (iterator)

  • QVector、 QLinkedList與QList是Qt所提供的幾個常用容器類別。
    • QVector將項目(item)儲存在鄰接的記憶體空間之中,提供基於索引(index-based)存取方式的容器類別。
    • QLinkedList以鏈結(Linked)的方式儲存項目,提供基於迭代器(iterator- based)存取方式的容器類別。
    • QList提供基於索引的快速存取容器類別,內部使用指標陣列,可提供快速插入及移除項目。
  • 列出QVector、QLinkedList及QList的使用比較:
    • 如果想要有連續鄰接的記憶體空間來存放元件,則使用QVector。
    • 如果需要真正的鏈結資料結構,並使用基於迭代器的存取方式,則使用QLinkedList。
    • 在大部份情況下,QList可以滿足快速存取、插入、移除的需求,並可提供基於索引的存取方式。
  • QVector
  • QVector的基本使用方式,建立一個可容納兩個元素的QVector,並使用索引方式存取元素值:
    #include <iostream>
    #include <vector>
    using namespace std;
    
    QVector<double> vect(2);
    vect[0] = 1.0;
    vect[1] = 2.0;
    
    for (int i = 0; i < vect.count(); ++i) {
        // 使用 [] 運算子指定索引存取
        cout << vect[i] << endl;
    }
    
    for (int i = 0; i < vect.count(); ++i) {
        // 使用 at() 方法指定索引存取
        cout << vect.at(i) << endl;
    }
    
    可以使用QVector的append()方法來加入元素,使用remove()方法來移除元素,使用insert()方法來插入元素,例如append()的使用如下:
    vect.append(3.0);
    vect.append(4.0);
    
    或者是使用<<運算子附加元素:
    vect << 5.0 << 6.0;
    
    QVector提供的是鄰接的記憶體空間以存取物件,所以對於循序存取或使用索引,效率較高,但如果要插入或移除元素時,效率就會低落。QVector的子類別QStack提供了push()、pop()、top()等方法,方便進行堆疊結構的物件管理。
  • QList
  • QList提供的是基於索引的存取方式,其內部實作使用了指標陣列,陣列中每個指標指向所要儲存的元素,結合了QVector與QLinkedList的優點,提供快速存取與插入、移除,其索引存取方式或可用的方法與QVector是類似的,也可以使用<<運算子來附加元素。
    QList<QString> list;
    list << "caterpillar" << "momor" << "bush";
    
    for(int i = 0; i < list.size(); ++i) {
        cout << list[i].toAscii().data() << endl;
    }
    cout << endl;
        
    for(int i = 0; i < list.size(); ++i) {
        cout << list.at(i).toAscii().data() << endl;
    }    
    cout << endl;
    
    QList的子類別QStringList為Qt中應用很廣的類別,可以讓您儲存QString物件,QList的子類別QQueue則提供了佇列結構的容器管理。
  • QIterator
    • 關於迭代器於容器類別的使用,Qt提供兩種風格的迭代器:Java風格與STL風格。Java風格的迭代器使用上就如同Java的迭代器,使用這種迭代器對於Java開發人員較為容易,然而STL風格的迭代器則提供更有彈性的操作。
    • Java-Style iterator
    簡單示範在QList上使用Java風格迭代器:
    // Java-Style Iterator
    QList<QString> list;
    list << "caterpillar" << "momor" << "bush";
        
    QListIterator<QString> iterator(list);
    while (iterator.hasNext()) {
        cout << iterator.next().toAscii().data() << endl;
    }
    
    與Java迭代器類似的,hasNext()測試是否有下一個元素,next()傳回下一個元素,其它還有hasPrevious()、previous()等方法可以使用。Java風格的迭代器有兩種:唯讀與可讀寫。QListIterator是唯讀迭代器,對於可讀寫迭代器,命名上會加上Mutable,例如QMutableListIterator,除了next()、previous()等方法之外,還提供了insert()、remove()等方法可以使用,以QLinkedList使用Java風格迭代器為例:
    QLinkedList<QString> list;
    list << "caterpillar" << "momor" << "bush";
    
    QMutableLinkedListIterator<QString> rwIterator(list);
    while (rwIterator.hasNext()) {
        if(rwIterator.next() == "momor") {
            rwIterator.insert("bee");
            break;
        }
    }
    
    QLinkedListIterator<QString> rIterator(list);
    while (rIterator.hasNext()) {
        cout << rIterator.next().toAscii().data() << endl;
    }
    
    • STL-Style iterator
    • 關於使用STL風格迭代器,可以使用容器類別的begin()方法傳回基於STL的迭代器,它指向容器的第一個元素位址,end()方法則傳回指向容器最後一個元素之後的位址。您可以如下使用基於STL的迭代器:
    // STL-Style Iterator
    QList<QString> list;
    list << "caterpillar" << "momor" << "bush";
    
    QList<QString>::const_iterator i = list.begin();
    while (i != list.end()) {
        cout << (*i).toAscii().data() << endl;
        ++i;
    }
    
    STL風格的迭代器一樣有兩種,C<T>::const_iterator形式的迭代器宣告為唯讀,可以讀取資料,但無法修改資料,C<T>::iterator形式的迭代器則可以修改資料,例如:
    QList<QString> list;
    list << "caterpillar" << "momor" << "bush";
        
    QList<QString>::iterator i = list.begin();
    while (i != list.end()) {
        (*i) = (*i) + ".onlyfun";
        cout << (*i).toAscii().data() << endl;
        ++i;
    }
    
    對於簡單的循序存取,Qt提供了foreach虛擬關鍵字(pseudo-keyword),以標準的for迴圈實作,例如您可以如下循序取出QList中的元素:
    QList<QString> list;
    list << "caterpillar" << "momor" << "bush";
        
    foreach(QString str, list) {
        cout << str.toAscii().data() << endl;
    }
    

2010年9月14日 星期二

Qt4 學習筆記(八):Custom Event and Post Event

  • Custom Event and Post Event
自訂事件類型,最簡單的方式,是透過QEvent::Type指定事件類型的常數值,在建構QCustomEvent時作為建構引數並透過postEvent()傳送事件,例如:
const QEvent::Type MyEvent = (QEvent::Type) 9393;
...
QApplication::postEvent(object, new QCustomEvent(MyEvent));
自訂事件必須定義事件號碼(Event number),自定義的事件號碼必須大於QEvent::Type的列舉值,通常1024以下的值是保留給Qt預先定義的事件類型來使用。object是事件的接受者,使用 postEvent()方法時,事件必須以new的方式建立,在事件處理完畢之後,會自動將事件delete,postEvent()會將事件放至事件佇列的尾端,然後立即返回。若要強迫Qt馬上處理先前postEvent()排到佇列的事件,則可以使用sendPostedEvents()。
您可以使用sendEvent()方法,事件會立即送至接受者,sendEvent()方法的事件不會被delete,所以通常建立在堆疊(Stack)區,例如:
CustomEvent event("Event Message");
QApplication::sendEvent(object, &event);
自訂的事件類型必須是QEvent的子類別,通常繼承QCustomEvent類別,建立自訂事件類別可以獲得更多的型態安全(Type safety)。

  • 要處理自訂事件,可以重新定義customEvent()方法,例如:
void CustomWidget::customEvent(QCustomEvent *event) {
    CustomEvent *customEvent = static_cast<CustomEvent *>(event);
    ....
}
  • 或是重新定義event()方法,將自訂事件分派給其它函式或直接在event()中處理,例如:
bool CustomWidget::event(QEvent *event) {
    if (event->type() == MyCustomEventType) {
        CustomEvent *myEvent = static_cast<CustomEvent *>(event);
        // 對自訂事件的處理,或呼叫其它函式來處理事件
        return true;
    }
    return QWidget::event(event);
}

Qt4 學習筆記(七):Event Filter

  • Event Filter
Qt將事件封裝為QEvent實例之後,會呼叫QObject的event()方法並將QEvent實例傳送給它,在某些情況下,會希望物件在執行event()處理事件之前,先對一些事件進行處理或過濾,然後再決定是否呼叫event()方法,這個時候就可以使用事件過濾器。

舉例來說,對QWidget按鍵事件的Tab鍵處理而言,如果圖形介面中有很多的元件,每個圖型元件都要如當中的範例重新定義event()方法,顯然是非常沒有效率且沒什麼維護性的方法。

可以藉由自定義一個物件繼承QObject(或其子類別),重新定義它的eventFilter()方法,例如自定義了一個FilterObject,希望Tab鍵可以用來將焦點轉移至下一個子元件:
bool FilterObject::eventFilter(QObject *object, QEvent *event) {
    if(event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Tab) {
            // 處理Tab鍵
            return true;
        }
    }
    return false;
}
eventFilter()的object參數表示事件發生的來源物件,eventFilter()若傳回false,則安裝該事件過濾器的物件之event()就會繼續執行,若傳回true,則安裝該事件過濾器的物件之event()方法就不會被執行,由此進行事件的攔截處理。

要為指定的物件安裝事件過濾器,可以使用物件的installEventFilter()方法,例如:
QLineEdit *nameEdit = new QLineEdit;
QLineEdit *addressEdit = new QLineEdit;
...
FilterObject filter = new FilterObject;
...
nameEdit->installEventFilter(filter);
addressEdit->installEventFilter(filter);
....

Notes:
  • 也可以將事件過濾器安裝在QApplication,在任何的事件發生後呼叫每個物件的event()方法之前,會先經過事件過濾器,這可提供更多控制應用程式事件的能力。
  • Qt的事件迴圈與sendEvent()方法會呼叫QCoreApplication(QApplication的父類別)的notify()以分派事件,如果想要完全控制Qt應用程式的事件,則可以重新定義notify()方法。
P.S.
由此可以看出Qt事件處理的五個層次:
  1. 重新定義事件處理者
  2. 重新定義event()方法
  3. 為個別物件安裝事件過濾器
  4. 為QApplication安裝事件過濾器
  5. 重新定義QCoreApplication的notify()方法

2010年9月13日 星期一

Qt4 學習筆記(六):Event Accept or Ignore and event() method

  • Event Accept or Ignore and event() method
不同類型的事件,都有對應的事件處理函式,它們接受QEvent的特定子類別作為引數,像是下例中mousePressEvent()事件處理函式上的 QMouseEvent,可以針對事件的不同狀況作特定處理,而其它未指定的狀況,則呼叫父類別對應的的事件處理函式,讓父類別預先定義的事件處理來完成。
void CustomLabel::mousePressEvent(QMouseEvent *event) {
     if (event->button() == Qt::LeftButton) {
         // 指定處理當滑鼠左鍵按下事件
         // ....
     } else {
         // 由父類別所定義的事件處理函式來處理
         QLabel::mousePressEvent(event);
     }
}
void CustomLabel::mouseReleaseEvent(QMouseEvent *event) {
    // 滑鼠放開事件處理....
}

每個可傳播的事件都有accept()與igore()兩個方法,用以告知Qt應用程式,這個事件處理者是否接受或忽略此一事件,如果事件處理者中呼叫事件的accept(),則事件不會再進一步傳播,若呼叫了ignore(),則Qt應用程式會嘗試尋找另一個事件的接受者,您可以藉由isAccepted()方法得知事件是否被接受。

一般來說,除了QCloseEvent之外,很少直接呼叫accept()或ignore(),如果您接受事件,則在事件處理者當中實作對事件的處理(如上例的if陳述句),如果您不接受事件,則直接呼叫父類別的事件實作(如上例的else陳述句),對於QWidget來說,預設的實作如下,由於QWidget預設的實作是呼叫ignore(),這讓事件可以向父元件傳播。

void QWidget::keyPressEvent(QKeyEvent *event) {
    event->ignore();
}
  • QCloseEvent則建議直接呼叫accept()與ignore(),accept()方法會繼續關閉的操作,ignore()則會取消關閉的操作:
void MainWindow::closeEvent(QCloseEvent *event) {
    if (continueToClose()) {
        event->accept();
    } else {
        event->ignore();
    }
}

QObject的event()方法通常用於分派事件,但在某些情況下,您希望在事件分派給其它事件處理者之前,先行作一些處理,則可以重新定義event()方法,例如在視窗程式中,Tab鍵按下時希望其將焦點移至下一個圖型元件,而不是直接讓目前焦點的圖形元件直接處理Tab鍵,則您可以在繼承QWidget子類別時,重新定義其event()方法,例如:

bool CustomWidget::event(QEvent *event) {
    if (event->type() == QEvent::KeyPress) {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Tab) {
            // 處理Tab鍵
            return true;
        }
    }
    return QWidget::event(event);
}
Notes:
      if (event->type() == QEvent::KeyPress)
    1. 在執行時期想要知道所取得之QEvent類型,可以使用QEvent的type()方法取得常數值,並與QEvent::Type作比對。
    2. QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
    3. 對event作強制形態轉換為QKeyEvent並宣告為keyEvent,新的keyEvent可以使用QKeyEvent的成員。

事件若順利處理完畢,則要傳回true,表示這個事件被接受並處理,QApplication可以繼續事件佇列中的下一個事件處理,若傳回false,則QApplication嘗試尋找下一個可以處理事件的方法。不用透過呼叫事件的accept()或ignore(),這也沒有意義,accept()或ignore()是用來在特定的事件處理者之間作溝通,而event()的true或false,是用來告知QApplication的notify()方法是否處理下一事件,以QWidget的event()實作來說,它是根據事件的isAccepted()來判斷該傳回true或false。

bool QWidget::event(QEvent *event) {
    switch (event->type()) {
    case QEvent::KeyPress:
         keyPressEvent((QKeyEvent *)event);
        if (!((QKeyEvent *)event)->isAccepted())
            return false;
        break;
    case QEvent::KeyRelease:
        keyReleaseEvent((QKeyEvent *)event);
        if (!((QKeyEvent *)event)->isAccepted())
            return false;
        break;
        ...
    }
    return true;
}
  • 當重新定義event()的情況是自訂CustomEvent子類型時,可以將之分派給其它函式或直接在event()中處理,自訂事件必須是CustomEvent的子類別,也可以直接實作customEvent()方法來處理自訂事件,例如:
bool CustomWidget::event(QEvent *event) {
    if (event->type() == MyCustomEventType) {
        CustomEvent *myEvent = static_cast<CustomEvent *>(event);
        // 對自訂事件的處理,或呼叫其它函式來處理事件
        return true;
    }
    return QWidget::event(event);
}

本文參考自"良葛格:Qt4學習筆記"

Qt4 學習筆記(五):Event Class & Event Handler

  • Event Class & Event Handler
    • 當執行QApplication的exec()方法之後,應用程式會進入事件迴圈來傾聽(Listen)應用程式的事件,事件來源通常是視窗系統,例如使用者的滑鼠事件或鍵盤事件,事件來源可以是Qt應用程式事件本身,例如QTimerEvent,事件來源也可以是使用者自定義的事件,透過QApplicaiton的sendEvent()或postEvent()來發送。
    • 當事件發生時,Qt為之建立事件實例,QEvent是Qt中所有事件的基礎類別,Qt所建立的事件實例為QEvent的子類別實例,並將之傳送給 QObject子類別實例的event()函式,event()這個函式本身通常不直接處理事件,而是基於所傳送的事件類型,分派給處理特定類型的事件處理者(Event Handler)。

以下是簡單的事件處理示範,繼承了QLabel並重新定義了相關的事件處理者,當滑鼠移動、按下或放開時,顯示滑鼠游標的所在位置。

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QMouseEvent>

class EventLabel : public QLabel {
protected:
    void mouseMoveEvent(QMouseEvent *event);
    void mousePressEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
};

void EventLabel::mouseMoveEvent(QMouseEvent *event) {
    QString msg;
    msg.sprintf("Move: (%d, %d)", event->x(), event->y());
    this->setText(msg);  
}

void EventLabel::mousePressEvent(QMouseEvent *event) {
    QString msg;
    msg.sprintf("Press: (%d, %d)", event->x(), event->y());
    this->setText(msg);
}

void EventLabel::mouseReleaseEvent(QMouseEvent *event) {
    QString msg;
    msg.sprintf("Release: (%d, %d)", event->x(), event->y());
    this->setText(msg);
}

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
 
    EventLabel *label = new EventLabel;
    label->setWindowTitle("MouseEvent Demo");
    label->resize(300, 200);
    label->show();
    
    return app.exec();
}

Notes:
  1. QEvent是Qt中所有事件的基礎類別,最常見的事件類型皆為其子類別,像是滑鼠事件的QMouseEvent、鍵盤事件的QKeyEvent、縮放事件的QResizeEvent等,這些子類別事件皆加入其特定的函式。
    • 滑鼠事件的x()、y():指出發生滑鼠事件時,滑鼠游標的x、y座標。
    • 鍵盤事件的key():可以取得目前所按下的按鍵常數。
  2. 以圖形元件來說,通常會繼承QWidget或其子類別,並重新定義事件處理者,也就是事件處理函式,QWidget定義了:keyPressEvent()、keyReleaseEvent()、mouseDoubleClickEvent()、mouseMoveEvent()、mousePressEvent()、mouseReleaseEvent()等事件處理函式,並接受QEvent的特定子類別實例作為引數,只要根據想要處理的事件重新定義對應的函式即可進行事件處理。
P.S.
Qt的事件跟Signal、Slot機制是不同的。Signal與Slot的機制是同步的(Synchronous),Signal是由物件發出的,使用QObject的connect()連接物件上定義的Slot來立即處理。

Qt的事件可以是非同步的(Asynchronous)的,Qt使用一個事件佇列來維護,新的事件產生時基本上會被排到佇列的尾端,前一個事件處理完成,再從佇列的前端取出下一個佇列來處理,必要的時候,Qt的事件也可以是同步的,而事件還可以使用事件過濾器 進行過濾處理。

本文參考自"良葛格:Qt4學習筆記"

Qt4 學習筆記(四):Custom Signal & Slot

  • Custom Signal & Slot
    • 除了使用Qt現有元件預先定義好的Signal與Slot之外,也可以定義自己物件的Signal與Slot,方式是繼承QObject或它的子類別(例如QWidget)。
    • 現在改以定義一個物件,當拉桿拉動時,必須通知該物件儲存拉桿的游標值,而物件儲存的游標值有變動時,LCD數字顯示也必須更新,這樣的一個物件不是圖形元件,它是個資料模型,用以儲存與圖形介面無關的資料。

定義一個Model Class如下:
Model.h
#ifndef MODEL_H
#define MODEL_H
#include <QObject>

class Model : public QObject {
     Q_OBJECT

 public:
     Model() { m_value = 0; }
     int value() const { return m_value; }

 public slots:
     void setValue(int);

 signals:
     void valueChanged(int);

 private:
     int m_value;
 };

#endif

  • 簡介Qt的Meta-Object System,它基於以下三個部份:
    • QObject類別
    • Q_OBJECT巨集
    • Meta-Object Compiler(moc)

Qt管理的物件必須繼承QObject類別,以提供Qt物件的Meta訊息,若要實作Signal與Slot機制,則必須包括Q_OBJECT巨集,moc會處理Qt的C++擴充(Meta-Object System),使用moc讀取C++標頭檔案,若發現類別定義中包括Q_OBJECT巨集,就會產生Qt meta-object相關的C++程式碼。
若使用qmake來產生Makefile,若必要時,檔案中就會包括moc的使用,程式完成建置之後,會在release或debug目錄中,找到moc_Model.cpp,即為moc所提供的C++程式碼。


public slots:
void setValue(int);

signals:
void valueChanged(int);

在Model中,自訂了Signal與Slot,slots與signals關鍵字其實是巨集,將被展開為相關的程式碼。
Slot:定義setValue(int),將接收Signal傳來的整數資料,如果不想接受資料的話,int可以省去。
Signal:定義valueChanged(int),表示將發出的Signal會帶有一個整數。

Model.cpp
#include "Model.h"

void Model::setValue(int value) {
     if (value != m_value) {
         m_value = value;
         emit valueChanged(m_value);
     }
}

Slot只是一般的函式,可以由程式的其它部份直接呼叫,也可以連接至Signal,若有呼叫setValue(),程式執行到emit時,就會發出valueChanged()的Signal。

main.cpp
#include <QApplication>
#include <QWidget>
#include <QSlider>
#include <QLCDNumber>
#include "Model.h"

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

     QWidget *parent = new QWidget;
     parent->setWindowTitle("Signal & Slot");
     parent->setMinimumSize(240, 140);
     parent->setMaximumSize(240, 140);
          
     QLCDNumber *lcd = new QLCDNumber(parent);
     lcd->setGeometry(70, 20, 100, 30);
     
     QSlider *slider = new QSlider(Qt::Horizontal, parent);
     slider->setRange(0, 99);
     slider->setValue(0);
     slider->setGeometry(70, 70, 100, 30);
     
     Model model;
     
     QObject::connect(slider, SIGNAL(valueChanged(int)),
                      &model, SLOT(setValue(int)));
     QObject::connect(&model, SIGNAL(valueChanged(int)),
                      lcd, SLOT(display(int)));
     
     parent->show();
     
     return app.exec();
}

QObject::connect(slider, SIGNAL(valueChanged(int)), &model, SLOT(setValue(int)));

QObject::connect(&model, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));

這邊使用connect()連接QSlider SIGNAL:valueChanged()及Model SLOT:setValue(),當拉動拉桿時,Model的m_value就會被設定為QSlider的游標值,Model在執行setValue()過程中會emit valueChanged() signal,由於Model SIGNAL:valueChanged()連接至QLCDNumber SLOT:display(),所以LCD顯示數字也會改變。


Signal與Slot的簽名(參數)基本上要相同,但若Signal的參數多於Slot的參數,則額外的參數會被Slot忽略。
如果要斷開Signal與Slot的連接,則使用disconnect(),例如:
QObject::disconnect(slider, SIGNAL(valueChanged(int)), &model, SLOT(setValue(int)));

本文參考自"良葛格:Qt4學習筆記"

Qt4 學習筆記(三):Signal & Slot with Parameters

  • Signal & Slot with Parameters
    • 運用拉桿改變LCD數字

在實際運用上,Signal在發出時常常是帶參數的,而相對應的Slot也可以接受參數。
以下程式將建立一個LCD數字顯示元件,以及一個拉桿元件,LCD數字將顯示目前拉桿的進度。

#include <QApplication;>
#include <QWidget>
#include <QSlider>
#include <QLCDNumber>

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

     QWidget *parent = new QWidget;
     parent->setWindowTitle("Signal & Slot");
     parent->setMinimumSize(240, 140);
     parent->setMaximumSize(240, 140);
     // equal to parent->setFixedSize(240, 140);
          
     QLCDNumber *lcd = new QLCDNumber(parent);
     lcd->setGeometry(70, 20, 100, 30);
     
     QSlider *slider = new QSlider(Qt::Horizontal, parent);
     slider->setRange(0, 99);
     slider->setValue(0);
     slider->setGeometry(70, 70, 100, 30);
     
     QObject::connect(slider, SIGNAL(valueChanged(int)), 
                      lcd, SLOT(display(int)));
     
     parent->show();
     
     return app.exec();
}

Notes:
QWidget *parent = new QWidget;
parent->setWindowTitle("Signal & Slot");
parent->setMinimumSize(240, 140);
parent->setMaximumSize(240, 140);

  1. QWidget是Qt中所有使用者圖形介面元件的父類別,可在螢幕上繪製自身,可接受滑鼠、鍵盤等介面操作,一個QWidget可以指定它的parent為哪個元件,而這也表示child可顯示的範圍將是在parent之內,parent沒有顯示的話,子元件也不會顯示。
  2. 沒有指定parent的QWidget是一個獨立視窗(window),例如先前的幾個範例,無論是QLabel或QPushButton都沒有指定parent,它們可獨立的顯示在畫面之中,只要呼叫其show()方法。
  3. QLCDNumber *lcd = new QLCDNumber(parent); QSlider *slider = new QSlider(Qt::Horizontal, parent);
  4. QLCDNumber與QSlider實例建立時,指定了這個QWidget為它的parent,所以QLCDNumber與QSlider被置入了QWidget之中成為child。
  5. QObject::connect(slider, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));
  6. 當拉動QSlider的游標,造成游標值變動時會發出valueChanged(int) Signal,參數int表示Signal帶有一個整數值,在這表示QSlider的游標值一併被發出,QLCDNumber的display(int) Slot接受Signal所帶來的整數值,可以在QLCDNumber顯示數字。

本文參考自"良葛格:Qt4學習筆記"

Qt4 學習筆記(二):Signal & Slot

  • use Signal & Slot
    • 運用按鈕關閉視窗

在Qt之中,當某個元件發生狀態改變,而另一個元件想得知其狀態改變時,作出一些相對應行為的話,可以使用Signal與Slot的機制來達到。
Signal與Slot之間,可透過QObject的靜態方法connect來連結,Signal與Slot之間的處理是同步的(Synchronized)。

#include <QApplication>
#include <QPushButton>
#include <QFont>

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

     QPushButton *btn = new QPushButton("Close");
     btn->setWindowTitle("Signal & Slot");
     btn->setFont(QFont("Courier", 18, QFont::Bold));
     btn->resize(200, 50);
     
     QObject::connect(btn, SIGNAL(clicked()), &app, SLOT(quit()));
     
     btn->show();
     
     return app.exec();
}

Notes:
QObject::connect(btn, SIGNAL(clicked()), &app, SLOT(quit()));
  1. connect()方法的第一個參數是發出Signal的物件之位址,第三個參數是對Signal有反應動作的物件之位址。
  2. SIGNAL()與SLOT()為巨集函式,是語法的一部份,所傳入的Signal或Slot為沒有參數名稱的函式簽名(function signature)。
  3. 程式中btn與app並不知道彼此的存在,而是藉由connect()連接Signal與Slot,這降低了物件之間的耦合度。

本文參考自"良葛格:Qt4學習筆記"

Qt4 學習筆記(一):First Qt Application!

  • First Qt Application!
HelloWorld.cpp
#include <QApplication>
#include <QLabel>

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

     QLabel *label = new QLabel("Hello~World!");
     label->setWindowTitle("First Qt Application!");
     label->resize(150, 50);
     label->show();

     return app.exec();
}

Notes:
  1. 每個Qt視窗程式,都必須有且只能有一個QApplication物件,它管理了整個應用程式所需的資源〈負責程式的初始、結束及處理事件(event)的迴圈等,並提供基本的視窗外觀〉。
  2. QApplication :: exec(),這將程式的控制權交給了QApplication,exec()方法會提供一個事件處理迴圈,視窗顯示之後會不斷傾聽(listen)事件,像是鍵盤、滑鼠等動作所引發的事件。
  3. Qt的元件預設是不可視的,所以要使用show()方法將之顯示出來。
  4. Qt對於顯示字串可支援HTML格式。