的
對于此下拉功能,我將這些按鈕的框架設定為具有frame.setWindowFlags(Qt::Popup | Qt::FramelessWindowHint);. 這作業得很好,除了它弄亂了制表順序。
小部件的結構如下所示:
MenuWidget
|- Tab1
|- Group_<without_name>
...
|- Group_File
...
|- Group_Export
|-Frame (can be either standard sub-widget, or a popup widgets)
|- Button 1
|- Button 2
....
你可以在那里看到當前的 WIP:
設定Qt::Popup和設定后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?
uj5u.com熱心網友回復:
簡短的回答:基本上你不能自動修復小部件選項卡順序。將 a 設定QWidget為彈出視窗會將其從QWidget選項卡順序層次結構中洗掉,因為彈出視窗是一種具有自己內部選項卡層次結構的視窗。通過將您的彈出視窗重置回一個簡單的小部件,然后它會被讀取到您添加它的級別和級別的選項卡層次結構中,以加擾其間的所有內容。這似乎是Qt庫的問題。我想你的想法是之后恢復 taborder 的唯一方法。關于閱讀小部件的相關執行緒。(您的嘗試 2 基本上是那里建議的內容)
在您嘗試使用 main-function-lambda 中非常明智的 Attempt 1 修復它后,您可以通過呼叫此函式來驗證您的 Tab 鍵順序變得多么混亂:
void printTabOrder(QWidget *start)
{
QWidget *current = start;
do
{
qDebug() << current;
current = current->nextInFocusChain();
} while(current != start);
}
我建議您不要即時更改小部件視窗標志。Insted 只是創建一個自定義行為并設定QWidget為彈出視窗。恕我直言,無論如何它會是更好的風格,因為你TestWidget只是拿著按鈕并處理它們的點擊,你TestWidgetMenu可以處理所有彈出的東西。
我將所有結構和樣式問題都歸因于這段代碼的最小作業示例性質。
uj5u.com熱心網友回復:
從不使用自動
僅在槍口處使用 Lambda
auto tryRecoverThisMess = [&window, &t1, &t2, &t3, &t4]() { qDebug() << "Trying to recover this mess"; // Attempt 1: not working window.setTabOrder( &t1, &t2 ); window.setTabOrder( &t2, &t3 ); window.setTabOrder( &t3, &t4 );#if 0 // 嘗試 2:非常hacky 并且不作業 QWidget *w=nullptr; w = t1.orderTabs( w ); w = t2.orderTabs( w ); w = t3.orderTabs( w ); w = t4.orderTabs( w ); #萬一
};
你是否創建了一個從 QWidget 派生的類 MyClass 并給了悲傷的類一個插槽 void tryRecoverThisMess();
您不需要引數,因為 TestWidget 專案本來是成員變數。更重要的是,插槽只需要。
setTabOrder( &t1, &t2 );
setTabOrder( &t2, &t3 );
setTabOrder( &t3, &t4 );
因為它將在小部件內執行。
您正在使用自動型別在 Lambda 中呼叫 QTabWidget::setTabOrder。編譯器可以自由地確定這個 Lambda 是一個 QWidget 并為其設定 Tab 鍵順序,或者在 Lambda 生命周期結束時處理它之前制造一個臨時 QWidget 設定其 Tab 鍵順序。
您的代碼中沒有任何內容表明您要更改“視窗”的選項卡順序。
誠然,我在使用 Qt 5.12.8 的 Ubuntu 20.04 LTS 上嘗試過這個,但我確實看到點擊后跳轉到第三個按鈕。在我修復后,他們沒有這樣做。“正確”的解決方法是將這些東西放在一個類中,并將 SIGNAL 連接到類中的一個插槽。
我懷疑您在其他代碼中也有類似的育兒問題。
重構您的代碼以洗掉所有 Lambda 并洗掉所有汽車。
Lambda 作為插槽非常危險。 當涉及到創建的物件然后移動到另一個執行緒時,它們會變得非常危險。Lambda 不是物件的一部分,它不必移動。這意味著您可能有一個排隊連接,并且此 Lambda 插槽試圖回傳的物件可能會被洗掉。
年輕的開發人員喜歡使用 auto 和 Lambda,因為它可以讓他們走捷徑。
任意兩點之間的最長距離是一條捷徑。
隨著年齡的增長,您會意識到這是 IT 領域的一個事實。
歡迎來到精彩的編程世界!
根據您的要求,我“修補”了您的代碼。它需要從頭開始重新設計才能“修復”。
#include <QApplication>
#include <QDebug>
#include <QWidget>
#include <QPushButton>
class TestWidget: public QWidget
{
Q_OBJECT
public:
explicit TestWidget( QString txt, QWidget *parent=nullptr )
: QWidget( parent )
, button1( nullptr )
, button2( nullptr )
{
// don't create widgets on the stack
//
QString lbl1 = QString( "%1-%2" ).arg( txt ).arg( 1 );
QString lbl2 = QString( "%1-%2" ).arg( txt ).arg( 2 );
button1 = new QPushButton( lbl1, this );
button2 = new QPushButton( lbl2, this );
button1->setGeometry( 10, 10, 80, 30 );
button2->setGeometry( 110, 10, 80, 30 );
setGeometry( 0,0,200,50 );
resize( 200,50 ); // ????
setStyleSheet( "QPushButton{ background-color: rgba(170, 176, 81, 200); }"
"QPushButton:focus{ background-color: rgba(72, 75, 224, 200); } "
"QPushButton:focus:pressed{ background-color: rgba(229, 141, 29, 200); } "
"QPushButton:pressed{ background-color: rgba(241, 5, 10, 250); } " );
setFocusProxy( this );
setFocusProxy( button1 );
setFocusPolicy( Qt::FocusPolicy::StrongFocus );
setInternalTabOrder();
connect( button1, &QPushButton::clicked, [this]()
{
const auto flag = this->windowFlags();
// In some circumstances, the widget needs to show it content as drop-down
this->setWindowFlags( Qt::Popup | Qt::FramelessWindowHint );
//try to recover here
this->setWindowFlags( flag );
this->show();
emit needsTabOrder();
this->setFocus( ); // without this clicked button won't grab
// focus but a clicked button2 will
} );
}
~TestWidget()
{
if ( button1 != nullptr )
{
delete button1;
button1 = nullptr;
}
if ( button2 != nullptr )
{
delete button2;
button2 = nullptr;
}
}
void setInternalTabOrder()
{
setTabOrder( button1, button2 );
}
signals:
void needsTabOrder();
private:
QPushButton *button1;
QPushButton *button2;
};
#include "main.moc"
auto main ( int argn, char *args[] )-> int
{
QApplication app( argn, args );
// don't create widgets on the stack
//
QWidget *window = new QWidget();
TestWidget *t1 = new TestWidget( "Fred", window );
TestWidget *t3 = new TestWidget( "Ethyl", window ); //Intentionally out of order
TestWidget *t2 = new TestWidget( "Lucy", window );
TestWidget *t4 = new TestWidget( "Ricky", 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 = [window, t1, t2, t3, t4]()
{
qDebug() << "Trying to recover this mess";
window->setTabOrder( t1, t2 );
window->setTabOrder( t2, t3 );
window->setTabOrder( t3, t4 );
};
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();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/379730.html
標籤:c qt drop-down-menu focus
