Context:
For a custom widget, similar to a menu, I have some of the content inside a "drop-down" frame when space is not sufficient:
For this drop-down feature, I set the frame for those buttons to have frame.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);. This works pretty well, except that it mess the tabulation order.
The structure of widgets look like:
MenuWidget
|- Tab1
|- Group_<without_name>
...
|- Group_File
...
|- Group_Export
|-Frame (can be either standard sub-widget, or a popup widgets)
|- Button 1
|- Button 2
....
You can see the current WIP there: https://github.com/Escain/QTopMenu
I reduced the issue to the following code, which has proper tabulation order at the begining, and has messed tabulation after I set Qt::Popup and back to Qt::Widget.
Any attempt to recover the proper tabulation order is failing.
Before setting Qt::Popup:
After setting Qt::Popup and setting back Qt::Widget:
Here is the minimal example to reproduce the issue.
DISCLAIM: this is not production code, just quick-done code aiming to reproduce the same issue.
#include <QApplication>
#include <QDebug>
#include <QWidget>
#include <QPushButton>
class TestWidget: public QWidget
{
Q_OBJECT
public:
explicit TestWidget( QWidget* parent=nullptr)
: QWidget(parent)
, frame(this)
, but1(&frame)
, but2(&frame)
{
but1.setGeometry(10, 10, 80, 30);
but2.setGeometry(110, 10, 80, 30);
frame.setGeometry(0,0,200,50);
resize(200,50);
setStyleSheet("background-color: rgba(0,128,128,32);");
setFocusProxy(&frame);
frame.setFocusProxy(&but1);
setFocusPolicy(Qt::FocusPolicy::StrongFocus);
connect(&but1, &QPushButton::clicked, [this]()
{
const auto flag = frame.windowFlags();
// In some circumstances, the widget needs to show it content as drop-down
frame.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);
//try to recover here
frame.setWindowFlags(flag);
frame.show();
emit needsTabOrder();
});
}
QWidget* orderTabs( QWidget* first)
{
setTabOrder(first, &but1);
setTabOrder(&but1, &but2);
return &but2;
}
signals:
void needsTabOrder();
private:
QWidget frame;
QPushButton but1, but2;
};
#include "main.moc"
auto main (int argn, char* args[])-> int
{
QApplication app(argn, args);
QWidget window;
TestWidget t1(&window);
TestWidget t3(&window); //Intentionally out of order
TestWidget t2(&window);
TestWidget t4(&window);
t1.move(0,10);
t2.move(200,10);
t3.move(400,10);
t4.move(600,10);
QWidget::setTabOrder(&t1, &t2);
QWidget::setTabOrder(&t2, &t3);
QWidget::setTabOrder(&t3, &t4);
auto tryRecoverThisMess = [&t1, &t2, &t3, &t4]()
{
qDebug() << "Trying to recover this mess";
// Attempt 1: not working
QWidget::setTabOrder(&t1, &t2);
QWidget::setTabOrder(&t2, &t3);
QWidget::setTabOrder(&t3, &t4);
// Attempt 2: very hacky and not working
QWidget* w=nullptr;
w = t1.orderTabs( w);
w = t2.orderTabs( w);
w = t3.orderTabs( w);
w = t4.orderTabs( w);
};
QWidget::connect(&t1, &TestWidget::needsTabOrder, tryRecoverThisMess);
QWidget::connect(&t2, &TestWidget::needsTabOrder, tryRecoverThisMess);
QWidget::connect(&t3, &TestWidget::needsTabOrder, tryRecoverThisMess);
QWidget::connect(&t4, &TestWidget::needsTabOrder, tryRecoverThisMess);
window.resize(800,200);
window.show();
return app.exec();
}
Using Qt 5.15.2
The CMakeLists looks like:
cmake_minimum_required(VERSION 3.13)
cmake_policy( SET CMP0076 NEW )
project("QtTest")
set(CMAKE_AUTOMOC ON)
find_package(Qt5Widgets REQUIRED)
include_directories(${Qt5Widgets_INCLUDE_DIRS})
add_definitions(${Qt5Widgets_DEFINITIONS})
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${Qt5Widgets_EXECUTABLE_COMPILE_FLAGS}")
set(TARGET "QtTest")
add_executable(${TARGET})
target_compile_options( ${TARGET} PRIVATE -Wall -pedantic -Wno-padded -Werror=return-type)
target_compile_features( ${TARGET} PUBLIC cxx_std_17)
target_sources( ${TARGET} PRIVATE "main.cpp")
target_link_libraries(${TARGET} "Qt5::Widgets" )
My attempts to solve the issue:
I tried to call
setTabOrderon the parent widgets, as well as on each button (hacky). Without success.To print the tab-order, it indeed does NOT re-order as per
setTabOrderDifferent
setWindowFlagsvaluesSeveral combinations of
setFocusProxyandsetFocusPolicyHaving the frame always as "Popup" and move all the widgets on it between the frame and the main widget.
The question:
How to recover the tab order after setting Qt::Popup flag?


