1

When I press the [?] "What's This?" button in the title bar, which signal should I check for?

   Qt::WindowFlags flags;

   flags |= Qt::CustomizeWindowHint;    // Remove all previous windows hints

   // Restore previous hints
   flags |= Qt::Window;
   flags |= Qt::WindowTitleHint;
   flags |= Qt::WindowSystemMenuHint;
   //flags |= Qt::WindowMinimizeButtonHint;    // Hides [?]
   //flags |= Qt::WindowMaximizeButtonHint;    // Hides [?]
   flags |= Qt::WindowCloseButtonHint;

   // Add new hints
   flags |= Qt::WindowContextHelpButtonHint;

   setWindowFlags(flags);

   connect(this, ???, this, MainWindow::TestSlot());
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
Pietro
  • 12,086
  • 26
  • 100
  • 193
  • 1
    There's no signal, but a more complex system based on events. See https://doc.qt.io/qt-5/qwidget.html#whatsThis-prop https://doc.qt.io/qt-5/qhelpevent.html https://doc.qt.io/qt-5/qwhatsthis.html – peppe May 19 '17 at 15:16
  • @peppe: What I need to do is to call a function (e.g. write a log message) when the [?] button is pressed. How can I do it without signals? Is it possible at all? – Pietro May 19 '17 at 15:28
  • Why don't you start by reading [the documentation](http://doc.qt.io/qt-5/qwhatsthis.html)? – Jesper Juhl May 19 '17 at 16:00
  • @Kuba Ober - Well, it's pretty clear when you read it that there are *no signals* emitted.. – Jesper Juhl May 19 '17 at 16:04
  • @Kuba Ober - of course not; but it's a pretty big hint that that's not the way to go for a solution and the title of the question makes it pretty clear that OP has not bothered to read the docs; otherwise the question would not have been about "what signal".. – Jesper Juhl May 19 '17 at 16:13
  • @JesperJuhl - It is not so clear: there is simply no mention of signals; they do not say that signals are not emitted. Considering that signals are the standard tool with widgets, I just took it for granted, by mistake. – Pietro May 19 '17 at 16:15
  • Sometimes things are in the documentation, just not where you expect. Usually the `QEvent` documentation is a catch-all place to look for notification of things happening that aren't otherwise signaled or mentioned :) In this case, one finds the `EnterWhatsThisMode` event and bingo :) – Kuba hasn't forgotten Monica May 19 '17 at 16:52

1 Answers1

1

I need to [...] call a function (e.g. write a log message) when the [?] button is pressed.

The top-level window receives the QEvent::EnterWhatsThisMode and QEvent::LeaveWhatsThisMode events when the What's This mode is entered and left, respectively.

When a widget receives the event, you can convert the event to a signal e.g. using an event signaler installed on that widget.

Alternatively, if you want to catch the events on all windows automatically, without installing the signaler on each top-level widget, you can install the signaler on the QApplication object itself.

Below is a complete example:

// https://github.com/KubaO/stackoverflown/tree/master/questions/whatsthis-bypass-44073556
#include <QtWidgets>

// See https://stackoverflow.com/a/32027028/1329652
class WhatsThisSignaler : public QObject {
   Q_OBJECT
   bool eventFilter(QObject * obj, QEvent * ev) override {
      if (!obj->isWidgetType())
         return false;
      auto widget = static_cast<QWidget*>(obj);
      if (!widget->isWindow())
         return false;
      switch (ev->type()) {
      case QEvent::EnterWhatsThisMode:
      case QEvent::LeaveWhatsThisMode:
         emit whatsThisEvent(widget, ev);
         break;
      default:
         break;
      }
      return false;
   }
public:
   Q_SIGNAL void whatsThisEvent(QWidget *, QEvent *);
   WhatsThisSignaler(QObject * parent = {}) : QObject(parent) {}
   void installOn(QWidget * widget) {
      widget->installEventFilter(this);
   }
   void installOn(QCoreApplication * app) {
      app->installEventFilter(this);
   }
};

// See https://stackoverflow.com/q/22535469/1329652
template<typename EnumType> QString toName(EnumType enumValue)
{
    auto * enumName = qt_getEnumName(enumValue);
    auto * metaObject = qt_getEnumMetaObject(enumValue);
    QString name;
    if (metaObject) {
        auto enumIndex = metaObject->indexOfEnumerator(enumName);
        name = metaObject->enumerator(enumIndex).valueToKey(enumValue);
    }
    if (name.isEmpty())
       name = QString::number((int)enumValue);
    return name;
}

int main(int argc, char ** argv) {
   QApplication app{argc, argv};
   WhatsThisSignaler sig;
   QPlainTextEdit w;
   w.setWindowFlags(Qt::WindowContextHelpButtonHint | Qt::WindowCloseButtonHint);
   w.setMinimumSize(200, 200);
   w.setReadOnly(true);
   w.show();
   sig.installOn(&w);
   QObject::connect(&sig, &WhatsThisSignaler::whatsThisEvent, &w, [&w](QWidget*widget, QEvent*ev){
      w.appendPlainText(QStringLiteral("%1(0x%2) \"%3\" QEvent::%4")
                        .arg(widget->metaObject()->className())
                        .arg((uintptr_t)widget, 0, 16)
                        .arg(widget->objectName())
                        .arg(toName(ev->type())));
   });
   return app.exec();
}

#include "main.moc"
Community
  • 1
  • 1
Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
  • It now works fine. Thank you. Just a detail: once I click on the [?] button, the browser opens as expected, but when I move the mouse pointer back on the Qt dialog, this looks like a red circle with a bar, until I click again. Do you know if it possible to avoid this last behaviour? – Pietro May 22 '17 at 16:09
  • 1
    The "no entry" circle indicates that there is no valid What's This target. Since you're not using the What's This mode at all, you should exit it immediately by calling `QWhatsThis::leaveWhatsThisMode()`. I must bring up the fact that reuse of the What's This button for F1 is not a good idea, since the users expect What's This mode to be what its name implies: a way to point on UI elements to get information about them. The button is not a general "show me help" button. And finally, it's style-dependent. There's no What's This button on Mac and some other platforms and/or styles! – Kuba hasn't forgotten Monica May 22 '17 at 19:52
  • 1
    TL;DR: What's This is a Windows-ism that **is expected to have a certain functionality**. What you're doing is providing bad user experience on Windows by reusing the button for something **it was never meant to do**. That's why it's so circuitous in Qt: you're not supposed to be doing any of it, and you should educate whoever came up with software specification that they're very much mistaken. – Kuba hasn't forgotten Monica May 22 '17 at 19:54