2
\$\begingroup\$

I have below code for implement toggle button.

1

After including below code, processing power consumed over 90% in my embedded application. Is there any way to reduce this processing power.


ToggleButton.h

#ifndef TOGGLEBUTTON_H
#define TOGGLEBUTTON_H

#include <QtWidgets/QAbstractButton>


class QPropertyAnimation;

class ToggleButton :public QAbstractButton
{
    Q_OBJECT
        Q_PROPERTY(int mOffset READ offset WRITE setOffset);
public:
    explicit ToggleButton(int trackRadius, int thumbRadius, QWidget* parent = nullptr);
    ~ToggleButton();

    QSize sizeHint() const override;

protected:
    void paintEvent(QPaintEvent *) override;
    void resizeEvent(QResizeEvent*) override;
    void mouseReleaseEvent(QMouseEvent  *) override;
    void enterEvent(QEvent *event) override;
    void setChecked(bool checked);

    int offset();
    void setOffset(int value);

private:
    qreal mOffset;
    qreal mBaseOffset;
    qreal mMargin;
    qreal mTrackRadius;
    qreal mThumbRadius;
    qreal mOpacity;
    QPropertyAnimation* mAnimation;

    QHash<bool, qreal> mEndOffset;
    QHash<bool, QBrush> mTrackColor;
    QHash<bool, QBrush> mThumbColor;
    QHash<bool, QColor> mTextColor;
    QHash<bool, QString> mThumbText;

};

#endif // TOGGLEBUTTON_H

ToggleButton.cpp

#include "toggleButton.h"
#include <QtCore/QEvent>
#include <QtCore/QCoreApplication>
#include <QtCore/QPropertyAnimation> 
#include <QtGui/QPainter> 
#include <QtGui/QMouseEvent> 

///<summary>
/// Toggle button has 2 different design. In the first design, if the ball (thumb) radius is 
/// larger than the slide (track) radius, a flat ball slides and colors from the slide according to 
/// the on / off situation. In the second design, if the ball radius is smaller than the slide radius, 
/// the ball moves according to the on / off status inside the slide and includes the check and uncheck marks.
///</summary>
ToggleButton::ToggleButton(int trackRadius, int thumbRadius, QWidget* parent)
    : QAbstractButton(parent)
{
    setCheckable(true);
    setSizePolicy(QSizePolicy(QSizePolicy::Policy::Fixed, QSizePolicy::Policy::Fixed));
    mTrackRadius = trackRadius;
    mThumbRadius = thumbRadius;
    mAnimation = new QPropertyAnimation(this);
    mAnimation->setTargetObject(this);

    mMargin = 0 > (mThumbRadius - mTrackRadius) ? 0 : (mThumbRadius - mTrackRadius);
    mBaseOffset = mThumbRadius > mTrackRadius ? mThumbRadius : mTrackRadius;
    mEndOffset.insert(true, 4 * mTrackRadius + 2 * mMargin - mBaseOffset); // width - offset
    mEndOffset.insert(false, mBaseOffset);
    mOffset = mBaseOffset;
    QPalette palette = this->palette();

    if (mThumbRadius > mTrackRadius)
    {
        mTrackColor.insert(true, palette.highlight());
        mTrackColor.insert(false, palette.dark());
        mThumbColor.insert(true, palette.highlight());
        mThumbColor.insert(false, palette.light());
        mTextColor.insert(true, palette.highlightedText().color());
        mTextColor.insert(false, palette.dark().color());
        mThumbText.insert(true, "");
        mThumbText.insert(false, "");
        mOpacity = 0.5;
    }
    else
    {
        mTrackColor.insert(true, palette.highlight());
        mTrackColor.insert(false, palette.dark());
        mThumbColor.insert(true, palette.highlightedText());
        mThumbColor.insert(false, palette.light());
        mTextColor.insert(true, palette.highlight().color());
        mTextColor.insert(false, palette.dark().color());
        mThumbText.insert(true, QChar(0x2714)); // check character
        mThumbText.insert(false, QChar(0x2715)); // uncheck character
        mOpacity = 1.0;
    }
}


ToggleButton::~ToggleButton()
{
    delete mAnimation;
}

QSize ToggleButton::sizeHint() const
{
    int w = 4 * mTrackRadius + 2 * mMargin;
    int h = 2 * mTrackRadius + 2 * mMargin;

    return QSize(w, h);
}

void ToggleButton::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    QPainter::RenderHints m_paintFlags = QPainter::RenderHints(QPainter::Antialiasing |
        QPainter::TextAntialiasing);
    p.setRenderHints(m_paintFlags, true);
    p.setPen(Qt::NoPen);
    bool check = isChecked();
    qreal trackOpacity = mOpacity;
    qreal textOpacity = 1.0;
    qreal thumbOpacity = 1.0;
    QBrush trackBrush;
    QBrush thumbBrush;
    QColor textColor;

    if (this->isEnabled())
    {

        trackBrush = mTrackColor[check];
        thumbBrush = mThumbColor[check];
        textColor = mTextColor[check];
    }
    else
    {
        trackOpacity *= 0.8;
        trackBrush = this->palette().shadow();
        thumbBrush = this->palette().mid();
        textColor = this->palette().shadow().color();
    }

    p.setBrush(trackBrush);
    p.setOpacity(trackOpacity);
    p.drawRoundedRect(mMargin, mMargin, width() - 2 * mMargin, height() - 2 * mMargin, mTrackRadius, mTrackRadius);

    p.setBrush(thumbBrush);
    p.setOpacity(thumbOpacity);
    p.drawEllipse(mOffset - mThumbRadius, mBaseOffset - mThumbRadius, 2 * mThumbRadius, 2 * mThumbRadius);

    p.setPen(textColor);
    p.setOpacity(textOpacity);
    QFont font = p.font();
    font.setPixelSize(1.5*mThumbRadius);
    p.setFont(font);


    // Since the antialiasasing provided by the drawText function is incompetent,
    // DrawPath function preferred. But since the drawPath function is not capable of aligment,
    // Pixel offsets calculated to provide aligment.
    QPainterPath textPath;
    qreal pixelOffset = (qreal)mThumbRadius * (1 - 1 / 1.414);
    textPath.addText(mOffset - mThumbRadius + pixelOffset, mBaseOffset + mThumbRadius - pixelOffset, font, mThumbText.value(check));
    p.drawPath(textPath);
   mAnimation->setDuration(100);
   if(mAnimation->state() != mAnimation->Running)
   {
     mAnimation->setPropertyName("mOffset");
   }
   mAnimation->setStartValue(mOffset);
   mAnimation->setEndValue(mEndOffset[isChecked()]);
   mAnimation->start();


    /*p.drawText(QRectF(mOffset - mThumbRadius,
        mBaseOffset - mThumbRadius,
        2 * mThumbRadius,
        2 * mThumbRadius),
        Qt::AlignCenter,
        mThumbText.value(check));*/
}

void ToggleButton::resizeEvent(QResizeEvent* e)
{
    QAbstractButton::resizeEvent(e);
    mOffset = mEndOffset.value(isChecked());
}

void ToggleButton::mouseReleaseEvent(QMouseEvent  *e)
{
    QAbstractButton::mouseReleaseEvent(e);
    if (e->button() == Qt::LeftButton)
    {
        mAnimation->setDuration(120);
        mAnimation->setPropertyName("mOffset");
        mAnimation->setStartValue(mOffset);
        mAnimation->setEndValue(mEndOffset[isChecked()]);
        mAnimation->start();
    }
}

void ToggleButton::enterEvent(QEvent * event)
{
    setCursor(Qt::PointingHandCursor);
    QAbstractButton::enterEvent(event);
}

void ToggleButton::setChecked(bool checked)
{
    QAbstractButton::setChecked(checked);
    mOffset = mEndOffset.value(checked);
}

int ToggleButton::offset()
{
    return mOffset;
}

void ToggleButton::setOffset(int value)
{
    mOffset = value;
    update();
}

main.cpp

#include "toggleButton.h"
#include <QtWidgets/QApplication>
#include <QtWidgets/QHBoxLayout>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget *widget = new QWidget;
    widget->setWindowFlags(Qt::FramelessWindowHint);
    QHBoxLayout layout;
    widget->setLayout(&layout);
    ToggleButton *toggleButton1 = new ToggleButton(10, 8);
    ToggleButton *toggleButton2 = new ToggleButton(10, 12);
    layout.addWidget(toggleButton1);
    layout.addWidget(toggleButton2);
    widget->show();
    return a.exec();
}
\$\endgroup\$
5
  • 2
    \$\begingroup\$ Have you profiled your code to find which functions are consuming the most CPU time? This is generally the first step in improving performance. If you are on Linux one of the most common profiling tools is gprof. \$\endgroup\$ Commented Sep 8, 2020 at 12:52
  • 1
    \$\begingroup\$ I agree with @pacmaninbw that profiling this is the best way to work out what the bottleneck is. Have a look at gamma-ray doc.qt.io/GammaRay/gammaray-getting-started.html which is a tool for inspecting the internals of qt apps. \$\endgroup\$ Commented Sep 8, 2020 at 16:34
  • 1
    \$\begingroup\$ I got the solution by profiling. Thank you for commenting. \$\endgroup\$ Commented Sep 9, 2020 at 8:44
  • \$\begingroup\$ You are welcome. You can improve your question by posting your findings, or you could delete the question. \$\endgroup\$ Commented Sep 10, 2020 at 13:07
  • \$\begingroup\$ Or post an answer to your own question. \$\endgroup\$ Commented Sep 11, 2020 at 16:07

1 Answer 1

1
\$\begingroup\$

It takes more processing due to mAnimation inside paintEvent() method.. So remove Create animation on from paintEvent().

generate animation inside mouseReleaseEvent() method only..

 mAnimation->setDuration(100);
 if(mAnimation->state() != mAnimation->Running)
 {
    mAnimation->setPropertyName("mOffset");
 }
 mAnimation->setStartValue(mOffset);
 mAnimation->setEndValue(mEndOffset[isChecked()]);
 mAnimation->start();
\$\endgroup\$

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.