[SOLVED] Qt 4.8.5 Focus bug, keyPresses routed via menu, OSX only
-
Here's a minimal example:
TestWidget.h
@#ifndef TESTWIDGET_H
#define TESTWIDGET_H#include <QtGui/QtGui>
#include <QtCore/QObject>class TestWidget: public QWidget
{
Q_OBJECT
public:
TestWidget();public Q_SLOTS:
void onPressP1();
void onPressP2();private:
QStackedWidget* _stack;
};#endif // TESTWIDGET_H
@TestWidget.cpp
@#include "testpanel.h"#include <QtGui/QtGui>
#include <QtOpenGL/QGLWidget>TestWidget::TestWidget() : QWidget()
{
QVBoxLayout* layout = new QVBoxLayout();
setLayout(layout);
_stack = new QStackedWidget();
QPushButton* b1 = new QPushButton("p1");
QPushButton* b2 = new QPushButton("p2");layout->addWidget(b1);
layout->addWidget(b2);
layout->addWidget(_stack);//QLabel* page1 = new QLabel("PAGE 1");
QGLWidget* page1 = new QGLWidget();
_stack->addWidget(page1);QTextEdit* page2 = new QTextEdit();
_stack->addWidget(page2);connect(b1, SIGNAL(pressed()), this, SLOT(onPressP1()));
connect(b2, SIGNAL(pressed()), this, SLOT(onPressP2()));
}void TestWidget::onPressP1()
{
qDebug() << "onPressP1";
_stack->setCurrentIndex(0);
}
void TestWidget::onPressP2()
{
qDebug() << "onPressP2";
_stack->setCurrentIndex(1);
setFocusProxy(_stack->currentWidget());
}
@main.cpp
@#include <QtCore/QCoreApplication>
#include <QtGui/QtGui>#include "testpanel.h"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);QMainWindow* mw = new QMainWindow();
mw->show();TestWidget* t = new TestWidget();
t->setParent(mw);
t->show();return app.exec();
}@I dont have a .pro file - not using qmake projects, but its standard stuff.
Once compiled, expand the window. There are 2 buttons and an uncleared QGLWidget. If you switch between the two pages of the QStackedWidget, you suddenly cannot type in the QTextEdit any more.
If you recompile with a QLabel for page1 instead of a QGLWidget, it works fine. In fact setting any widget to use the WA_NativeWindow flag also breaks it.
-
I just tested it with on 10.8.5 and can confirm the behavior for Qt 4.8.5 but it works on Qt 5.2. Can you open a bug report "here":http://bugreports.qt-project.com ?
Posting the link to it would be great
-
Thanks for testing... I'll log a bug
-
-
I really need a patch or workaround for this. Can anyone help?
-
I've reported the bug, but it looks like no suggestion will be forthcoming any time soon. So I am trying to debug myself.
More info. I've tried different combinations of widgets in the QStackedWidget:
Working
page1: QQLWidget
page2: QLabel, QPushButton, QWidget or QGLWidgetWorking
page1: QLineEdit, QPlainTextEdit or QTextEdit
page2: QLineEdit, QPlainTextEdit or QTextEditBroken
page1: QGLWidget
page2: QLineEdit, QPlainTextEdit, QTextEdit or QComboBoxBroken
page1: QLineEdit, QPlainTextEdit, QTextEdit or QComboBox
page2: QGLWidgetSo to reproduce it you definitely need a QGLWidget and some sort of widget which accepts focus in the same stack.
Significantly, you can switch between the two pages and see key presses received correctly (using an event filter). It works until you focus the focusable widget (the QTextEdit becomes the QApplication::focusWidget()). Then when you change pages and back, it is broken.
EDIT - Found that QComboBox also exhibits the problem, so its not confined to text entry widgets
-
My debug efforts show that in the scenario where a QStackedWidget has a mix of Native and alien widgets in its stack, the focussing is broken. Exact repro steps:
- start app which has a QStackedWidget showing page1. Page1 is a widget with WA_NativeWindow set. Page2 is a Widget which accepts focus, eg QLineEdit.
- switch to page2. Focus the widget with the mouse. You can type in the QLineEdit .
- switch to page1. QStackedLayout::setCurrentIndex switches focus from the QLineEdit to the Native widget.
- switch to page2. QStackedLayout::setCurrentIndex tries to focus the QLineEdit, but this line returns NIL, qwidget_mac.mm:3914, QWidgetPrivate::setFocus_sys:
@NSView *view = qt_mac_nativeview_for(q);@
The next line then does makeFirstResponder:nil, which unfocuses widgets and routes further keyboard events to the top level application instead.
My patch ensures we always get a valid native view by calling:
@NSView *view = qt_mac_effectiveview_for(q);@
Is this the right approach?
-
Further evidence that my fix is correct. It brings OSX into line with other platforms. On windows, we setFocus on the effectiveWinId. But on OSX, we were using internalWinID.
On Windows, qwidget_win.cpp:
@void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
if (q->testAttribute(Qt::WA_WState_Created) && q->window()->windowType() != Qt::Popup)
SetFocus(q->effectiveWinId());
}@On OSX, qwidget_mac.mm:
@void QWidgetPrivate::setFocus_sys()
{
Q_Q(QWidget);
if (q->testAttribute(Qt::WA_WState_Created)) {
#ifdef QT_MAC_USE_COCOA
QMacCocoaAutoReleasePool pool;
//NSView *view = qt_mac_nativeview_for(q); // WRONG as it uses internalWinId
NSView *view = qt_mac_effectiveview_for(q); // CORRECT as it uses effectiveWinId
[[view window] makeFirstResponder:view];
#else
SetKeyboardFocus(qt_mac_window_for(q), qt_mac_nativeview_for(q), 1);
#endif
}
}Q_GUI_EXPORT OSViewRef qt_mac_nativeview_for(const QWidget *w)
{
return reinterpret_cast<OSViewRef>(w->internalWinId());
}Q_GUI_EXPORT OSViewRef qt_mac_effectiveview_for(const QWidget *w)
{
// Get the first non-alien (parent) widget for
// w, and return its NSView (if it has one):
return reinterpret_cast<OSViewRef>(w->effectiveWinId());
}
@ -
Thanks for submitting the patch, SGaist!
-
You're welcome !
Since it will be working now, please update the thread title prepending [solved] so other forum users may know a solution has been found :)