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源碼 還是有些幫助的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章