Qt 图像叠加模式[composition Modes]官方例子 源码解读

前言:

看 qt 的例子 看到个有意思的
图片质量有压缩 看起来不美

在这里插入图片描述

在这里插入图片描述

这个代码 比我们平常看到的要复杂一点 能学到东西 我把源码看了一下
在这里在仔细整理说一下

在这里插入图片描述

composition 项目结构

在这里插入图片描述

一个 shared 文件夹
几个类
注意 这个 hoverpoints 类没有用到
因为我没有开启 opengl

两个资源文件 一些美化控件的图片
在这里插入图片描述

在这里插入图片描述

两种 底色图片 就是那个背景花
一个 html 里面是介绍的这个项目
在这里插入图片描述

Main

在这里插入图片描述

 QStyle *arthurStyle = new ArthurStyle();

说明 ArthurStyle 这个类是Qstyle 的子类
也就是自定义 style 了

我们先把他注释掉 看运行效果

加载了 style的

在这里插入图片描述

未加载 style 的

在这里插入图片描述

明显的变化 右边控件 都变丑了

ok 我们等会再看 自定义 的style 先把整个架构看一遍

整个的窗口 就是

CompositionWidget

在这里插入图片描述

24个 radiobutton …

看 构造函数 吧
CompositionWidget::CompositionWidget(QWidget *parent)
    : QWidget(parent)
{
    CompositionRenderer *view = new CompositionRenderer(this);

    QGroupBox *mainGroup = new QGroupBox(parent);
    mainGroup->setTitle(tr("Composition Modes"));

    QGroupBox *modesGroup = new QGroupBox(mainGroup);
    modesGroup->setTitle(tr("Mode"));

    rbClear = new QRadioButton(tr("Clear"), modesGroup);
    connect(rbClear, SIGNAL(clicked()), view, SLOT(setClearMode()));
    rbSource = new QRadioButton(tr("Source"), modesGroup);
    connect(rbSource, SIGNAL(clicked()), view, SLOT(setSourceMode()));
    rbDest = new QRadioButton(tr("Destination"), modesGroup);
    connect(rbDest, SIGNAL(clicked()), view, SLOT(setDestMode()));
    rbSourceOver = new QRadioButton(tr("Source Over"), modesGroup);
    connect(rbSourceOver, SIGNAL(clicked()), view, SLOT(setSourceOverMode()));
    rbDestOver = new QRadioButton(tr("Destination Over"), modesGroup);
    connect(rbDestOver, SIGNAL(clicked()), view, SLOT(setDestOverMode()));
    rbSourceIn = new QRadioButton(tr("Source In"), modesGroup);
    connect(rbSourceIn, SIGNAL(clicked()), view, SLOT(setSourceInMode()));
    rbDestIn = new QRadioButton(tr("Dest In"), modesGroup);
    connect(rbDestIn, SIGNAL(clicked()), view, SLOT(setDestInMode()));
    rbSourceOut = new QRadioButton(tr("Source Out"), modesGroup);
    connect(rbSourceOut, SIGNAL(clicked()), view, SLOT(setSourceOutMode()));
    rbDestOut = new QRadioButton(tr("Dest Out"), modesGroup);
    connect(rbDestOut, SIGNAL(clicked()), view, SLOT(setDestOutMode()));
    rbSourceAtop = new QRadioButton(tr("Source Atop"), modesGroup);
    connect(rbSourceAtop, SIGNAL(clicked()), view, SLOT(setSourceAtopMode()));
    rbDestAtop = new QRadioButton(tr("Dest Atop"), modesGroup);
    connect(rbDestAtop, SIGNAL(clicked()), view, SLOT(setDestAtopMode()));
    rbXor = new QRadioButton(tr("Xor"), modesGroup);
    connect(rbXor, SIGNAL(clicked()), view, SLOT(setXorMode()));

    rbPlus = new QRadioButton(tr("Plus"), modesGroup);
    connect(rbPlus, SIGNAL(clicked()), view, SLOT(setPlusMode()));
    rbMultiply = new QRadioButton(tr("Multiply"), modesGroup);
    connect(rbMultiply, SIGNAL(clicked()), view, SLOT(setMultiplyMode()));
    rbScreen = new QRadioButton(tr("Screen"), modesGroup);
    connect(rbScreen, SIGNAL(clicked()), view, SLOT(setScreenMode()));
    rbOverlay = new QRadioButton(tr("Overlay"), modesGroup);
    connect(rbOverlay, SIGNAL(clicked()), view, SLOT(setOverlayMode()));
    rbDarken = new QRadioButton(tr("Darken"), modesGroup);
    connect(rbDarken, SIGNAL(clicked()), view, SLOT(setDarkenMode()));
    rbLighten = new QRadioButton(tr("Lighten"), modesGroup);
    connect(rbLighten, SIGNAL(clicked()), view, SLOT(setLightenMode()));
    rbColorDodge = new QRadioButton(tr("Color Dodge"), modesGroup);
    connect(rbColorDodge, SIGNAL(clicked()), view, SLOT(setColorDodgeMode()));
    rbColorBurn = new QRadioButton(tr("Color Burn"), modesGroup);
    connect(rbColorBurn, SIGNAL(clicked()), view, SLOT(setColorBurnMode()));
    rbHardLight = new QRadioButton(tr("Hard Light"), modesGroup);
    connect(rbHardLight, SIGNAL(clicked()), view, SLOT(setHardLightMode()));
    rbSoftLight = new QRadioButton(tr("Soft Light"), modesGroup);
    connect(rbSoftLight, SIGNAL(clicked()), view, SLOT(setSoftLightMode()));
    rbDifference = new QRadioButton(tr("Difference"), modesGroup);
    connect(rbDifference, SIGNAL(clicked()), view, SLOT(setDifferenceMode()));
    rbExclusion = new QRadioButton(tr("Exclusion"), modesGroup);
    connect(rbExclusion, SIGNAL(clicked()), view, SLOT(setExclusionMode()));

    QGroupBox *circleColorGroup = new QGroupBox(mainGroup);
    circleColorGroup->setTitle(tr("Circle color"));
    QSlider *circleColorSlider = new QSlider(Qt::Horizontal, circleColorGroup);
    circleColorSlider->setRange(0, 359);
    circleColorSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    connect(circleColorSlider, SIGNAL(valueChanged(int)), view, SLOT(setCircleColor(int)));

    QGroupBox *circleAlphaGroup = new QGroupBox(mainGroup);
    circleAlphaGroup->setTitle(tr("Circle alpha"));
    QSlider *circleAlphaSlider = new QSlider(Qt::Horizontal, circleAlphaGroup);
    circleAlphaSlider->setRange(0, 255);
    circleAlphaSlider->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
    connect(circleAlphaSlider, SIGNAL(valueChanged(int)), view, SLOT(setCircleAlpha(int)));

    QPushButton *showSourceButton = new QPushButton(mainGroup);
    showSourceButton->setText(tr("Show Source"));
#if defined(USE_OPENGL) && !defined(QT_OPENGL_ES)
    QPushButton *enableOpenGLButton = new QPushButton(mainGroup);
    enableOpenGLButton->setText(tr("Use OpenGL"));
    enableOpenGLButton->setCheckable(true);
    enableOpenGLButton->setChecked(view->usesOpenGL());

    if (!QGLFormat::hasOpenGL() || !QGLPixelBuffer::hasOpenGLPbuffers())
        enableOpenGLButton->hide();
#endif
    QPushButton *whatsThisButton = new QPushButton(mainGroup);
    whatsThisButton->setText(tr("What's This?"));
    whatsThisButton->setCheckable(true);

    QPushButton *animateButton = new QPushButton(mainGroup);
    animateButton->setText(tr("Animated"));
    animateButton->setCheckable(true);
    animateButton->setChecked(true);

    QHBoxLayout *viewLayout = new QHBoxLayout(this);
    viewLayout->addWidget(view);
    viewLayout->addWidget(mainGroup);

    QVBoxLayout *mainGroupLayout = new QVBoxLayout(mainGroup);
    mainGroupLayout->addWidget(circleColorGroup);
    mainGroupLayout->addWidget(circleAlphaGroup);
    mainGroupLayout->addWidget(modesGroup);
    mainGroupLayout->addStretch();
    mainGroupLayout->addWidget(animateButton);
    mainGroupLayout->addWidget(whatsThisButton);
    mainGroupLayout->addWidget(showSourceButton);
#if defined(USE_OPENGL) && !defined(QT_OPENGL_ES)
    mainGroupLayout->addWidget(enableOpenGLButton);
#endif

    QGridLayout *modesLayout = new QGridLayout(modesGroup);
    modesLayout->addWidget(rbClear, 0, 0);
    modesLayout->addWidget(rbSource, 1, 0);
    modesLayout->addWidget(rbDest, 2, 0);
    modesLayout->addWidget(rbSourceOver, 3, 0);
    modesLayout->addWidget(rbDestOver, 4, 0);
    modesLayout->addWidget(rbSourceIn, 5, 0);
    modesLayout->addWidget(rbDestIn, 6, 0);
    modesLayout->addWidget(rbSourceOut, 7, 0);
    modesLayout->addWidget(rbDestOut, 8, 0);
    modesLayout->addWidget(rbSourceAtop, 9, 0);
    modesLayout->addWidget(rbDestAtop, 10, 0);
    modesLayout->addWidget(rbXor, 11, 0);

    modesLayout->addWidget(rbPlus, 0, 1);
    modesLayout->addWidget(rbMultiply, 1, 1);
    modesLayout->addWidget(rbScreen, 2, 1);
    modesLayout->addWidget(rbOverlay, 3, 1);
    modesLayout->addWidget(rbDarken, 4, 1);
    modesLayout->addWidget(rbLighten, 5, 1);
    modesLayout->addWidget(rbColorDodge, 6, 1);
    modesLayout->addWidget(rbColorBurn, 7, 1);
    modesLayout->addWidget(rbHardLight, 8, 1);
    modesLayout->addWidget(rbSoftLight, 9, 1);
    modesLayout->addWidget(rbDifference, 10, 1);
    modesLayout->addWidget(rbExclusion, 11, 1);


    QVBoxLayout *circleColorLayout = new QVBoxLayout(circleColorGroup);
    circleColorLayout->addWidget(circleColorSlider);

    QVBoxLayout *circleAlphaLayout = new QVBoxLayout(circleAlphaGroup);
    circleAlphaLayout->addWidget(circleAlphaSlider);

    view->loadDescription(":res/composition/composition.html");
    view->loadSourceFile(":res/composition/composition.cpp");

    connect(whatsThisButton, SIGNAL(clicked(bool)), view, SLOT(setDescriptionEnabled(bool)));
    connect(view, SIGNAL(descriptionEnabledChanged(bool)), whatsThisButton, SLOT(setChecked(bool)));
    connect(showSourceButton, SIGNAL(clicked()), view, SLOT(showSource()));
#if defined(USE_OPENGL) && !defined(QT_OPENGL_ES)
    connect(enableOpenGLButton, SIGNAL(clicked(bool)), view, SLOT(enableOpenGL(bool)));
#endif
    connect(animateButton, SIGNAL(toggled(bool)), view, SLOT(setAnimationEnabled(bool)));

    circleColorSlider->setValue(270);
    circleAlphaSlider->setValue(200);
    rbSourceOut->animateClick();

    setWindowTitle(tr("Composition Modes"));
}

在这里插入图片描述

主界面 又分为两部分

左边 是 CompositionRenderer 等会我们看

CompositionRenderer *view = new CompositionRenderer(this);

右边是 个 groubox

QGroupBox *mainGroup = new QGroupBox(parent);

右边 groupbox 又分为 3个小的 groupbox

顶部 Circle color 是个名字叫 Circle color groupbox 放了一个滑动条

下面 Circle alpha 的groupbox 也是放的滑动条

在向下是 叫 Mode 的 groupbox 放了 24个 radiobutton

下面 还有 3个 按钮

然后 垂直布局

在这里插入图片描述

有部分 函数 没有必要说了 我看了一下

比如当点击 show source 按钮时 就是把 composition.cpp 的源码 加载出来

点击 what is this ? 就是 把 资源文件的 html 的内容 画出来 也没必说了

你们要看一下

主要说一下 左边的 view 里面的效果是怎么实现的
和自定义的 style 是怎么实现的

左边部分

左边这部分的实现 就是他 CompositionRenderer

在这里插入图片描述
在这里插入图片描述

class CompositionRenderer : public ArthurFrame
{
    Q_OBJECT

    enum ObjectType { NoObject, Circle, Rectangle, Image };

    Q_PROPERTY(int circleColor READ circleColor WRITE setCircleColor)
    Q_PROPERTY(int circleAlpha READ circleAlpha WRITE setCircleAlpha)
    Q_PROPERTY(bool animation READ animationEnabled WRITE setAnimationEnabled)

public:
    CompositionRenderer(QWidget *parent);

    void paint(QPainter *) override;

    void setCirclePos(const QPointF &pos);

    QSize sizeHint() const override { return QSize(500, 400); }

    bool animationEnabled() const { return m_animation_enabled; }
    int circleColor() const { return m_circle_hue; }
    int circleAlpha() const { return m_circle_alpha; }

protected:
    void mousePressEvent(QMouseEvent *) override;
    void mouseMoveEvent(QMouseEvent *) override;
    void mouseReleaseEvent(QMouseEvent *) override;
    void timerEvent(QTimerEvent *) override;

public slots:
    void setClearMode() { m_composition_mode = QPainter::CompositionMode_Clear; update(); }
    void setSourceMode() { m_composition_mode = QPainter::CompositionMode_Source; update(); }
    void setDestMode() { m_composition_mode = QPainter::CompositionMode_Destination; update(); }
    void setSourceOverMode() { m_composition_mode = QPainter::CompositionMode_SourceOver; update(); }
    void setDestOverMode() { m_composition_mode = QPainter::CompositionMode_DestinationOver; update(); }
    void setSourceInMode() { m_composition_mode = QPainter::CompositionMode_SourceIn; update(); }
    void setDestInMode() { m_composition_mode = QPainter::CompositionMode_DestinationIn; update(); }
    void setSourceOutMode() { m_composition_mode = QPainter::CompositionMode_SourceOut; update(); }
    void setDestOutMode() { m_composition_mode = QPainter::CompositionMode_DestinationOut; update(); }
    void setSourceAtopMode() { m_composition_mode = QPainter::CompositionMode_SourceAtop; update(); }
    void setDestAtopMode() { m_composition_mode = QPainter::CompositionMode_DestinationAtop; update(); }
    void setXorMode() { m_composition_mode = QPainter::CompositionMode_Xor; update(); }

    void setPlusMode() { m_composition_mode = QPainter::CompositionMode_Plus; update(); }
    void setMultiplyMode() { m_composition_mode = QPainter::CompositionMode_Multiply; update(); }
    void setScreenMode() { m_composition_mode = QPainter::CompositionMode_Screen; update(); }
    void setOverlayMode() { m_composition_mode = QPainter::CompositionMode_Overlay; update(); }
    void setDarkenMode() { m_composition_mode = QPainter::CompositionMode_Darken; update(); }
    void setLightenMode() { m_composition_mode = QPainter::CompositionMode_Lighten; update(); }
    void setColorDodgeMode() { m_composition_mode = QPainter::CompositionMode_ColorDodge; update(); }
    void setColorBurnMode() { m_composition_mode = QPainter::CompositionMode_ColorBurn; update(); }
    void setHardLightMode() { m_composition_mode = QPainter::CompositionMode_HardLight; update(); }
    void setSoftLightMode() { m_composition_mode = QPainter::CompositionMode_SoftLight; update(); }
    void setDifferenceMode() { m_composition_mode = QPainter::CompositionMode_Difference; update(); }
    void setExclusionMode() { m_composition_mode = QPainter::CompositionMode_Exclusion; update(); }

    void setCircleAlpha(int alpha) { m_circle_alpha = alpha; update(); }
    void setCircleColor(int hue) { m_circle_hue = hue; update(); }
    void setAnimationEnabled(bool enabled);

private:
    void updateCirclePos();
    void drawBase(QPainter &p);
    void drawSource(QPainter &p);

    QPainter::CompositionMode m_composition_mode;

    QImage m_image;
    QImage m_buffer;
    QImage m_base_buffer;

    int m_circle_alpha;
    int m_circle_hue;

    QPointF m_circle_pos;
    QPointF m_offset;

    ObjectType m_current_object;
    bool m_animation_enabled;
    int m_animationTimer;

#ifdef QT_OPENGL_SUPPORT
    QGLPixelBuffer *m_pbuffer;
    GLuint m_base_tex;
    GLuint m_compositing_tex;
    int m_pbuffer_size; // width==height==size of pbuffer
    QSize m_previous_size;
#endif
};

这个部分还是要仔细看的 他的基类 是 ArthurFrame

我们等会看基类 先看着这个实现的

一个是这个圆圈是怎么实现的
二个是背景图的叠加

在这里插入图片描述
背景图就是这两个资源文件的 两朵花 重叠一块
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
右半侧的是渐变色 下面的函数实现的

在这里插入图片描述

圆圈是这个画出来的

在这里插入图片描述

下面的是 paint 函数

在这里插入图片描述

先画 drawBase 渐变色

在画 drawSource 圆圈

在画 两个重叠的花 drawImage

这个圆圈是移动有两种 一是自动动 而是 鼠标拖着动

在这里插入图片描述

这个函数 就是用了个定时器 控制 自动动的

在这里插入图片描述
**鼠标拖着动 **

先获取 圆圈的 位置和外围矩形框的大小

判断鼠标点击的位置在不在 圆圈内 如果在就记录位置 并把 object 给他
然后 关闭 自动动的定时器

在这里插入图片描述

这些 背景 格子 是哪里来的?

在这里插入图片描述

这时候就看他的基类 ArthurFrame
在里面实现的

在这里插入图片描述
实现也简单 画一个 128 * 128 的格子
一半画白色 6464
一半画灰色 64
64

在这里插入图片描述
然后把整个都填充
在这里插入图片描述

因为他是基类 所以先画格子

这个类 还有个显示源码的 和 html 内容的 没必要说 都能看懂

整个的左边的 实现 到这里就过了一遍了 你们可以仔细看下源码
我不能每句代码都介绍 我把整体的关键的说一下

右边部分

ok 右边的 美化 是实现了 自定义的 QStyle

这个QCommonstyle 也是继承 QStyle 是个标准style 类
在这里插入图片描述
在这里插入图片描述

QCommonStyle类封装了GUI的公共外观和感觉。
这个抽象类实现了小部件的一些外观,这些外观对于作为Qt一部分提供和提供的所有GUI样式都是通用的。
因为QCommonStyle继承了QStyle,所以它的所有功能都被完整地记录在QStyle文档中。

看 官方 api qstyle 的介绍

在这里插入图片描述

开发具有样式意识的自定义小部件
如果您正在开发定制的小部件,并且希望它们在所有平台上都表现良好,那么您可以使用QStyle函数来执行小部件绘图的各个部分,比如drawItemText()、drawItemPixmap()、drawPrimitive()、drawControl()和drawComplexControl()。

在这里插入图片描述
在这里插入图片描述

咱们就看一个 radiobutton 滑动 时效果怎么实现的 以此类推就行

在这里插入图片描述

看到
if (hover)
drawHoverRect(painter, widget->rect());
这里就可以

看这个 函数  drawHoverRect(painter, widget->rect());

下面是选中时和未选中时 改变不同的样式

在这里插入图片描述

在这里插入图片描述

看到代码没 这一个 绿色的高亮
是画了 3个东西

左边一个半圆 右边一个半圆

中间一个矩形
然后 用了颜色 填充一下 。。。。

ok 所有的 用到这个样式 的都是这个效果

先获取 控件的大小 然后 画3个东西 加个颜色

其他的都大同小异
如果要实现的很酷炫 还是要看 基类 的 API QStyle 的函数

我觉得这样实现会不会效率低啊 直接用 qss 会不会好一些
难道加载qss 还是解析qss 在这样实现一次?

行 基本的这个代码 是怎么实现的 我是看了一遍了

我这篇文章 对快速了解这个demo源码 还是有些帮助的

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值