Focus

Summary
  • Tab key received in QWidget::event().

  • event() calls focusNextPrevChild() on itself.

  • focusNextPrevChild() calls parentWidget()→focusNextPrevChild if this is not a top level window (so it gets called repeatedly till a window is found).

  • On the window widget there is no parent to find, so focusNextPrevChild() finds the next focusable children with focusNextPrevChild_helper.

  • Focus is set on said widget via QWidget::setFocus.

First, a tab key press is processed on QWidget::event:

case QEvent::KeyPress: {
    QKeyEvent *k = (QKeyEvent *)event;
    bool res = false;
    if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
        if (k->key() == Qt::Key_Backtab
            || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
            res = focusNextPrevChild(false);
        else if (k->key() == Qt::Key_Tab)
            res = focusNextPrevChild(true);
        if (res)
            break;
    }
    keyPressEvent(k);

This just calls focusNextPrevChild on itself. That is, a widget controls what to do to pass the focus, because that function can be reimplemented, and do something special. The example that such function gives is a rich text browser which has the focus, and receives a tab press. That should instead highlight the first link, then the second, etc. Only when the last link in the browser is selected, the tab key should move the focus forward.

The focusNextPrevChild being called by the widget with the focus might seem odd, and rightfully so. Normally we see the focus being passed to a sibling widget, not to a child one. For example, the OK/Cancel buttons in a dialog need to pass back and forth the focus with tab and backtab. But none have children, and they are indeed, siblings. What gives? Why "child" in the name of the function?

The first lines of the focusNextPrevChild function tell us how that’s possible:

bool QWidget::focusNextPrevChild(bool next)
{
    QWidget* p = parentWidget();
    bool isSubWindow = (windowType() == Qt::SubWindow);
    if (!isWindow() && !isSubWindow && p)
        return p->focusNextPrevChild(next);

So the typical widget doesn’t normally change the focus itself: it calls its parent to fulfill the request. And the parent could call the grandparent, and so on, till the a window is found, and that one top level widget actually changes the focus. Which is done in the next lines of the function (partially simplified):

bool wrappingOccurred = false;
QWidget *w = QApplicationPrivate::focusNextPrevChild_helper(this, next,
                                                            &wrappingOccurred);
if (!w) return false;
Qt::FocusReason reason = next ? Qt::TabFocusReason : Qt::BacktabFocusReason;
/* If we are about to wrap the focus chain, give the platform
 * implementation a chance to alter the wrapping behavior.  This is
 * especially needed when the window is embedded in a window created by
 * another process.
 */
if (wrappingOccurred) {
    // ...
}
w->setFocus(reason);
return true;

So the bulk of the decision on which widget is the right one is done by that helper in QApplicationPrivate (remember that this is called from QWidget). But the details of what happens is right there: it just calls w→setFocus on the wanted one. A reimplementation of focusNextPrevChild just needs to do that.

What to do when wrappingOccurred is true is not important. As the comment says, seems necessary for a fairly involved case of embedding a window in another application.

Let’s now look at focusNextPrevChild_helper, a helper function which seems weird to exist on the QApplicationPrivate. But the comment on top of it tells us the alleged reason:

/*!internal
* Helper function that returns the new focus widget, but does not set the focus reason.
* Returns \nullptr if a new focus widget could not be found.
* Shared with QGraphicsProxyWidgetPrivate::findFocusChild()
*/
QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next,
                                                        bool *wrappingOccurred)

So the function is supposedly shared between widgets and the graphics view framework. The mentioned function in QGraphicsProxyWidgetPrivate, however, has this comment:

Some of the logic is shared with QApplicationPrivate::focusNextPrevChild_helper

And it actually doesn’t use focusNextPrevChild_helper, so in practice, the helper is not shared as claimed (as of Qt 5.15). The focusNextPrevChild_helper is called from QWidget::focusNextPrevChild and QApplication::setActiveWindow instead.

But let’s finally check what it does:

QWidget *QApplicationPrivate::focusNextPrevChild_helper(QWidget *toplevel, bool next,
                                                        bool *wrappingOccurred)
{
    uint focus_flag = qt_tab_all_widgets() ? Qt::TabFocus : Qt::StrongFocus;
QWidget *f = toplevel->focusWidget();
if (!f)
    f = toplevel;

The first thing is deciding between TabFocus and StrongFocus. Later the function will iterate through widgets, and will obviously skip the ones with Qt::NoFocus. But it will only consider the ones with the right focus flag, where "right" is decided by qt_tab_all_widgets, which is just a helper that returns:

QGuiApplication::styleHints()->tabFocusBehavior() == Qt::TabFocusAllControls;

For simplicity, just consider focus_flag == Qt::TabFocus, which will be used later to find widgets compatible with this flag.

The next lines decide on which is the focused widget, and are equivalent to:

QWidget * const f = toplevel->focusWidget() ? toplevel->focusWidget() : toplevel;

Remember that QWidget::focusWidget just is:

(…​) the last child of this widget that setFocus had been called on. For top level widgets this is the widget that will get focus in case this window gets activated.

When a widget gets focus via setFocus, the focus child gets set on their parents.

The future of smart pointers in Qt API

The use of deleteLater seems one of the hardest parts:

So obviously this:

std::unique_ptr<> ptr; ptr→deleteLater();

should show a warning. Thus, the first step is to annotate deleteLater with a optional deprecation.

Then two new functions need to be added:

static QObject::deleteLater(QObject *ptr)

which does not violate that invariant. (Unless you take a pointer out of a unique_ptr and pass it in.)

And a second variant: static QObject::deleteLater(std::unique_ptr<QObject> ptr)

which quite obviously also keeps the invariant.

I think I missed the function in my patch, but that’s how you could easily do it.

— Daniel Teske

Also a problem with layouts:

I don’t think these lines above are correct.

QBoxLayout::addWidget does not take ownership. Widgets are reparented to their correct parent once you call QWidget::setLayout in the next line, and QLayout operates on QLayoutItems that hold a weak pointer to the widgets that the layout places.

— Volker Hilshelmer

Also, a problem with elements on the stack:

Same as before, in essence a stack object is equivalent to a unique_ptr object.

Thus:

There’s no problem with having a QObjects without a parent on the stack/in a unique_ptr.

A QObject with a parent on the stack/unique_ptr is double owned and thus a problem. The severity of that problem is arguably worse with a unique_ptr.

Where my patch improves this situation is that the object ctors taking a parent ptr are all marked with a optional deprecation, thus if you opt into that, you’ll get a warning for the second case even for the stack allocation.

And yes this contrary to very crafty code that allocates objects in the right order on the stack, but that has never been the recommend way to use Qt.

— Daniel Teske

How qobject_cast works

  1. qobject_cast<QSpinBox*>(widget) is just calling static_cast<T>(ObjType::staticMetaObject.cast(object)).

  2. QMetaObject::cast(QObject *obj) is just calling obj→metaObject()→inherits(this)) on the meta object of the wished class.

  3. QMetaObject::inherits compares the meta object returned by the obj→metaObject() call (on the object which is being cast), with the meta object of the class we are casting to. If the comparison fails, tries to go up the hierarchy tree (so a pointer to QWidget can be cast to QFrame if the object happens to be a QLabel, for example).

If one wants to cast a widget to specifically one type of widget, but none of the derived subclasses, one can just compare the addresses directly. For example, to test if a widget is just a QWidget but not an instance of any derived class, one can do object→metaObject() == &QWidget::staticMetaObject.

Translation and internationalization mistakes

Notes to self

Styles in Qt

Some old notes that I took when I was trying to understand better the style system.

  • Styles: classes that inherit the abstract base class QStyle

  • To customize an existing style, inherit QProxyStyle and override functions.

  • To create a fully custom style, inherit QCommonStyle.

  • The API of QStyle contains the functions that draw the widgets.

  • The styles create a QPalette that contains QBrushes to draw with.

  • QStyle draws graphical "elements": widgets or their parts, like a scroll bar.