Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Creating Style Plugin in QT5



  • I try to create my own style plugin. However i cant get it to work.

    Here is the code for it:

    QT += widgets
    CONFIG += c++17
    
    CONFIG += plugin release
    TEMPLATE      = lib
    
    TARGET = $$qtLibraryTarget($$TARGET)
    
    target.path = $$[QT_INSTALL_PLUGINS]/styles
    INSTALLS += target
    
    #target.path = /home/sandro/Qt/Tools/QtCreator/bin/plugins/styles
    #INSTALLS += target
    
    
    HEADERS       = ../../bronze/bronze/bronzestyle.h \
                    bronzestyleplugin.h \
                    bronzestyleplugin.h
    SOURCES       = ../../bronze/bronze/bronzestyle.cpp \
                    bronzestyleplugin.cpp \
                    bronzestyleplugin.cpp
    RESOURCES     = ../../bronze/bronze/bronze.qrc
    
    OTHER_FILES += bronzestyleplugin.json
    
    
    #ifndef BRONZESTYLEPLUGIN_H
    #define BRONZESTYLEPLUGIN_H
    
    #include <QStylePlugin>
    
    class BronzeStylePlugin : public QStylePlugin
    {
        Q_OBJECT
        Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QStyleFactoryInterface" FILE "bronzestyleplugin.json")
    public:
        QStyle *create(const QString &key) override;
    };
    
    #endif // BRONZESTYLEPLUGIN_H
    
    
    #include "bronzestyleplugin.h"
    
    #include "../../bronze/bronze/bronzestyle.h"
    
    QStyle *BronzeStylePlugin::create(const QString &key)
    {
        if (key.toLower() == "bronze") {
            return new BronzeStyle;
        }
        return nullptr;
    }
    
    #ifndef BRONZESTYLE_H
    #define BRONZESTYLE_H
    
    #include <QProxyStyle>
    
    class BronzeStyle : public QProxyStyle
    {
        Q_OBJECT
    public:
        void polish(QPalette &palette) override;
        void polish(QWidget *widget) override;
        void unpolish(QWidget *widget) override;
    
        int styleHint(StyleHint stylehint, const QStyleOption *opt,
                      const QWidget *widget,
                      QStyleHintReturn *returnData) const override;
    
        int pixelMetric(PixelMetric metric, const QStyleOption *option,
                        const QWidget *widget = nullptr) const override;
    
        void drawPrimitive(PrimitiveElement pe, const QStyleOption *opt,
                           QPainter *p, const QWidget *w = nullptr) const override;
    
        void drawComplexControl(ComplexControl cc,
                                const QStyleOptionComplex *opt,
                                QPainter *p, const
                                QWidget *widget = nullptr) const override;
    
    
        QRect subControlRect(ComplexControl cc,
                             const QStyleOptionComplex *opt,
                             SubControl sc,
                             const QWidget *widget = nullptr) const override;
    
    public:
        QIcon standardIcon(StandardPixmap standardIcon, const QStyleOption *option,
                           const QWidget *widget = nullptr) const override;
    
    private:
        void drawBronzeFrame(const QStyleOption *option,
                             QPainter *painter) const;
        void drawBronzeBevel(const QStyleOption *option,
                             QPainter *painter) const;
        void drawBronzeCheckBoxIndicator(const QStyleOption *option,
                                         QPainter *painter) const;
        void drawBronzeSpinBoxButton(SubControl which,
                                     const QStyleOptionComplex *option,
                                     QPainter *painter) const;
    };
    
    #endif // BRONZESTYLE_H
    
    
    #include "bronzestyle.h"
    
    #include <QAbstractButton>
    #include <QAbstractSpinBox>
    #include <QDialogButtonBox>
    
    #include <QPainter>
    #include <QStyleOptionComplex>
    
    void BronzeStyle::polish(QPalette &palette)
    {
        QPixmap backgroundImage(":/images/background.png");
        QColor bronze(207, 155, 95);
        QColor veryLightBlue(239, 239, 247);
        QColor lightBlue(223, 223, 239);
        QColor darkBlue(95, 95, 191);
    
        palette = QPalette(bronze);
        palette.setBrush(QPalette::Window, backgroundImage);
        palette.setBrush(QPalette::BrightText, Qt::white);
        palette.setBrush(QPalette::Base, veryLightBlue);
        palette.setBrush(QPalette::AlternateBase, lightBlue);
        palette.setBrush(QPalette::Highlight, darkBlue);
        palette.setBrush(QPalette::Disabled, QPalette::Highlight,
                         Qt::darkGray);
    }
    
    void BronzeStyle::polish(QWidget *widget)
    {
        if (qobject_cast<QAbstractButton *>(widget)
                || qobject_cast<QAbstractSpinBox *>(widget)) {
            widget->setAttribute(Qt::WA_Hover, true);
        }
    }
    
    void BronzeStyle::unpolish(QWidget *widget)
    {
        if (qobject_cast<QAbstractButton *>(widget)
                || qobject_cast<QAbstractSpinBox *>(widget)) {
            widget->setAttribute(Qt::WA_Hover, false);
        }
    }
    
    int BronzeStyle::styleHint(QStyle::StyleHint stylehint,
                               const QStyleOption *opt,
                               const QWidget *widget,
                               QStyleHintReturn *returnData) const
    {
        switch (stylehint) {
        case SH_DialogButtonLayout:
            return int(QDialogButtonBox::MacLayout);
        case SH_EtchDisabledText:
            return int(true);
        case SH_DialogButtonBox_ButtonsHaveIcons:
            return int(true);
        case SH_UnderlineShortcut:
            return int(false);
        default:
            return QProxyStyle::styleHint(stylehint, opt, widget, returnData);
        }
    }
    
    int BronzeStyle::pixelMetric(QStyle::PixelMetric metric,
                                 const QStyleOption *option,
                                 const QWidget *widget) const
    {
        switch (metric) {
        case PM_ButtonDefaultIndicator:
            return 0;
        case PM_IndicatorWidth:
            [[fallthrough]];
        case PM_IndicatorHeight:
            return 16;
        case PM_CheckBoxLabelSpacing:
            return 8;
        case PM_DefaultFrameWidth:
            return 2;
        default:
            return QProxyStyle::pixelMetric(metric, option, widget);
        }
    }
    
    void BronzeStyle::drawPrimitive(QStyle::PrimitiveElement pe,
                                    const QStyleOption *opt,
                                    QPainter *p,
                                    const QWidget *w) const
    {
        switch (pe) {
        case PE_IndicatorCheckBox:
            drawBronzeCheckBoxIndicator(opt, p);
            break;
        case PE_PanelButtonCommand:
            drawBronzeBevel(opt, p);
            break;
        case PE_Frame:
            drawBronzeFrame(opt, p);
            break;
        case PE_FrameDefaultButton:
            break;
        default:
            QProxyStyle::drawPrimitive(pe, opt, p, w);
        }
    }
    
    void BronzeStyle::drawComplexControl(QStyle::ComplexControl cc,
                                         const QStyleOptionComplex *opt,
                                         QPainter *p,
                                         const QWidget *widget) const
    {
        if (cc == CC_SpinBox) {
            drawBronzeSpinBoxButton(SC_SpinBoxDown, opt, p);
            drawBronzeSpinBoxButton(SC_SpinBoxUp, opt, p);
    
            QRect rect = subControlRect(CC_SpinBox, opt,
                                        SC_SpinBoxEditField, widget)
                         .adjusted(-1, 0, +1, 0);
            p->setPen(QPen(opt->palette.mid(), 1.0));
            p->drawLine(rect.topLeft(), rect.bottomLeft());
            p->drawLine(rect.topRight(), rect.bottomRight());
        }
        else {
            return QProxyStyle::drawComplexControl(cc, opt, p, widget);
        }
    }
    
    QRect BronzeStyle::subControlRect(QStyle::ComplexControl cc,
                                      const QStyleOptionComplex *opt,
                                      QStyle::SubControl sc,
                                      const QWidget *widget) const
    {
        if (cc == CC_SpinBox) {
            int frameWidth = pixelMetric(PM_DefaultFrameWidth, opt, widget);
            int buttonWidth = 16;
    
            switch (sc) {
            case SC_SpinBoxFrame:
                return opt->rect;
            case SC_SpinBoxEditField:
                return opt->rect.adjusted(+buttonWidth, +frameWidth,
                                             -buttonWidth, -frameWidth);
            case SC_SpinBoxDown:
                return visualRect(opt->direction, opt->rect,
                                  QRect(opt->rect.x(), opt->rect.y(),
                                        buttonWidth,
                                        opt->rect.height()));
            case SC_SpinBoxUp:
                return visualRect(opt->direction, opt->rect,
                                  QRect(opt->rect.right() - buttonWidth,
                                        opt->rect.y(),
                                        buttonWidth,
                                        opt->rect.height()));
            default:
                return QRect();
            }
        } else {
            return QProxyStyle::subControlRect(cc, opt,
                                                 sc, widget);
        }
    }
    
    QIcon BronzeStyle::standardIcon(QStyle::StandardPixmap standardIcon,
                                    const QStyleOption *option,
                                    const QWidget *widget) const
    {
        QImage image = QProxyStyle::standardPixmap(standardIcon, option, widget)
                       .toImage();
        if (image.isNull())
            return QIcon();
    
        QPalette palette;
        if (option) {
            palette = option->palette;
        } else if (widget) {
            palette = widget->palette();
        }
    
        QPainter painter(&image);
        painter.setOpacity(0.25);
        painter.setCompositionMode(QPainter::CompositionMode_SourceAtop);
        painter.fillRect(image.rect(), palette.highlight());
        painter.end();
    
        return QIcon(QPixmap::fromImage(image));
    }
    
    void BronzeStyle::drawBronzeFrame(const QStyleOption *option,
                                      QPainter *painter) const
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setPen(QPen(option->palette.windowText(), 1.0));
        painter->drawRect(option->rect.adjusted(+1, +1, -1, -1));
        painter->restore();
    }
    
    void BronzeStyle::drawBronzeBevel(const QStyleOption *option,
                                      QPainter *painter) const
    {
        QColor buttonColor = option->palette.button().color();
        int coeff = (option->state & State_MouseOver) ? 115 : 105;
    
        QLinearGradient gradient(0, 0, 0, option->rect.height());
        gradient.setColorAt(0.0, option->palette.light().color());
        gradient.setColorAt(0.2, buttonColor.lighter(coeff));
        gradient.setColorAt(0.8, buttonColor.darker(coeff));
        gradient.setColorAt(1.0, option->palette.dark().color());
    
        double penWidth = 1.0;
        if (const QStyleOptionButton *buttonOpt =
                qstyleoption_cast<const QStyleOptionButton *>(option)) {
            if (buttonOpt->features & QStyleOptionButton::DefaultButton) {
                penWidth = 2.0;
            }
        }
    
        QRect roundRect = option->rect.adjusted(+1, +1, -1, -1);
        if (!roundRect.isValid())
            return;
    
        int diameter = 12;
        int cx = 100 * diameter / roundRect.width();
        int cy = 100 * diameter / roundRect.height();
    
        painter->save();
        painter->setPen(Qt::NoPen);
        painter->setBrush(gradient);
        painter->drawRoundedRect(roundRect, cx, cy);
    
        if (option->state & (State_On | State_Sunken)) {
            QColor slightlyOpaqueBlack(0, 0, 0, 63);
            painter->setBrush(slightlyOpaqueBlack);
            painter->drawRoundedRect(roundRect, cx, cy);
        }
    
        painter->setRenderHint(QPainter::Antialiasing, true);
        painter->setPen(QPen(option->palette.windowText(), penWidth));
        painter->setBrush(Qt::NoBrush);
        painter->drawRoundedRect(roundRect, cx, cy);
        painter->restore();
    }
    
    void BronzeStyle::drawBronzeCheckBoxIndicator(const QStyleOption *option,
                                                  QPainter *painter) const
    {
        painter->save();
        painter->setRenderHint(QPainter::Antialiasing, true);
    
        if (option->state & State_MouseOver) {
            painter->setBrush(option->palette.alternateBase());
        }
        else {
            painter->setBrush(option->palette.base());
        }
        painter->drawRoundRect(option->rect.adjusted(+1, +1, -1, -1));
    
        if (option->state & (State_On | State_NoChange)) {
            QPixmap pixmap;
            if (!(option->state & State_Enabled)) {
                pixmap.load(":/images/checkmark-disabled.png");
            } else if (option->state & State_NoChange) {
                pixmap.load(":/images/checkmark-partial.png");
            } else {
                pixmap.load(":/images/checkmark.png");
            }
    
            QRect pixmapRect = pixmap.rect()
                                     .translated(option->rect.topLeft())
                                     .translated(+2, -6);
            QRect painterRect = visualRect(option->direction, option->rect,
                                           pixmapRect);
            if (option->direction == Qt::RightToLeft) {
                painter->scale(-1.0, +1.0);
                painterRect.moveLeft(-painterRect.right() - 1);
            }
            painter->drawPixmap(painterRect, pixmap);
        }
        painter->restore();
    }
    
    void BronzeStyle::drawBronzeSpinBoxButton(QStyle::SubControl which,
                                              const QStyleOptionComplex *option,
                                              QPainter *painter) const
    {
        PrimitiveElement arrow = PE_IndicatorArrowLeft;
        QRect buttonRect = option->rect;
        if ((which == SC_SpinBoxUp)
                != (option->direction == Qt::RightToLeft)) {
            arrow = PE_IndicatorArrowRight;
            buttonRect.translate(buttonRect.width() / 2, 0);
        }
        buttonRect.setWidth((buttonRect.width() + 1) / 2);
    
        QStyleOption buttonOpt(*option);
    
        painter->save();
        painter->setClipRect(buttonRect, Qt::IntersectClip);
        if (!(option->activeSubControls & which))
            buttonOpt.state &= ~(State_MouseOver | State_On | State_Sunken);
        drawBronzeBevel(&buttonOpt, painter);
    
        QStyleOption arrowOpt(buttonOpt);
        arrowOpt.rect = subControlRect(CC_SpinBox, option, which)
                        .adjusted(+3, +3, -3, -3);
        if (arrowOpt.rect.isValid())
            drawPrimitive(arrow, &arrowOpt, painter);
        painter->restore();
    }
    
    

    When i try to compile this i i get this output:

    19:05:23: Running steps for project bronzestyleplugin...
    19:05:23: Configuration unchanged, skipping qmake step.
    19:05:23: Starting: "/usr/bin/make" -j4
    Makefile:975: warning: overriding recipe for target 'moc_bronzestyleplugin.cpp'
    Makefile:904: warning: ignoring old recipe for target 'moc_bronzestyleplugin.cpp'
    Makefile:1321: warning: overriding recipe for target 'bronzestyleplugin.o'
    Makefile:1222: warning: ignoring old recipe for target 'bronzestyleplugin.o'
    /home/sandro/Qt/5.13.0/gcc_64/bin/qmake -o Makefile ../bronzestyleplugin/bronzestyleplugin.pro -spec linux-g++ CONFIG+=qtquickcompiler
    Makefile:978: warning: overriding recipe for target 'moc_bronzestyleplugin.cpp'
    Makefile:907: warning: ignoring old recipe for target 'moc_bronzestyleplugin.cpp'
    Makefile:1324: warning: overriding recipe for target 'bronzestyleplugin.o'
    Makefile:1225: warning: ignoring old recipe for target 'bronzestyleplugin.o'
    g++ -c -pipe -O2 -std=gnu++1z -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I../bronzestyleplugin -I. -I/home/sandro/Qt/5.13.0/gcc_64/include -I/home/sandro/Qt/5.13.0/gcc_64/include/QtWidgets -I/home/sandro/Qt/5.13.0/gcc_64/include/QtGui -I/home/sandro/Qt/5.13.0/gcc_64/include/QtCore -I. -isystem /usr/include/libdrm -I/home/sandro/Qt/5.13.0/gcc_64/mkspecs/linux-g++ -o bronzestyle.o ../../bronze/bronze/bronzestyle.cpp
    g++ -c -pipe -O2 -std=gnu++1z -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I../bronzestyleplugin -I. -I/home/sandro/Qt/5.13.0/gcc_64/include -I/home/sandro/Qt/5.13.0/gcc_64/include/QtWidgets -I/home/sandro/Qt/5.13.0/gcc_64/include/QtGui -I/home/sandro/Qt/5.13.0/gcc_64/include/QtCore -I. -isystem /usr/include/libdrm -I/home/sandro/Qt/5.13.0/gcc_64/mkspecs/linux-g++ -o bronzestyleplugin.o ../bronzestyleplugin/bronzestyleplugin.cpp
    /home/sandro/Qt/5.13.0/gcc_64/bin/moc -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB --include /mnt/Programmierung/Cpp/QT/C++_GUI_Programming_with_Qt/CH21_creating_plugins/bronzestyleplugin/build-bronzestyleplugin-Desktop_Qt_5_13_0_GCC_64bit-Release/moc_predefs.h -I/home/sandro/Qt/5.13.0/gcc_64/mkspecs/linux-g++ -I/mnt/Programmierung/Cpp/QT/C++_GUI_Programming_with_Qt/CH21_creating_plugins/bronzestyleplugin/bronzestyleplugin -I/home/sandro/Qt/5.13.0/gcc_64/include -I/home/sandro/Qt/5.13.0/gcc_64/include/QtWidgets -I/home/sandro/Qt/5.13.0/gcc_64/include/QtGui -I/home/sandro/Qt/5.13.0/gcc_64/include/QtCore -I. -I/usr/include/c++/7 -I/usr/include/x86_64-linux-gnu/c++/7 -I/usr/include/c++/7/backward -I/usr/lib/gcc/x86_64-linux-gnu/7/include -I/usr/local/include -I/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed -I/usr/include/x86_64-linux-gnu -I/usr/include ../../bronze/bronze/bronzestyle.h -o moc_bronzestyle.cpp
    g++ -c -pipe -O2 -std=gnu++1z -Wall -W -D_REENTRANT -fPIC -DQT_NO_DEBUG -DQT_PLUGIN -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -I../bronzestyleplugin -I. -I/home/sandro/Qt/5.13.0/gcc_64/include -I/home/sandro/Qt/5.13.0/gcc_64/include/QtWidgets -I/home/sandro/Qt/5.13.0/gcc_64/include/QtGui -I/home/sandro/Qt/5.13.0/gcc_64/include/QtCore -I. -isystem /usr/include/libdrm -I/home/sandro/Qt/5.13.0/gcc_64/mkspecs/linux-g++ -o moc_bronzestyle.o moc_bronzestyle.cpp
    ../../bronze/bronze/bronzestyle.cpp: In member function ‘void BronzeStyle::drawBronzeCheckBoxIndicator(const QStyleOption*, QPainter*) const’:
    ../../bronze/bronze/bronzestyle.cpp:254:65: warning: ‘void QPainter::drawRoundRect(const QRect&, int, int)’ is deprecated: Use drawRoundedRect(..., Qt::RelativeSize) instead [-Wdeprecated-declarations]
         painter->drawRoundRect(option->rect.adjusted(+1, +1, -1, -1));
                                                                     ^
    In file included from /home/sandro/Qt/5.13.0/gcc_64/include/QtGui/QPainter:1:0,
                     from ../../bronze/bronze/bronzestyle.cpp:7:
    /home/sandro/Qt/5.13.0/gcc_64/include/QtGui/qpainter.h:379:10: note: declared here
         void drawRoundRect(const QRect &r, int xround = 25, int yround = 25);
              ^~~~~~~~~~~~~
    rm -f libbronzestyleplugin.so
    g++ -Wl,-O1 -Wl,-rpath,/home/sandro/Qt/5.13.0/gcc_64/lib -shared -o libbronzestyleplugin.so bronzestyle.o bronzestyleplugin.o bronzestyleplugin.o qrc_bronze.o moc_bronzestyle.o moc_bronzestyleplugin.o  /home/sandro/Qt/5.13.0/gcc_64/lib/libQt5Widgets.so /home/sandro/Qt/5.13.0/gcc_64/lib/libQt5Gui.so /home/sandro/Qt/5.13.0/gcc_64/lib/libQt5Core.so -lGL -lpthread    
    bronzestyleplugin.o: In function `BronzeStylePlugin::create(QString const&)':
    bronzestyleplugin.cpp:(.text+0x0): multiple definition of `BronzeStylePlugin::create(QString const&)'
    bronzestyleplugin.o:bronzestyleplugin.cpp:(.Makefile:277: recipe for target 'libbronzestyleplugin.so' failed
    text+0x0): first defined here
    collect2: error: ld returned 1 exit status
    make: *** [libbronzestyleplugin.so] Error 1
    19:05:25: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project bronzestyleplugin (kit: Desktop Qt 5.13.0 GCC 64bit)
    When executing step "Make"
    19:05:25: Elapsed time: 00:02.
    

    Any idea how to find the issue here?


  • Lifetime Qt Champion

    Hi,

    How many create method do you have ?


  • Lifetime Qt Champion

    @sandro4912 said in Creating Style Plugin in QT5:

    SOURCES = ../../bronze/bronze/bronzestyle.cpp
    bronzestyleplugin.cpp
    bronzestyleplugin.cpp

    You add your sources (and also headers) twice.



  • @Christian-Ehrlicher

    removing the double declaration fixed the issue. I could compile the style addon.

    However i don't see that the styles plugin gets deployed. I only get:

    18:15:49: Running steps for project bronzestyleplugin...
    18:15:49: Configuration unchanged, skipping qmake step.
    18:15:49: Starting: "/usr/bin/make" -j4
    /home/sandro/Qt/5.13.0/gcc_64/bin/qmake -o Makefile ../bronzestyleplugin/bronzestyleplugin.pro -spec linux-g++ CONFIG+=qtquickcompiler
    make: Nothing to be done for 'first'.
    18:15:50: The process "/usr/bin/make" exited normally.
    18:15:50: Elapsed time: 00:01.
    

    To have it available from qt creator do i have to ?


  • Lifetime Qt Champion

    'make' just compiles a library, 'make install' installs it. But since you did not define an install target there won't be done anything. You have to copy it to the correct folder by yourself.



  • I thought i defined it with

    TARGET = $$qtLibraryTarget($$TARGET)
    
    target.path = $$[QT_INSTALL_PLUGINS]/styles
    INSTALLS += target
    

    what do i need to add to automatically copy it to the correct folder?


  • Lifetime Qt Champion

    So did you actually do a 'make install' ?



  • what do you mean with that?


  • Lifetime Qt Champion

    Just because you define an install target nothing happens - you have to call make with the parameter 'install' as I said above.


Log in to reply