3

I need to create a button which has three states:

  • unclicked
  • intermediate
  • clicked

The logic I want to implement with this button is that whenever this button is clicked, I want the system to go to the intermediate state and wait for an event.

In other way when the state transition is unclicked --> intermediate -- > clicked and then clicked --> intermediate -->unclicked.

Does Qt support implementing this kind of button? If so, how?

cbuchart
  • 10,847
  • 9
  • 53
  • 93
lferasu
  • 185
  • 2
  • 10
  • 2
    what about using a normal button and giving it a different color (or change appearance somehow) for the intermediate state? – 463035818_is_not_an_ai Jul 11 '17 at 09:28
  • If you want to just iterate through all states then just create a button and inside create a state value of 0 then with each click just shift 1 to the left or to the right: `clicked -> state <<=1 | state >>=1` then you have 3 states with 0 being unclicked, 1 is indeterminate, 2 being clicked – mrogal.ski Jul 11 '17 at 09:32
  • Even a possible try is to reimplement QPushButton – saeed Jul 11 '17 at 12:00

1 Answers1

6

The nearest you have is QCheckBox. It already has a property for it: QCheckBox::setTristate:

auto yourCheckBoxButton = new QCheckBox("Tristate button");
yourCheckBoxButton->setTristate(true);

You can do it on the Designer too (it is at the end of the properties list).

If you don't want to use a QCheckBox, a stylesheet and a custom property that is modified each time the button is pressed can do it:

auto pushButton = new QPushButton("Tristate button");
pushButton->setProperty("state", 0);
pushButton->setProperty("state-step", 1); // change to next state, 1 or -1
pushButton->setStyleSheet("QPushButton[state=\"0\"] { background: red; }"
                          "QPushButton[state=\"1\"] { background: grey; }"
                          "QPushButton[state=\"2\"] { background: blue; }");
connect(pushButton, &QPushButton::clicked, [ = ](bool) {
  const int state = pushButton->property("state").toInt();
  const int step = state == 0 ? 1 :
                   state == 2 ? -1 : pushButton->property("state-step").toInt();
  pushButton->setProperty("state", state + step);
  pushButton->setProperty("state-step", step); // update in case it changed

  // Changing the property is not enough to choose a new style from the stylesheet,
  //  it is necessary to force a re-evaluation
  pushButton->style()->unpolish(pushButton);
  pushButton->style()->polish(pushButton);
});

Other more elaborated options would be to use a QProxyStyle or to re-implement the QPushButton class itself.

cbuchart
  • 10,847
  • 9
  • 53
  • 93
  • The tri-state is changing state like `A -> B -> C -> A`... if I remember well, isn't it ? Not `A -> B -> C -> B -> A` like it is asked. – ymoreau Jul 11 '17 at 14:42
  • @ymoreau thanks for pointing this out, I've updated the answer to cover it – cbuchart Jul 11 '17 at 19:53