Qt5官方demo解析集37——Vector Deformation

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873

接上文Qt5官方demo解析集36——Wiggly Example

在 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减去的值更大,从而使图形向中心收缩,形成凹透镜的效果。

主要就是这些啦~

时间: 2024-11-01 17:35:49

Qt5官方demo解析集37——Vector Deformation的相关文章

Qt5官方demo解析集13——Qt Quick Particles Examples - Image Particles

本系列全部文章能够在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文 Qt5官方demo解析集12--Qt Quick Particles Examples - CustomParticles 先唠下嗑,在上文CustomParticles中我们接触了强大的ShaderEffect,笔者对其产生了极大的兴趣,于是去找了找有没有很多其它相关的例程,于是就发现了一个QML Video Shader Effects E

Qt5官方demo解析集12——Qt Quick Particles Examples - CustomParticles

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集11--Qt Quick Particles Examples - Affectors 使用Emitter和Affectors强大的功能,我们已经可以构造出丰富多彩的粒子特效,但当这些功能还不能满足我们的需要时,我们可以转而采用CustomParticle取代ImageParticle,在CustomParticle中我们

Qt5官方demo解析集33——Qt Quick Examples - Window and Screen

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集32--Qt Quick Examples - Threading 来到我们Qt Quick Examples的第二个例子了,之所以挑这个demo,主要是我们使用Qt开发界面(尤其是跨平台界面)时,本地屏幕信息与窗口调用是不可避免的课题. 这个例子便向我们展示了在QML中获取本地屏幕信息的方法. 项目树如图,其中share

Qt5官方demo解析集31——StocQt

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集30--Extending QML - Binding Example 最近在做QML制表,因此想找一些相关曲线绘制的demo看看,结果发现了这个例子,觉得挺不错,它相比于我们之前的Extend和Particle系列显得更大一些,涉及到的面也更广一些.因此想拿过来给大家分享~ 这个例子是基于QML的股票走势图绘制,数据来源

Qt5官方demo解析集15——Chapter 1: Creating a New Type

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 前面我们说到了QML的粒子系统,它可以创造丰富多彩的粒子特效.但是更多的情况下,我们的QML界面是配合C++进行工作的:QML负责界面渲染,C++负责逻辑事务.甚至有时,我们还会利用QML来绘制C++代码中定义的可视化组件,或者使用C++代码来访问QML中对象的属性等.从这篇博文开始,我们介绍了Qt官方Demo中的"Chapter"系列,它介

Qt5官方demo解析集17——Chapter 3: Adding Property Bindings

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集16--Chapter 2: Connecting to C++ Methods and Signals 在C++中我们通常将用户的交互与处理函数用信号槽绑定起来,比如窗口尺寸的变化,颜色的变化等,但在QML中,我们更多的使用属性绑定来完成这些功能.我们可以将这个属性值绑定到另一个对象或者本身的属性值上,这样当后者改变时,

Qt5官方demo解析集16——Chapter 2: Connecting to C++ Methods and Signals

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集15--Chapter 1: Creating a New Type 在上篇博文我们了解到如何在C++代码中将一个C++类注册为一个QML类型,并供QML文件使用.接下来这个Demo中进一步向这个PieChart中添加信号和方法供QML使用. 在项目上没有什么改变,我们直接来看代码PieChart.h: #ifndef P

Qt5官方demo解析集18——Chapter 4: Using Custom Property Types

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集17--Chapter 3: Adding Property Bindings 在前面的"饼状图"Demo中,我们为这个自定义类型定义了"name"和"color"属性,他们都是基于Qt内置类型"QString"和"QColor",这

Qt5官方demo解析集19——Chapter 5: Using List Property Types

本系列所有文章可以在这里查看http://blog.csdn.net/cloud_castle/article/category/2123873 接上文Qt5官方demo解析集18--Chapter 4: Using Custom Property Types 上个例子向我们展示了如何为QML调用的C++类型添加自定义类型的属性,在这个例子中我们更进一步,将这个类型更换为一个PieSlice的列表,以此得到更丰富的处理能力. 项目文件与上个例子是一样的. 还是先看看piechart.h: #if