本系列所有文章可以在這里查看[http://blog.csdn.net/cloud_castle/article/category/2123873](http://blog.csdn.net/cloud_castle/article/category/2123873)
接上文[](http://blog.csdn.net/cloud_castle/article/details/43672509)[Qt5官方demo解析集36——Wiggly Example](http://blog.csdn.net/cloud_castle/article/details/44018679)
在 Qt 中設計GUI界面,經常需要考慮不同尺寸,不同分辨率下面的情況,因此我們經常需要準備幾套圖片素材來應付不同的場景。不過好在,我們還可以使用矢量繪圖和矢量圖形。
今天這個例子基于?QPainterPath?繪制了文本字符的矢量路徑,并可以在一個"濾鏡"范圍內進行變形處理,效果萌萌噠~下面就來看看吧:

這個例子看起來代碼量較多,我們關心的核心處理也就是幾行,經過抽絲剝繭,去掉布局按鈕定時器之類的邏輯,其實這也就是個小demo啦。
還是先從main.cpp來看:
~~~
#include "pathdeform.h"
#include <QApplication>
int main(int argc, char **argv)
{
Q_INIT_RESOURCE(deform);
QApplication app(argc, argv);
bool smallScreen = QApplication::arguments().contains("-small-screen");
PathDeformWidget deformWidget(0, smallScreen);
QStyle *arthurStyle = new ArthurStyle();
deformWidget.setStyle(arthurStyle);
QList<QWidget *> widgets = deformWidget.findChildren<QWidget *>();
foreach (QWidget *w, widgets)
w->setStyle(arthurStyle);
if (smallScreen)
deformWidget.showFullScreen();
else
deformWidget.show();
#ifdef QT_KEYPAD_NAVIGATION
QApplication::setNavigationMode(Qt::NavigationModeCursorAuto);
#endif
return app.exec();
}
~~~
在上一個例子中我們提到了這個?smallScreen,這里就不多提啦,注意將這個參數傳遞給我們的窗口,以做不同的處理。
接著它將窗口風格設置為 “ArthurStyle”,這個類是在?shared?子工程中定義的,繼承自 QCustomStyle,之所以放在shared?中是因為有好幾個 demo 是使用它的。如果大家一直在做 Qt 開發,不妨留心建立下自己的“Qt庫”,把可擴展性和通用性考慮進去之后,就可以在下一個項目中復用一些東西啦。
好,不扯遠了,如果屏蔽掉這幾行 setStyle 語句后,可以看到這個 control 面板幾乎不忍直視。。

不看?shared?子工程,我們就剩 pathdeform.h 和 pathdeform.cpp 倆文件了,不過里面定義了三個類:
PathDeformWidget、PathDeformControls、PathDeformRenderer,分別是主窗口,控件窗體和渲染窗體
可以看到,控件窗體?PathDeformControls 針對 smallScreen 參數設計了兩套布局
layoutForDesktop()
layoutForSmallScreen()
以應對不同的場景。
接下來,繪制“濾鏡”并保存在 QImage 或 QPixmap 中,代碼就不帖啦,
然后使用 QPainterPath 的 addText 將用戶輸入的字符添加到繪制路徑中:
~~~
bool do_quick = true;
for (int i=0; i<text.size(); ++i) {
if (text.at(i).unicode() >= 0x4ff && text.at(i).unicode() <= 0x1e00) {
do_quick = false;
break;
}
}
if (do_quick) {
for (int i=0; i<text.size(); ++i) {
QPainterPath path;
path.addText(advance, f, text.mid(i, 1));
m_pathBounds |= path.boundingRect();
m_paths << path;
advance += QPointF(fm.width(text.mid(i, 1)), 0);
}
} else {
QPainterPath path;
path.addText(advance, f, text);
m_pathBounds |= path.boundingRect();
m_paths << path;
}
~~~
有意思的是,針對字符的不同編碼,這里使用了兩種不同的添加方式:
Unicode編碼大于 0X4FF 且 小于 0X1E00 的字符,直接將整個文本添加到路徑中去;
否則,使用循環語句添加該字符串中每個字符。
根據 do_quick 命名似乎是第二種方式要更快速一些,不過暫時沒有找到相關的證明-.-
函數lensDeform()用來返回一個經過變形的QPainterPath,并由 painter 繪制出來:
~~~
QPainterPath PathDeformRenderer::lensDeform(const QPainterPath &source, const QPointF &offset)
{
QPainterPath path;
path.addPath(source);
qreal flip = m_intensity / qreal(100);
for (int i=0; i<path.elementCount(); ++i) {
const QPainterPath::Element &e = path.elementAt(i);
qreal x = e.x + offset.x();
qreal y = e.y + offset.y();
qreal dx = x - m_pos.x();
qreal dy = y - m_pos.y();
qreal len = m_radius - qSqrt(dx * dx + dy * dy);
if (len > 0) {
path.setElementPositionAt(i,
x + flip * dx * len / m_radius,
y + flip * dy * len / m_radius);
} else {
path.setElementPositionAt(i, x, y);
}
}
return path;
}
~~~
這里通過 len 判斷 QPainterPath 的元素是否在 “濾鏡”內,len值越大,離“濾鏡”中心點越近。
一個在圓內的點各參數可以表示為下面這張圖:

由
~~~
x + flip * dx * len / m_radius,
y + flip * dy * len / m_radius
~~~
可知當 flip 為正數時,越靠近濾鏡中心的部分 x,y增量越大,表現為中心部分向外擴張得更厲害,并且保證坐標增量不至于超出濾鏡范圍,從而形成凸透鏡的效果。
反之,flip為負數時,越靠近中心部分的x,y減去的值更大,從而使圖形向中心收縮,形成凹透鏡的效果。
主要就是這些啦~
- 前言
- 1——Fortune Server/Client
- 2——Multicast Sender/Receiverz
- 3——Broadcast Sender/Receiver
- 4——Blocking Fortune Client
- 5——Threaded Fortune Server
- 5(總結)——Fortune例程的各個實現區別
- 6——Loopback Example
- 7——Analog Clock Example
- 8——Shaped Clock Example
- 9——Analog Clock Window Example
- 10——Qt Quick Particles Examples - Emitters
- 11——Qt Quick Particles Examples - Affectors
- 12——Qt Quick Particles Examples - CustomParticles
- 13——Qt Quick Particles Examples - Image Particles
- 14——Qt Quick Particles Examples - System
- 15——Chapter 1: Creating a New Type
- 16——Chapter 2: Connecting to C++ Methods and Signals
- 17——Chapter 3: Adding Property Bindings
- 18——Chapter 4: Using Custom Property Types
- 19——Chapter 5: Using List Property Types
- 20——Chapter 6: Writing an Extension Plugin
- 21——Extending QML - Adding Types Example
- 22——Extending QML - Object and List Property Types Example
- 23——Extending QML - Inheritance and Coercion Example
- 24——Extending QML - Default Property Example
- 25——Extending QML - Methods Example
- 26——Extending QML - Grouped Properties Example
- 27——Extending QML - Attached Properties Example
- 28——Extending QML - Signal Support Example
- 29——Extending QML - Property Value Source Example
- 30——Extending QML - Binding Example
- 31——StocQt
- 32——Qt Quick Examples - Threading
- 33——Qt Quick Examples - Window and Screen
- 34——Concentric Circles Example
- 35——Music Player
- 36——Wiggly Example
- 37——Vector Deformation