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
setTabOrder
on 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
setTabOrder
Different
setWindowFlags
valuesSeveral combinations of
setFocusProxy
andsetFocusPolicy
Having 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?