前面我們一再強調,Qt 使用自己的方式繪制組件。然而我們也看到,在不同的平台上,Qt 的組件表現也不相同。這和 Swing 有些類似:Swing 使用 look and feel 表現組件的外觀,Qt 也是類似的。用來繪制組件外觀的類就是 QStyle。 需要說明一點,組件的 style 是一個非常復雜的內容,僅在這裡不可能全部講解清楚。如果需要,還是要自己仔細閱讀相關文檔。另外,這部分牽扯的類很多,函數也很復雜,步步為營才是最好的對待方法。除非非常必要,還是建議不要輕易去碰 style 這部分。 好了,說明也說明過了,嚇唬也嚇唬過了,下面進入正題。 自定義 style,顧名思義,也就是自己實現外觀。這裡通常有兩種實現方式:第一,重寫 widget 的 paintEvent() 函數;第二,使用 QStyle 類。兩種方式的側重點不同:重寫組件的 paintEvent() 函數,可以簡單地實現某一類組件的樣式,而繼承 QStyle 類,則可以實現對全部組件一致性處理,例如,將程序中所有的 text 變成紅色等。 首先我們來看看重寫 paintEvent() 函數。paintEvent() 是 QWidget 的一個函數,用於實現自身的繪制。一個組件顯示到屏幕上,就是通過調用 paintEvent() 函數。看看一個組件有多復雜,全部要使用 QPainter 提供的畫點、畫線的函數實現,就知道這裡的工作量了。當然也有偷懶的辦法,就是重寫 paintEvent() 的時候使用一張圖片代替。我們這裡就不討論這種思路了,完全從代碼開始。 我們以 QPushButton 為例。這裡,我們創建一個 button,這個 button 在點擊時可以凹下顯示。為了重寫 paintEvent() 函數,我們必須繼承 QPushButton 類。頭文件很簡單,暫且略去,下面只看 paintEvent() 這個函數:
盡管前面說過,我們需要重頭繪制整個組件,但實際上,Qt 為我們提供了一系列方便的函數,用於繪制出各個組件。這種在將組建組合的時候非常有用。例如,一個 combo box 實際上是一個 button 加上一個向下的三角形構成。那麼,我不需要將整個 combo box 用像素畫出來,而是借用 Qt 已有的組建繪制,畫出一個 button 和一個三角形就可以了。所以,這裡我們也使用類似的思路,讓 Qt 繪制出組件,我們要做的就是修改參數,讓它按照我們的參數繪制。 如果調用 Qt 的組件繪制函數呢?這個繪制函數是 QStyle 類的成員。QWidget 提供了 style() 函數,返回當前的 QStyle 對象。那麼,我們就可以通過這個對象繪制。注意上面代碼中最後一行,我們從這裡看起。下面給出這個函數的簽名:
- void MyPushButton::paintEvent(QPaintEvent *)
- {
- QStyleOptionButton option;
- option.initFrom(this);
- qDebug() << option.state;
- option.state |= isDown() ? QStyle::State_Sunken : QStyle::State_Raised;
- qDebug() << option.state;
- if (isDefault())
- option.features |= QStyleOptionButton::DefaultButton;
- option.text = text();
- option.icon = icon();
- QPainter painter(this);
- style()->drawControl(QStyle::CE_PushButton, &option, &painter, this);
- }
盡管這是一個純虛函數,但是類似於 Java 的 interface,我們可以直接使用 style() 返回的對象調用。這是一個很典型的 style 式的函數調用。翻看一下 QStyle 的定義,QStyle 類提供了很多以 draw 打頭的函數,用於繪制整個系統組件的繪制。這類 draw 函數一般會有四個參數:
- virtual void QStyle::drawControl ( ControlElement element, const QStyleOption * option, QPainter * painter, const QWidget * widget = 0 ) const = 0;
MyProxyStyle 覆蓋了 drawControl() 函數,然後判斷,如果是 button label 的話,繪制文本 “fixed”。可想而知,我們的 QPushButton::setText() 函數已經沒有作用了,因為我們在繪制時沒有使用這個屬性,也就不會顯示出來了。不管你設不設置,所有 button 的 text 都會是 fixed。如果要使用這個 style ,需要在運行前設置,例如:
- class MyProxyStyle : public QProxyStyle
- {
- public:
- void drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const;
- };
- void MyProxyStyle::drawControl(ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const
- {
- if(element == QStyle::CE_PushButtonLabel) {
- painter->drawText(option->rect, "fixed");
- } else {
- QProxyStyle::drawControl(element, option, painter, widget);
- }
- }
這樣,我們就可以用我們自己的 style 顯示組件了。 就像前面所說,自定義 style 是一個相當復雜的話題,我們不可能在這裡完全說明。不過,也正因為 Qt 提供了這種機制,也能夠讓我們可以比較輕松地實現自定義 style。
- int main(int argc, char **argv)
- {
- QApplication app(argc, argv);
- app.setStyle(new MyProxyStyle);
- MainWindow w;
- w.show();
- return app.exec();
- }
本文出自 “豆子空間” 博客,請務必保留此出處http://devbean.blog.51cto.com/448512/471941