1

I have a QPushButton, I want to make it "pushed in" so I call

btn->setDown(true);

But this doesn't update the appearance or the behavior of the button (it's still raised, and pressable).

This happens when I call the command from a general function, but when I call it from a function that is triggered when it's pressed (by binding a slot to its clicked() signal).

The value of the property down is true, as expected, but the behaviour doesn't match. What is missing?

SIMEL
  • 8,745
  • 28
  • 84
  • 130
  • 1
    Maybe there is some sort of `refresh` function you can use to update the button? – Rakete1111 Jul 23 '17 at 15:47
  • @Rakete1111, I tried to call `update()` after `setDown()`, it didn't work. – SIMEL Jul 23 '17 at 15:48
  • I couldn't confirm your observation. It's possible that I missed your specific conditions. Please, feel free to take my sample code, to adapt it to your specific problem, and edit your question. – Scheff's Cat Jul 23 '17 at 16:54
  • May be, it's worth to mention the platform, the Qt version, and may be the default Qt style which is used. – Scheff's Cat Jul 23 '17 at 17:00
  • The platform is wondows 7, written in VS 2010, QT version is 4.8.1 – SIMEL Jul 23 '17 at 17:11
  • Try setCheckable (bool) – Vahagn Avagyan Jul 23 '17 at 22:46
  • And where you check the isDown ()??? it will return the false always if the isDown call from the inside of the clicked slot – Vahagn Avagyan Jul 23 '17 at 22:52
  • @SIMEL I believe, you platform is similar to mine. (I probably renders with `windowsvista` style as well if you didn't change it.) Btw. I don't know about Qt 4 (as I started with Qt 5). However, that button stuff is not new and probably not changed between Qt 4 and Qt 5. – Scheff's Cat Jul 24 '17 at 06:25
  • @SIMEL I'm such a git: I didn't notice that you're using Qt 4 (until I wrote my last comment). I made an update of my sample code. However, the behavior hasn't changed... Btw. Now, I'm once more happy that I started with Qt 5 (with the new signal-slot concept). – Scheff's Cat Jul 24 '17 at 07:23
  • @Rakete1111 I had a look into [source code of `setDown()`](https://code.woboq.org/qt5/qtbase/src/widgets/widgets/qabstractbutton.cpp.html#_ZN15QAbstractButton7setDownEb) (at woboq.org). The call of `refresh()` is already there. – Scheff's Cat Jul 24 '17 at 09:03
  • @SIMEL Out of curiosity, I tried what happens if the button is disabled: `QPushButton::setDown()` has no visual effect if the button is not enabled. Actually, you wrote that the button reacts to mouse input properly. Thus, it shouldn't be disabled. I'm out of ideas... – Scheff's Cat Jul 24 '17 at 09:16

3 Answers3

1

I did what you described in an MCVE. (Strictly speaking: I did it how I understood what you described...)

This is my sample testQPushButtonSetDown.cc:

// Qt header:
#include <QtWidgets>

#if QT_VERSION_MAJOR < 5
#define USE_OLD_SIGNAL_SLOT
#endif // QT_VERSION_MAJOR < 5

#ifdef USE_OLD_SIGNAL_SLOT
#include "PushButton.h"
#else // (not) USE_OLD_SIGNAL_SLOT
#define PushButton QPushButton
#endif // USE_OLD_SIGNAL_SLOT

int main(int argc, char **argv)
{
  qDebug() << QT_VERSION_STR;
  // main application
#undef qApp // undef macro qApp out of the way
  QApplication qApp(argc, argv);
  qDebug() << QApplication::style()->objectName();
  // setup GUI
  QWidget qWin;
  QHBoxLayout qBox;
  QCheckBox qTglBtn(QString::fromUtf8("Force Button Down"));
  qBox.addWidget(&qTglBtn);
  PushButton qBtn(QString::fromUtf8("A Button"));
  qBtn.setFocusPolicy(Qt::StrongFocus); // requirement of OP
  qBox.addWidget(&qBtn);
  qWin.setLayout(&qBox);
  qWin.show();
  // install signal handlers
#ifdef USE_OLD_SIGNAL_SLOT
  QObject::connect(&qTglBtn, SIGNAL(toggled(bool)),
    &qBtn, SLOT(setDown(bool)));
#else  // (not) USE_OLD_SIGNAL_SLOT
  QObject::connect(&qTglBtn, &QCheckBox::toggled,
    &qBtn, &PushButton::setDown);
#endif // USE_OLD_SIGNAL_SLOT
  // run application
  return qApp.exec();
}

Header file PushButton.h to override QPushButton for Qt 4:

#ifndef PUSH_BUTTON_H
#define PUSH_BUTTON_H

#include <QPushButton>

class PushButton: public QPushButton {
  Q_OBJECT
  public:
    PushButton(const QString &label, QWidget *pQParent = nullptr):
      QPushButton(label, pQParent)
    { }
  public slots:
    void setDown(bool down) { QPushButton::setDown(down); }
};

#endif // PUSH_BUTTON_H

Note:

Unfortunately, QPushButton::setDown() is not a slot and thus cannot be used as such in Qt 4 like signals. Thus, PushButton is derived from QPushButton only to make setDown() a slot.

I compiled it in VS2013 and tested on Windows 10 (64 bit).

Snapshot of testQPushButtonSetDown (button not forced down)

Snapshot of testQPushButtonSetDown (button forced down)

It seems to work like expected.

I doesn't look like "The button is down." but this his how it's rendered on my Windows 10 where the default Qt style ("windowsvista") mimics the Windows look&feel. At least, you can see a visible change of the button when the check box is toggled. Beside of this, it has the exact look when button is clicked by mouse.


Note:

Calling QPushButton::setDown() does not emit a pressed() or clicked() signal.

From Qt doc. (emphasizing by me):

If this property is true, the button is pressed down. The signals pressed() and clicked() are not emitted if you set this property to true.

If this is intended, you had to use another method instead: QPushButton::click()

This is described in the Qt doc. of QAbstractButton (from which it is inherited in QPushButton):

QAbstractButton provides four signals:

  1. pressed() is emitted when the left mouse button is pressed while the mouse cursor is inside the button.

  2. released() is emitted when the left mouse button is released.

  3. clicked() is emitted when the button is first pressed and then released, when the shortcut key is typed, or when click() or animateClick() is called.

  4. toggled() is emitted when the state of a toggle button changes.

Scheff's Cat
  • 19,528
  • 6
  • 28
  • 56
  • There is one thing that I noticed that is different here. My widget was built using the designer, and in it the focus for the buttons was set as `strongFocus` while you didn't set the focus so it's defaulted to `noFocus`. Could it be that this is the difference? (I wont have access to the test environment for a few days, so I can't check if this was the issue). – SIMEL Jul 24 '17 at 08:26
  • @SIMEL I made an update `qBtn.setFocusPolicy(Qt::StrongFocus);` but the described behavior (concerning `setDown()`) didn't change. Btw. thanks for the `setFocusPolicy()` hint. I haven't even noticed about that before - I learnt something new. About Qt Designer, I cannot tell anything - have never used it. – Scheff's Cat Jul 24 '17 at 08:39
0

You can use an EventFilter to drop all mouse press events from this button.

yourButton->installEventFilter(this); // this = MainWindow, change to your needs

bool MainWindow::eventFilter(QObject *obj, QEvent *event)    
{
    if (event->type() == QEvent::MouseButtonPress)
    {
        QPushButton *button = static_cast<QPushButton *>(obj);
        if (button == yourButton)
            if (button->isDown())
                return true;
    }
    // standard event processing
    return QObject::eventFilter(obj, event);
}

After another control set down to false, everthing works as before.

Fritz
  • 359
  • 3
  • 9
-3

A button must be set checkable to retain its state after losing the focus.

Try setChecked(TRUE) on the button before calling setDown().

Gene
  • 1
  • A. it doesn't. B. checkable is a different behavior that the one I want, I don't want it to release when I click it again, I want it to release only when I tell it (when another button is pressed). – SIMEL Jul 23 '17 at 16:07