Qt QApplication 類簡介--Qt 類簡介專題(四)

pamxy發表於2013-03-18

轉自:http://blog.csdn.net/yyzsyx/article/details/6039882


一、詳細描述

QApplication類管理圖形使用者介面應用程式的控制流和主要設定。 可以說QApplication 是Qt的整個後臺管理的命脈

它包含主事件迴圈,在其中來自視窗系統和其它資源的所有事件被處理和排程。它也處理應用程式的初始化和結束,並且提供對話管理。它也處理絕大多數系統範圍和應用程式範圍的設定。

對於任何一個使用Qt的圖形使用者介面應用程式,都正好存在一個QApplication物件,而不論這個應用程式在同一時間內是不是有0、1、2或更多個視窗。

QApplication物件是可以通過全域性變數qApp訪問。它的負責的主要範圍有:

* 它使用使用者的桌面設定,例如palette()、font()和doubleClickInterval()來初始化應用程式。如果使用者改變全域性桌面,例如通過一些控制皮膚,它會對這些屬性保持跟蹤。

 

* 它執行事件處理,也就是說它從低下的視窗系統接收事件並且把它們分派給相關的視窗部件。通過使用sendEvent()和postEvent(),你可以傳送你自己的事件到視窗部件。

* 它分析命令列引數並且根據它們設定內部狀態。關於這點的詳細情況請參考下面的建構函式文件。

* 它定義了由QStyle物件封裝的應用程式的觀感。在執行狀態下,可以通過setStyle()來改變。

* 它指定了應用程式如何分配顏色。詳細情況請參考setColorSpec()。

* 它定義了預設文字編碼(請參考setDefaultCodec())並且提供了通過translate()使用者可見的本地化字串。

* 它提供了一些像desktop()和clipboard()這樣的魔術般的物件。

* 它知道應用程式的視窗。你可以使用widgetAt()來詢問在一個確定點上存在哪個視窗部件,得到一個topLevelWidgets()(頂級視窗部件)的列表和通過closeAllWindows()來關閉所有視窗,等等。

* 它管理應用程式的滑鼠游標處理,請參考setOverrideCursor()和setGlobalMouseTracking()。

* 在X視窗系統上,它提供重新整理和同步通訊流的函式,請參考flushX()和syncX()。

* 它提供複雜的對話管理支援。這使得當使用者登出時,它可以讓應用程式很好地結束,如果無法終止,撤消關閉程式並且甚至為未來的對話保留整個應用程式的狀態。詳細情況請參考isSessionRestored()、sessionId()、commitData()和saveState()。

應用程式排演例項包含了一個QApplication通常用法的典型完整的main()。

因為QApplication物件做了如此多的初始化,它必須在所有與使用者介面相關的其它類被建立之前被建立

因為它也處理命令列引數,在應用程式中對argv解釋和修改之前建立它通常是一個好主意。(注意,也對於X11,setMainWidget()可以根據-geometry選項來改變主視窗部件。為了保持這個功能,你必須在setMainWidget()和它的任何過載之前設定你的預設。)

二、QApplication兩類構造的講解

QApplication::QApplication ( int & argc, char ** argv )

初始化視窗系統並且使用在argv中的argc個命令列引數構造一個應用程式物件
全域性指標qApp指向這個應用程式物件。應該只有一個應用程式物件被建立。
這個應用程式物件必須在任何繪製裝置(包括視窗部件、畫素對映、點陣圖等等)之前被構造。
注意argc和argv也可以被改變。Qt會移除它能夠識別的命令列引數。原來的argc和argv稍後可以通過qApp->argc()和qApp->argv()來訪問。argv()的文件中包含如何處理命令列引數的詳細描述。
Qt除錯選項(如果Qt被使用被定義的QT_NO_DEBUG標記進行編譯,這些選項就是不可用的):

* -nograb,告訴Qt永遠不要捕獲滑鼠或者鍵盤。
* -dograb (只有在X11下),在偵錯程式下執行可能導致和-nograb衝突,使用-dograb來覆蓋。
* -sync (只有在X11下),為了除錯切換為同步模式。

更詳細的解釋請參考除錯技術。

所有的Qt程式自動支援下面這些命令列選項:

* -style= style,設定應用程式圖形使用者介面風格。可能的值有motif、windows和platinum。如果你使用其它風格編譯Qt或者有作為外掛編譯了其它風格,那麼它們都可以被用作-style命令列選項。
* -style style,這個和上面的一樣。
* -session= session,從以前的對話中重新載入應用程式。
* -session session,這個和上面的一樣。

X11版本的Qt也支援傳統的X11命令列選項:

* -display display,設定X顯示(預設為$DISPLAY)。
* -geometry geometry,設定主視窗部件的客戶端位置和大小。
* -fn或者-font font,定義應用程式的字型。這個字型必須使用X邏輯字型描述來北指定。
* -bg或者-background color,設定預設背景色和應用程式調色盤(亮的和暗的陰影將被計算出來)。
* -fg或者-foreground color,設定預設前景色。
* -btn或者-button color,設定預設按鈕顏色。
* -name name,設定應用程式名稱。
* -title title,設定應用程式標題。
* -visual TrueColor,強制應用程式在8位顯示上使用真彩影象。
* -ncols count,如果應用程式使用QApplication::ManyColor顏色規格,在8位顯示中限制顏色立方體重分配的顏色。如果count為216,那麼一個6x6x6的顏色立方體將被使用(也就是說6級紅色,6級綠色和6級藍色),對於其它值,與2x3x1立方體成比例的立方體將被使用。
* -cmap,導致應用程式在8位顯示上安裝一個私有的顏色對映。

QApplication::QApplication ( int & argc, char ** argv, bool GUIenabled )

構造一個使用argvargc個命令列引數的應用程式物件。如果GUIenabled為真,圖形使用者介面應用程式被構造,否則非圖形使用者介面(命令列)應用程式被建立。

對於沒有圖形使用者介面的程式,設定GUIenabled為假可以在沒有視窗系統的情況下執行。

在X11下,如果GUIenabled為真,視窗系統被初始化。如果GUIenabled為假,應用程式不連線X伺服器。在Windows和Macintosh,現在視窗系統總是被初始化,而不管GUIenabled的值。在Qt未來的版本這也許會改變。

對於執行緒配置(也就是說當Qt已經被作為執行緒庫建立),應用程式全域性互斥量在建構函式中將被鎖定並且當使用exec()進入事件迴圈中時解鎖。如果你不呼叫exec(),你必須明顯地對這個互斥量解鎖,否則你將會在應用程式退出時得到警告。

下面這個例子顯示如何建立在可能情況下使用圖形介面的應用程式。

  int main( int argcchar **argv )
  {
#ifdef Q_WS_X11
    bool useGUI = getenv( "DISPLAY" ) != 0;
#else
    bool useGUI = TRUE;
#endif
    QApplication app(argcargv, useGUI);

    if ( useGUI ) {
       //開始圖形使用者介面版本
       ...
    } else {
       //開始非圖形使用者介面版本
       ...
    }
    return app.exec();
  }

三、視窗管理

視窗管理方面,對於獨立的1個程式,qApplication 提供視窗管理的成員函式有(多程式的視窗管理,這裡暫不介紹):

QDesktopWidget * QApplication::desktop () [靜態]

返回桌面視窗部件(也呼叫根視窗)。

 

桌面視窗部件對於獲得螢幕大小很有用。在桌面上繪製也是可能的。我們建議不要假設可以在桌面上繪製,因為它不能在所有的作業系統上工作。

    QDesktopWidget *= QApplication::desktop();
    int w = d->width();     // 返回桌面寬度
    int h = d->height();    // 返回桌面高度

QWidgetList * QApplication::allWidgets () [靜態]

返回應用程式中所有視窗部件的列表。

 

這個列表必須使用new來被建立並且必須被呼叫者刪除。

如果沒有視窗部件,這個列表為空(QPtrList::isEmpty())。

注意一些視窗部件也許被隱藏。

更新所有視窗部件的例項:

    QWidgetList  *list = QApplication::allWidgets();
    QWidgetListIt it( *list );         // 遍歷視窗部件
    QWidget * w;
    while ( (w=it.current()) != 0 ) {  // 對於每一個視窗部件……
        ++it;
        w->update();
    }
    delete list;                      // 刪除這個列表,不是這個視窗部件

 

QWidgetList * QApplication::topLevelWidgets () [靜態]

返回應用程式中頂級視窗部件的列表。

 

這個列表是使用new建立的並且必須由呼叫者刪除。

如果沒有頂級視窗部件,這個列表是空的(QPtrList::isEmpty())。

注意一些頂級視窗部件也許被隱藏了,例如如果當前沒有工具提示被顯示的工具提示。

例項:

    // 顯示所有隱藏的頂級視窗部件。
    QWidgetList  *list = QApplication::topLevelWidgets();
    QWidgetListIt it( *list );  // 遍歷視窗部件
    QWidget * w;
    while ( (w=it.current()) != 0 ) {   // 對每一個頂級視窗部件
        ++it;
        if ( !w->isVisible() )
            w->show();
    }
    delete list;                // 刪除這個列表,而不是視窗部件

QWidget * QApplication::topLevelAt ( int x, int y ) [static]

返回最上層x,y點的widget, 可以用來定位最上層視窗

QWidget * QApplication::widgetAt ( int x, int y ) [static]

返回當前層x,y點的widget, 可以用來定位當前視窗,和topLevelAt不同的是 widgetAt是以global screen position 來判斷的,而topLevelAt是以顯示區域為座標區域的。

void QApplication::closeAllWindows () [static slot]

關閉所有頂級視窗。

 

     exitAct = new QAction(tr("E&xit")this);
     exitAct->setShortcuts(QKeySequence::Quit);
     exitAct->setStatusTip(tr("Exit the application"));
     connect(exitAct, SIGNAL(triggered())qApp, SLOT(closeAllWindows()));

四、關於事件迴圈

qApplication 的事件迴圈,就是MainLoop的事件迴圈,當然它的原理和QEventLoop的原理是一樣的。

void QCoreApplication::processEvents ( QEventLoop::ProcessEventsFlags flags =QEventLoop::AllEvents ) [static]

Processes all pending events for the calling thread according to the specified flags until there are no more events to process.
You can call this function occasionally when your program is busy performing a long operation (e.g. copying a file).
In event you are running a local loop which calls this function continuously, without an event loop, the DeferredDelete events will not be processed. This can affect the behaviour of widgets, e.g. QToolTip, that rely on DeferredDelete events to function properly. An alternative would be to call sendPostedEvents() from within that local loop.
Calling this function processes events only for the calling thread.
大體意思就是預先呼叫處於佇列狀態的事件,直到全部處理完畢。這個函式大多用於系統繁忙時,導致一些事件被延後了(如繪製事件等),用此函式可保證全部事件處理完畢後在繼續執行。常見於show(),update()之後呼叫。
Note: 這個函式執行緒安全

五、事件的傳送

關於事件的傳送有兩種方式:

1、bool QApplication::sendEvent ( QObject * receiver, QEvent * event ) [靜態]

使用notify()函式直接傳送事件event給接受者receiver。返回由事件處理器返回的值。

 

這個事件在它被髮送時,不能被刪除。通常的訪問方式是在棧中建立這個事件,例如:

QMouseEvent me( QEvent::MouseButtonPress, pos, 0, 0 );
QApplication::sendEvent( mainWindow, &me );

如果你在堆中建立這個事件,你就必須刪除它。

void QApplication::postEvent ( QObject * receiver, QEvent * event ) [靜態]

把事件event新增為物件receiver的接收物件,把它新增到事件佇列中並且立即返回。

 

這個時間必須在堆中被分配,因為遞送事件佇列將會得到事件的所有權並且一旦它被遞送就刪除它。

當控制返回主事件迴圈,儲存在佇列中的所有事件將被使用notify()函式傳送。

基本上Qt大部分的地方都是用到sendEvent, 而少部分地方會用到postEvent, 研究執行緒安全的童鞋可以多看看這方面的資料

相關文章