#(27):漸變
漸變是繪圖中很常見的一種功能,簡單來說就是可以把幾種顏色混合在一起,讓它們能夠自然地過渡,而不是一下子變成另一種顏色。漸變的算法比較復雜,寫得不好的話效率會很低,好在很多繪圖系統都內置了漸變的功能,Qt 也不例外。漸變一般是用在填充里面的,所以,設置漸變是在`QBrush`里面。
Qt 提供了三種漸變:線性漸變(`QLinearGradient`)、輻射漸變(`QRadialGradient`)和角度漸變(`QConicalGradient`)。我們可以在 Qt API 手冊中看到這幾種漸變的區別:
線性漸變:
[](http://files.devbean.net/images/2012/11/QLinearGradient.png)
輻射漸變:
[](http://files.devbean.net/images/2012/11/QRadialGradient.png)
角度漸變:
[](http://files.devbean.net/images/2012/11/QConicalGradient.png)
具體細節可以參考文檔。下面我們通過一個示例看看如何使用漸變進行填充:
~~~
void paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
QLinearGradient linearGradient(60, 50, 200, 200);
linearGradient.setColorAt(0.2, Qt::white);
linearGradient.setColorAt(0.6, Qt::green);
linearGradient.setColorAt(1.0, Qt::black);
painter.setBrush(QBrush(linearGradient));
painter.drawEllipse(50, 50, 200, 150);
}
~~~
像以前一樣,我們也只給出了`paintEvent()`的代碼。這段代碼看起來也相當清晰:首先我們打開了反走樣,然后創建一個`QLinearGradient`對象實例。`QLinearGradient`也就是線性漸變,其構造函數有四個參數,分別是 x1,y1,x2,y2,即漸變的起始點和終止點。在這里,我們從 (60, 50) 點開始漸變,到 (200, 200) 點止。關于坐標的具體細節,我們會在后面的章節中詳細介紹。漸變的顏色是在`setColorAt()`函數中指定的。下面是這個函數的簽名:
~~~
void QGradient::setColorAt ( qreal position, const QColor & color )
~~~
這個函數的作用是,把 position 位置的顏色設置成 color。其中,position 是一個 [0, 1] 閉區間的數字。也就是說,position 是相對于我們建立漸變對象時做的那個起始點和終止點區間的一個比例。以這個線性漸變為例,在從 (60, 50) 到 (200, 200) 的線段上,在 0.2,也就五分之一處設置成白色,在 0.6 也就是五分之三處設置成綠色,在 1.0 也就是終點處設置成黑色。創建`QBrush`對象時,把這個漸變對象傳遞進去,然后就可以運行了:
[](http://files.devbean.net/images/2012/11/gradient-demo.png)
下面我們開始一個更復雜,也更實用一些的例子:繪制一個色輪(color wheel)。所謂色輪,其實就是一個帶有顏色的圓盤(或許你沒聽說過這個名字,但是你肯定見過這個東西),下面是色輪的運行結果:
[](http://files.devbean.net/images/2012/11/color-wheel.png)
我們來看看它的代碼:
~~~
void ColorWheel::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const int r = 150;
QConicalGradient conicalGradient(0, 0, 0);
conicalGradient.setColorAt(0.0, Qt::red);
conicalGradient.setColorAt(60.0/360.0, Qt::yellow);
conicalGradient.setColorAt(120.0/360.0, Qt::green);
conicalGradient.setColorAt(180.0/360.0, Qt::cyan);
conicalGradient.setColorAt(240.0/360.0, Qt::blue);
conicalGradient.setColorAt(300.0/360.0, Qt::magenta);
conicalGradient.setColorAt(1.0, Qt::red);
painter.translate(r, r);
QBrush brush(conicalGradient);
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
painter.drawEllipse(QPoint(0, 0), r, r);
}
~~~
首先還是新建 QPainter 對象,開啟反走樣。然后我們將圓盤半徑定義為 150。下面創建一個角度漸變實例,其構造函數同樣接受三個參數:
~~~
QConicalGradient::QConicalGradient ( qreal cx, qreal cy, qreal angle )
~~~
前兩個參數 cx 和 cy 組成角度漸變的中心點,第三個參數是漸變的起始角度。在我們的例子中,我們將漸變中心點設置為 (0, 0),起始角度為 0。類似線性漸變,角度漸變的`setColorAt()`函數同樣接受兩個參數,第一個是角度比例,第二個是顏色。例如,
~~~
conicalGradient.setColorAt(0.0, Qt::red);
~~~
將 0 度角設置為紅色;
~~~
conicalGradient.setColorAt(60.0/360.0, Qt::yellow);
~~~
將 60 度角設置為黃色。由于一個圓周是 360 度,所以 60.0/360.0 即是這個角度的比例。其余代碼以此類推。最后一句,我們將 1.0 處設置為紅色,也就是重新回到起始處。至于顏色的分布,這是由顏色空間定義的,有興趣的朋友可以查閱有關顏色模型的理論。
~~~
painter.translate(r, r);
~~~
這是我們唯一不熟悉的函數。`QPainter::translate(x, y)`函數意思是,將坐標系的原點設置到 (x, y) 點。原本坐標系原點位于左上角,我們使用`translate(r, r)`,將坐標原點設置為 (r, r)。這么一來,左上角的點的坐標就應該是 (-r, -r)。
最后,我們使用`drawEllipse()`函數繪制圓盤。注意,由于我們已經把坐標原點設置為 (r, r),因此,在繪制時,圓心應該是新的坐標 (0, 0),而不是原來的 (r, r)。
PS:為了理解`translate()`函數的作用,可以思考下,如果去掉`translate()`函數的調用,我們的程序應該如何修改。答案是:
~~~
void ColorWheel::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const int r = 150;
QConicalGradient conicalGradient(r, r, 0);
conicalGradient.setColorAt(0.0, Qt::red);
conicalGradient.setColorAt(60.0/360.0, Qt::yellow);
conicalGradient.setColorAt(120.0/360.0, Qt::green);
conicalGradient.setColorAt(180.0/360.0, Qt::cyan);
conicalGradient.setColorAt(240.0/360.0, Qt::blue);
conicalGradient.setColorAt(300.0/360.0, Qt::magenta);
conicalGradient.setColorAt(1.0, Qt::red);
QBrush brush(conicalGradient);
painter.setPen(Qt::NoPen);
painter.setBrush(brush);
painter.drawEllipse(QPoint(r, r), r, r);
}
~~~
不僅我們需要修改最后的繪制語句,還需要注意修改`QConicalGradient`定義時傳入的中心點的坐標。
- (1)序
- (2)Qt 簡介
- (3)Hello, world!
- (4)信號槽
- (5)自定義信號槽
- (6)Qt 模塊簡介
- (7)MainWindow 簡介
- (8)添加動作
- (9)資源文件
- (10)對象模型
- (11)布局管理器
- (12)菜單欄、工具欄和狀態欄
- (13)對話框簡介
- (14)對話框數據傳遞
- (15)標準對話框 QMessageBox
- (16)深入 Qt5 信號槽新語法
- (17)文件對話框
- (18)事件
- (19)事件的接受與忽略
- (21)事件過濾器
- (22)事件總結
- (23)自定義事件
- (24)Qt 繪制系統簡介
- (25)畫刷和畫筆
- (26)反走樣
- (27)漸變
- (28)坐標系統
- (29)繪制設備
- (30)Graphics View Framework
- (31)貪吃蛇游戲(1)
- (32)貪吃蛇游戲(2)
- (33)貪吃蛇游戲(3)
- (34)貪吃蛇游戲(4)
- (35)文件
- (36)二進制文件讀寫
- (37)文本文件讀寫
- (38)存儲容器
- (39)遍歷容器
- (40)隱式數據共享
- (41)model/view 架構
- (42)QListWidget、QTreeWidget 和 QTableWidget
- (43)QStringListModel
- (44)QFileSystemModel
- (45)模型
- (46)視圖和委托
- (47)視圖選擇
- (48)QSortFilterProxyModel
- (49)自定義只讀模型
- (50)自定義可編輯模型
- (51)布爾表達式樹模型
- (52)使用拖放
- (53)自定義拖放數據
- (54)剪貼板
- (55)數據庫操作
- (56)使用模型操作數據庫
- (57)可視化顯示數據庫數據
- (58)編輯數據庫外鍵
- (59)使用流處理 XML
- (60)使用 DOM 處理 XML
- (61)使用 SAX 處理 XML
- (62)保存 XML
- (63)使用 QJson 處理 JSON
- (64)使用 QJsonDocument 處理 JSON
- (65)訪問網絡(1)
- (66)訪問網絡(2)
- (67)訪問網絡(3)
- (68)訪問網絡(4)
- (69)進程
- (70)進程間通信
- (71)線程簡介
- (72)線程和事件循環
- (73)Qt 線程相關類
- (74)線程和 QObject
- (75)線程總結
- (76)QML 和 QtQuick 2
- (77)QML 語法
- (78)QML 基本元素
- (79)QML 組件
- (80)定位器
- (81)元素布局
- (82)輸入元素
- (83)Qt Quick Controls
- (84)Repeater
- (85)動態視圖
- (86)視圖代理
- (87)模型-視圖高級技術
- (88)Canvas
- (89)Canvas(續)