Как перерисовать кнопку в Qt?

Хочу вывести кнопку которая будет иметь стандартный функционал кнопки (QPushButton), но при этом иметь другой внешний вид

Но почемуто не не позволяют вывести класс который наследуется от QPushButton

введите сюда описание изображения

вот код (не могу понять что я делаю не так ):

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(myButton VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
        mainwindow.ui
        custombutton.cpp
        custombutton.h
        lineitem.cpp
        lineitem.h
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(myButton
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
# Define target properties for Android with Qt 6 as:
#    set_property(TARGET myButton APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
#                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
    if(ANDROID)
        add_library(myButton SHARED
            ${PROJECT_SOURCES}
        )
# Define properties for Android with Qt 5 after find_package() calls as:
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
    else()
        add_executable(myButton
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(myButton PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

set_target_properties(myButton PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(myButton)
endif()

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}
  

mainwindow.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)

{
    _line = new lineItem(this);

    ui->setupUi(this);

    ui->gridLayout->addItem(_line);
}

MainWindow::~MainWindow()
{
    delete ui;
}
    

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

#include "lineitem.h"


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    lineItem*  _line;

};
#endif // MAINWINDOW_H

    

custombutton.cpp

#include "custombutton.h"

customButton::customButton(QPushButton *parent)
    : QPushButton{parent}
{
    _myPushButton = qobject_cast<QPushButton*>(parent);
}

void customButton::setPosition(float radiusPos, float angle)
{

    if(radiusPos<0)
        _rPos = 0;
    else
        _rPos = radiusPos;

    if(angle>360)
        _angle = 360;
    else if(radiusPos<0)
        _angle = 0;
    else
        _angle = angle;

    _myPushButton->update();
}

QPointF customButton::getCenterPoint(float radPos, float angle)
{
    float r = getRadius(_myPushButton->rect());
    float xx=cos(qDegreesToRadians(angle+90))*r;
    float yy=sin(qDegreesToRadians(angle+90))*r;

    QPointF pt;
    xx=_myPushButton->rect().center().x()-xx*radPos;
    yy=_myPushButton->rect().center().y()-yy*radPos;
    pt.setX(xx);
    pt.setY(yy);
    return pt;
}


void customButton::setColors(const QColor &substrate, const QColor &item, const QColor &outline)
{
    _colorSubstrate = substrate;
    _colorItem = item;
    _colorOutline = outline;
}

void customButton::setValueRange(float minValue, float maxValue)
{
    _minValue = minValue;
    _maxValue = maxValue;
}

void customButton::setDegreeRange(float minDegree, float maxDegree)
{
    _minDegree = minDegree;
    _maxDegree = maxDegree;
}

void customButton::setSubstrate(bool val)
{
    _drawSubstrate = val;
}

void customButton::setThicknessOutline(float val)
{
    _thicknessOutline = val;
}

void customButton::setOutline(bool val)
{
    _drawOutline = val;
}

void customButton::setShadow(bool val)
{
    _drawShadow = val;
}

float customButton::getRadius(const QRectF &tmpRect)
{
    float r = 0;
    if(tmpRect.width() < tmpRect.height()*_wh)
        r = tmpRect.width()/(2.0*_wh);
    else
        r = tmpRect.height()/2.0;
    return r;
}

float customButton::getDegFromValue(float val)
{
    float a = (_maxDegree-_minDegree)/(_maxValue-_minValue);
    float b = -a*_minValue+_minDegree;
    return a*val+b;
}

void customButton::setScaleFactor(float val)
{
    _scaleFactor = val;
}

void customButton::setThickness(float val)
{
    _thickness = val;
}

void customButton::setProportions(float wh)
{
    _wh = wh;
}
    

custombutton.h

#ifndef BUTTONITEM_H
#define BUTTONITEM_H

#include <QObject>
#include <QButtonGroup>
#include <QPushButton>

#include <QPainter>
#include <QColor>
#include <QFont>
#include <QDebug>

#include <QPainterPath>
#include <QPointF>
#include <QRect>
#include <QGraphicsBlurEffect>
#include <QGraphicsItem>
#include <QtMath>
#include <QMessageBox>

class customButton : public QPushButton
{

public:
    explicit customButton(QPushButton *parent = nullptr);

    virtual void draw(QPainter *p) = 0;

    ///
    /// \brief setPosition установить радиус (1=100%) и угол (в градусах) определяющий расположение item на виджете
    ///
    void setPosition(float radiusPos , float angle);

    ///
    /// \brief getPoint расчитать центральную точку
    ///
    QPointF getCenterPoint(float radPos, float angle);

    ///
    /// \brief setColors: установить три цвета ( подложки, основной и обводки) для item
    ///
    void setColors(const QColor &substrate, const QColor &item, const QColor &outline);

    ///
    /// \brief setValueRange установить диапазон изменения значения
    ///
    void setValueRange(float minValue,float maxValue);

    ///
    /// \brief setDegreeRange установить диапазон изменения угла
    ///
    void setDegreeRange(float minDegree,float maxDegree);

    /// inner function

    ///
    /// \brief включить отрисовку подложки с заданным ранее цветом и прозрачностью
    ///
    void setSubstrate(bool val);

    ///
    /// \brief setThicknessOutline установить толщину обводки
    ///
    void setThicknessOutline(float val);

    ///
    /// \brief включить отрисовку подложки с заданным ранее цветом и прозрачностью
    ///
    void setOutline(bool val);

    ///
    /// \brief включить отрисовку "тени"
    ///
    void setShadow(bool val);

    ///
    /// \brief getRadius получить радиус окружности в которую вписан заданный прямоугольник
    ///
    float getRadius(const QRectF &tmpRect);

    ///
    /// \brief getDegFromValue
    ///
    float getDegFromValue(float val);

    ///
    /// \brief setScaleFactor установить коэффициент масштаба
    ///
    void setScaleFactor(float val);

    ///
    /// \brief setThickness установить толщину линии
    ///
    void setThickness(float val);

    ///
    /// \brief setProportions задать соотношение ширины к высоте в виджете с данным item
    ///
    void setProportions(float wh);

//    QWidget *_parentWidget;
    QPushButton *_myPushButton;


    QColor   _colorSubstrate    {Qt::black};
    QColor   _colorItem         {Qt::black};
    QColor   _colorOutline      {Qt::white};
    QColor   _colorCornerBound  {Qt::darkRed};

    QColor   _colorShadowB      {Qt::black};
    QColor   _colorShadowW      {Qt::white};

    QColor   _colorKaracurtWhite  {255, 255, 255, 255};
    QColor   _colorKaracurtYellow {255, 255,  0 , 255};
    QColor   _colorKaracurtSubstrate { 0, 0,  0 , 128};
    QColor   _colorKaracurtShadow { 0 ,  0 ,  0 , 200};


    float    _thicknessOutline  {5};
    float    _thickness         {3};

    float    _scaleFactor       {1};

    float    _rPos              {0.5};
    float    _angle             {0.5};

    float    _minValue          {0};
    float    _maxValue          {100};
    float    _minDegree         {0};
    float    _maxDegree         {360};

    bool     _drawSubstrate     {false};
    bool     _drawOutline       {false};
    bool     _drawShadow        {false};

    float    _wh                {1};


signals:

};

#endif // BUTTONITEM_H

    

lineitem.cpp

#include "lineitem.h"

lineItem::lineItem(QPushButton *parent)
    : customButton(parent)
{

}

void lineItem::draw(QPainter *p)
{
    p->save();

    QPointF center = getCenterPoint(_rPos, _angle);
    float r = getRadius(_myPushButton->rect())*_scaleFactor;

    if(_drawSubstrate)
    {
        p->setBrush(QBrush(_colorSubstrate));
        p->drawEllipse(center,(int)(r), (int)(r));
    }

    p->translate(center);

    p->setPen(Qt::NoPen);
    p->setBrush(QBrush(_color));
    p->drawRect(-r/1.5, -r/1.5, r*1.34, r*1.34);


    QVector<QPointF> tmpPoints;
    tmpPoints.append(QPointF(0.0 - r*0.46 , 0.0 + r*0.2 ));
    tmpPoints.append(QPointF(0.0 - r*0.36 , 0.0 + r*0.2 ));

    tmpPoints.append(QPointF(0.0 - r*0.26 , 0.0 - r*0.15 ));
    tmpPoints.append(QPointF(0.0 - r*0.06 , 0.0 + r*0.45 ));

    tmpPoints.append(QPointF(0.0 + r*0.06 , 0.0 - r*0.4  ));
    tmpPoints.append(QPointF(0.0 + r*0.26 , 0.0 + r*0.25 ));

    tmpPoints.append(QPointF(0.0 + r*0.36 , 0.0 + r*0.1 ));
    tmpPoints.append(QPointF(0.0 + r*0.46 , 0.0 + r*0.1 ));

    QPainterPath path;
    path.addPolygon(tmpPoints);

    p->setBrush(Qt::NoBrush);
    p->setPen(QPen(_color_line, 2*_thickness, Qt::SolidLine));
    p->drawPath(path);

    p->restore();
}
    

lineitem.h

#ifndef LINEITEM_H
#define LINEITEM_H

#include "custombutton.h"

class lineItem : public customButton
{
public:
    lineItem();

    explicit lineItem(QPushButton *parent = nullptr);

    virtual void draw(QPainter * p) override final;

    private:

        QColor   _color        {220, 0, 0, 227};
        QColor   _color_line {255,255,255,255};
};
#endif // LINEITEM_H

Ответы (1 шт):

Автор решения: timob256

Вот тут дали отличный ответ :

https://blog.altuninvv.ru/программирование/qt5/виджеты/153-создаем-слайдер-скользящий-переключатель-slider-button-в-qt5

вот пример :

CMakeLists.txt

cmake_minimum_required(VERSION 3.5)

project(myButton3 VERSION 0.1 LANGUAGES CXX)

set(CMAKE_INCLUDE_CURRENT_DIR ON)

set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 COMPONENTS Widgets REQUIRED)
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)

set(PROJECT_SOURCES
        main.cpp
        mainwindow.cpp
        mainwindow.h
        qsliderbutton.cpp
        qsliderbutton.h
        mainwindow.ui
)

if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
    qt_add_executable(myButton3
        MANUAL_FINALIZATION
        ${PROJECT_SOURCES}
    )
# Define target properties for Android with Qt 6 as:
#    set_property(TARGET myButton3 APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
#                 ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
else()
    if(ANDROID)
        add_library(myButton3 SHARED
            ${PROJECT_SOURCES}
        )
# Define properties for Android with Qt 5 after find_package() calls as:
#    set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
    else()
        add_executable(myButton3
            ${PROJECT_SOURCES}
        )
    endif()
endif()

target_link_libraries(myButton3 PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)

set_target_properties(myButton3 PROPERTIES
    MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
)

if(QT_VERSION_MAJOR EQUAL 6)
    qt_finalize_executable(myButton3)
endif()

main.cpp

#include "mainwindow.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QVBoxLayout>
#include "qsliderbutton.h"

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;

    QSliderButton *sldBtn;
};
#endif // MAINWINDOW_H

mainwindows.cpp

#include "mainwindow.h"
#include "./ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    QVBoxLayout *vlay = new QVBoxLayout();
    QHBoxLayout *hlay1 = new QHBoxLayout();

    sldBtn =  new QSliderButton;
    hlay1->addWidget(sldBtn);

    hlay1->addStretch(1);
    vlay->addItem(hlay1);

    vlay->addStretch(1);
    ui->centralwidget->setLayout(vlay);
}

MainWindow::~MainWindow()
{
    delete ui;
}

qsliderbutton.h

#ifndef QSLIDERBUTTON_H
#define QSLIDERBUTTON_H

#include <QWidget>
#include <QMouseEvent>
#include <QDebug>


class QSliderButton : public QWidget {
    Q_OBJECT
public:    
    explicit QSliderButton(QWidget* parent);
    QSliderButton();


    int getStatus() const;
    void setStatus(int value);

    static const int off = 0;
    static const int on  = 1;

private:
    int status = 0;

protected:
    virtual void paintEvent(QPaintEvent *event);
    virtual QSize sizeHint() const;
    virtual void mousePressEvent(QMouseEvent * event);

};

#endif // QSLIDERBUTTON_H

qsliderbutton.cpp

#include "qsliderbutton.h"
#include <QPainter>

QSliderButton::QSliderButton(QWidget *parent)
{
    this->setParent(parent);
}

QSliderButton::QSliderButton()
{
}

int QSliderButton::getStatus() const
{
    return status;
}

void QSliderButton::setStatus(int value)
{
    status = value;
    repaint();
}

void QSliderButton::paintEvent(QPaintEvent *)
{
    QPainter painter(this);

    painter.setRenderHint(QPainter::Antialiasing, true);

    painter.setPen(QPen(QColor("#fff"), 0.1));

    QString bgColorTxt = "#ffffff";
    QColor bgColor = QColor(bgColorTxt);

    painter.setBrush(bgColor);

    painter.drawRoundedRect(QRectF(0, 0, 50, 20),10,10);

    QLinearGradient linearGradBtn(QPointF(0, 0),QPointF(16, 16));

    QString onColor = "#444";
    QColor mainColorOn = QColor(onColor);
    QColor subColorOn = QColor(onColor);
    subColorOn.setHsl(0,100,95,0);


    if (this->status==QSliderButton::on) {
        QLinearGradient linearGrad(QPointF(32, 2), QPointF(46, 16));
        linearGrad.setColorAt(0, subColorOn);
        linearGrad.setColorAt(1, mainColorOn);

        painter.setBrush(linearGrad);

        painter.drawEllipse( QRectF(30, 2, 17, 16) );
    } else {
        QLinearGradient linearGrad(QPointF(2, 2), QPointF(16, 16));
        linearGrad.setColorAt(0, subColorOn);
        linearGrad.setColorAt(1, mainColorOn);

        painter.setBrush(linearGrad);

        painter.drawEllipse( QRectF(2, 2, 16, 16) );
    }
}
QSize QSliderButton::sizeHint() const {
    return QSize(50, 20);
}

void QSliderButton::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton ) {
        if (this->status==QSliderButton::on) {
            this->status = QSliderButton::off;
        } else {
            this->status = QSliderButton::on;
        }
        repaint();
    }
}

введите сюда описание изображения

→ Ссылка