简体   繁体   中英

QT5 Change integer text smoothly

I don't know do the termin of that technology is smoothly but is sound most understandable. So let's explain what I want.

I have two buttons: One + and One - and in the middle one number 10.

My range is between 1 and 300. I don't want the user to click 289 times to go to 300. I want when user keep for my case finger on + button to go for example 5 seconds. And change it really fast.

Is it possible to implemented with clicked SLOT of the QPushButton or I need to find another solution and write custom widget. And do is have some function or widget already implemented

Create a widget containing two buttons (add and sub) and a label. Use QPushButton::pressed signal to know when a button is pressed and QPushButton::released .

When a button is pressed, define the direction (sub or add) and trigger a timer with a high initial interval. Each time the timer is elapsed ( QTimer::timeout ), increment/decrement the value regarding to the direction and decrease the interval of your timer.

A quick example:

class SpinBox: public QWidget
{
    Q_OBJECT
public:
    SpinBox(QWidget* parent=nullptr): QWidget(parent),
        value(0),
        min(0),
        max(500),
        direction(Forward),
        timer(new QTimer(this)),
        addButton(new QPushButton("+")),
        subButton(new QPushButton("-")),
        text(new QLabel("0"))
    {
        timer->setInterval(500);
        connect(addButton, &QPushButton::pressed, this, &SpinBox::forward);
        connect(subButton, &QPushButton::pressed, this, &SpinBox::backward);
        connect(addButton, &QPushButton::released, timer, &QTimer::stop);
        connect(subButton, &QPushButton::released, timer, &QTimer::stop);

        connect(timer, &QTimer::timeout, this, &SpinBox::updateValue);

        QHBoxLayout* layout = new QHBoxLayout(this);
        layout->addWidget(subButton);
        layout->addWidget(text);
        layout->addWidget(addButton);
    }
private slots:
    void updateValue()
    {
        if (direction == Forward)
        {
            ++value;
            if (value == max)
                timer->stop();
        }
        else
        {
            --value;
            if (value == min)
                timer->stop();
        }
        text->setText(QString::number(value));
        timer->setInterval(std::max(10.0, float(timer->interval()) * 0.9));
        update();
    }


    void backward()
    {
        direction = Backward;
        timer->start();
    }

    void forward()
    {
        direction = Forward;
        timer->start();
    }
private:
    enum Direction
    {
        Forward,
        Backward
    };

    int value;
    int min;
    int max;
    Direction direction;
    QTimer* timer;
    QPushButton* addButton;
    QPushButton* subButton;
    QLabel* text;
};

You can also do the same thing with a plain widget by using mousePressEvent and mouseReleaseEvent . It could be useful for custom-style widgets and avoid the issues related to the inner layout:

class SpinBox: public QWidget
{
    Q_OBJECT
public:
    SpinBox(QWidget* parent=nullptr): QWidget(parent),
        value(0),
        min(0),
        max(500),
        direction(Forward),
        timer(new QTimer(this))
    {
        timer->setInterval(500);
        connect(timer, &QTimer::timeout, this, &SpinBox::updateValue);
    }
private slots:
    void updateValue()
    {
        if (direction == Forward)
        {
            ++value;
            if (value == max)
                timer->stop();
        }
        else
        {
            --value;
            if (value == min)
                timer->stop();
        }
        timer->setInterval(std::max(10.0, float(timer->interval()) * 0.9));
        update();
    }

private:
    enum Direction
    {
        Forward,
        Backward
    };
    virtual void paintEvent(QPaintEvent* event) override
    {
        QPainter painter(this);
        painter.setPen(Qt::NoPen);
        painter.setBrush(Qt::gray);
        painter.drawRect(subButtonRect());
        painter.drawRect(addButtonRect());
        painter.setPen(Qt::black);
        painter.setFont(QFont("Helvetica", 20));
        painter.drawText(addButtonRect(), Qt::AlignCenter, "+");
        painter.drawText(subButtonRect(), Qt::AlignCenter, "-");
        painter.drawText(textRect(), Qt::AlignCenter, QString::number(value));
    }

    QRect addButtonRect()
    {
        return QRect(width() - 30, 0, 30, height());
    }

    QRect subButtonRect()
    {
        return QRect(0, 0, 30, height());
    }

    QRect textRect()
    {
        return QRect(30, 0, width() - 30 * 2, height());
    }

    virtual void mousePressEvent(QMouseEvent* event) override
    {
        if (addButtonRect().contains(event->pos()))
        {
            direction = Forward;
        }
        else if (subButtonRect().contains(event->pos()))
        {
            direction = Backward;
        }
        else
        {
            return;
        }
        timer->start();
    }

    virtual void mouseReleaseEvent(QMouseEvent* event) override
    {
        timer->stop();
        timer->setInterval(500);
    }

    int value;
    int min;
    int max;
    Direction direction;
    QTimer* timer;
};

This functionality is already implemented in Qt.

Enable the autoRepeat property of your QPushButton . It will trigger the clicked signal of your button periodically while it is pressed.

Just connect a slot to it as usual.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM