- 问题的场景和流程都比较奇怪,主界面上有多个dockwidget,堆叠在右侧,toolbar上有一些action按钮,用于控制dock的显示和非显示,当显示时会在slot函数中调用raise函数,使dock窗口置于最前面
- 问题现象是,当调整toolbar的长度时,toolbar会把部分action放到拓展菜单中,拓展菜单的按钮不能连续点击,而拓展菜单外的action没问题
- 而且这个问题只在dockwidget堆叠时发生,如果只有一个dock或浮动状态时,不会发生
- dockwindow堆叠显示就是下图的圈起来的状态,多个窗口都在同一个位置,通过点击tab标签可以切换窗口

- toolbar拓展菜单的问题现象如下,第二排和第三排的按钮无法连续点击,点击1次或2次,到最前面显示后就不能点击了,等鼠标离开,拓展区收回,再次打开时就复位了

- 经过一番调查发现,问题出在工具栏按钮的slot函数中,这里的处理是,如果需要不显示就使用hide,如果要显示就调用show和raise
如果将raise函数删除的话,问题现象就不会发生,也就是没有raise的效果但是可以点击

- 接下来要调查raise的源码了,如下图(qwidget.cpp)

subtractOpaqueSiblings和invalidateBackingStore两个函数计算了需要重绘的区域,并通过最后一行的sendEvent将重绘事件(rePaint)发送了
通过debug看了重绘区域的坐标,到这里还没问题 - 接下来sendEvent通过多层调用,调用了void QMainWindowLayout::tabChanged()

- 如下图,tabChanged在最后一行调用了centralWidget的raise函数,这个raise和刚才的是同一个
也就是说,centralWidget也被重绘了,而toolbar的拓展区域就在其中,所以被一起重绘了,因此导致无法点击,非拓展区没有问题
而单个窗口和浮动状态不会调用tabChanged,所以没问题

- 为了验证以上理论猜测,在toolbar和centralWidget之间再加一块测试区,也就是下图

- 代码是通过再追加一个toolbar实现的

- 测试结果是在测试区的toolbar拓展菜单的按钮可以连续点击,而测试区以外,也就是centralWidget的toolbar拓展菜单的按钮无法连续点击
- 经过以上调查,这个问题基本无解了。。。 也不知道这么奇怪又小众的问题会不会有人遇到
测试代码
main.cpp
c
#include "mainwindow.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
return a.exec();
}
mainwindow.cpp
c
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
setCentralWidget(new QWidget(this));
m_pTBWindow = addToolBar(tr("Window"));
m_pTBWindow->setObjectName("Window");
addToolBarBreak();
m_pTBTest = addToolBar(tr("test"));
m_pTBTest->setObjectName("test");
m_pTBTest->setStyleSheet("background-color: rgb(0, 196, 255);");
m_pTBTest->setMinimumWidth(100);
m_pTBTest->setMaximumWidth(800);
m_pTBTest->setFixedHeight(20);
m_pActTest1111DockShow = new QAction(this);
m_pActTest1111DockShow->setText(tr("Test1111"));
m_pActTest1111DockShow->setCheckable(true);
m_pActTest2222DockShow = new QAction(this);
m_pActTest2222DockShow->setText(tr("Test2222"));
m_pActTest2222DockShow->setCheckable(true);
m_pActTest3333WinDockShow = new QAction(this);
m_pActTest3333WinDockShow->setText(tr("Test3333"));
m_pActTest3333WinDockShow->setCheckable(true);
m_pActTest4444DockShow = new QAction(this);
m_pActTest4444DockShow->setText(tr("Test4444"));
m_pActTest4444DockShow->setCheckable(true);
m_pActTest5555DockShow = new QAction(this);
m_pActTest5555DockShow->setText(tr("Test5555"));
m_pActTest5555DockShow->setCheckable(true);
m_pActTest6666DockShow = new QAction(this);
m_pActTest6666DockShow->setText(tr("Test6666"));
m_pActTest6666DockShow->setCheckable(true);
m_pActTest7777DockShow = new QAction(this);
m_pActTest7777DockShow->setText(tr("Test7777"));
m_pActTest7777DockShow->setCheckable(true);
m_pActTest8888DockShow = new QAction(this);
m_pActTest8888DockShow->setText(tr("Test8888"));
m_pActTest8888DockShow->setCheckable(true);
m_pActTest9999DockShow = new QAction(this);
m_pActTest9999DockShow->setText(tr("Test9999"));
m_pActTest9999DockShow->setCheckable(true);
m_pActTest10101010DockShow = new QAction(this);
m_pActTest10101010DockShow->setText(tr("Test10101010"));
m_pActTest10101010DockShow->setCheckable(true);
m_pActTest20202020DockShow = new QAction(this);
m_pActTest20202020DockShow->setText(tr("Test20202020"));
m_pActTest20202020DockShow->setCheckable(true);
m_pTBWindow->addAction(m_pActTest1111DockShow);
m_pTBWindow->addAction(m_pActTest2222DockShow);
m_pTBWindow->addAction(m_pActTest3333WinDockShow);
m_pTBWindow->addAction(m_pActTest4444DockShow);
m_pTBWindow->addAction(m_pActTest6666DockShow);
m_pTBWindow->addAction(m_pActTest7777DockShow);
m_pTBWindow->addAction(m_pActTest8888DockShow);
m_pTBWindow->addAction(m_pActTest9999DockShow);
m_pTBWindow->addAction(m_pActTest10101010DockShow);
m_pTBWindow->addAction(m_pActTest20202020DockShow);
m_pTest1111Dock = new mydock("Test1111");
m_pTest1111Dock->setObjectName("Test1111");
m_pTest1111Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest1111Dock->setAccessibleName("Test1111Window");
m_pTest1111Dock->setWidget(new QWidget(m_pTest1111Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest1111Dock);
m_pTest2222Dock = new mydock("Test2222");
m_pTest2222Dock->setObjectName("Test2222");
m_pTest2222Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest2222Dock->setAccessibleName("Test2222");
m_pTest2222Dock->setWidget(new QWidget(m_pTest2222Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest2222Dock);
m_pTest3333WinDock = new mydock("Test3333");
m_pTest3333WinDock->setObjectName("Test3333");
m_pTest3333WinDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest3333WinDock->setAccessibleName("Test3333");
m_pTest3333WinDock->setWidget(new QWidget(m_pTest3333WinDock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest3333WinDock);
m_pTest4444Dock = new mydock("Test4444");
m_pTest4444Dock->setObjectName("Test4444");
m_pTest4444Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest4444Dock->setAccessibleName("Test4444");
m_pTest4444Dock->setWidget(new QWidget(m_pTest4444Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest4444Dock);
m_pTest20202020Dock = new mydock("Test20202020");
m_pTest20202020Dock->setObjectName("Test20202020");
m_pTest20202020Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest20202020Dock->setAccessibleName("Test20202020");
m_pTest20202020Dock->setWidget(new QWidget(m_pTest20202020Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest20202020Dock);
m_pTest5555Dock = new mydock("Test5555");
m_pTest5555Dock->setObjectName("Test5555");
m_pTest5555Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest5555Dock->setAccessibleName("Test5555");
m_pTest5555Dock->setWidget(new QWidget(m_pTest5555Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest5555Dock);
m_pTest6666Dock = new mydock("Test6666");
m_pTest6666Dock->setObjectName("Test6666");
m_pTest6666Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest6666Dock->setAccessibleName("Test6666");
m_pTest6666Dock->setWidget(new QWidget(m_pTest6666Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest6666Dock);
m_pTest7777Dock = new mydock("Test7777");
m_pTest7777Dock->setObjectName("Test7777");
m_pTest7777Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest7777Dock->setAccessibleName("Test7777");
m_pTest7777Dock->setWidget(new QWidget(m_pTest7777Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest7777Dock);
m_pTest8888Dock = new mydock("Test8888");
m_pTest8888Dock->setObjectName("Test8888");
m_pTest8888Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest8888Dock->setAccessibleName("Test8888");
m_pTest8888Dock->setWidget(new QWidget(m_pTest8888Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest8888Dock);
m_pTest9999Dock = new mydock("Test9999");
m_pTest9999Dock->setObjectName("Test9999");
m_pTest9999Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest9999Dock->setAccessibleName("Test9999");
m_pTest9999Dock->setWidget(new QWidget(m_pTest9999Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest9999Dock);
m_pTest10101010Dock = new mydock("Test10101010");
m_pTest10101010Dock->setObjectName("Test10101010");
m_pTest10101010Dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
m_pTest10101010Dock->setAccessibleName("Test10101010");
m_pTest10101010Dock->setWidget(new QWidget(m_pTest10101010Dock)); // 隶セ鄂ョ蜀�螳ケ
addDockWidget(Qt::RightDockWidgetArea, m_pTest10101010Dock);
connect(m_pActTest1111DockShow, SIGNAL(triggered(bool)), m_pTest1111Dock, SLOT(slotActivate(bool)));
connect(m_pActTest2222DockShow, SIGNAL(triggered(bool)), m_pTest2222Dock, SLOT(slotActivate(bool)));
connect(m_pActTest3333WinDockShow, SIGNAL(triggered(bool)), m_pTest3333WinDock, SLOT(slotActivate(bool)));
connect(m_pActTest4444DockShow, SIGNAL(triggered(bool)), m_pTest4444Dock, SLOT(slotActivate(bool)));
connect(m_pActTest6666DockShow, SIGNAL(triggered(bool)), m_pTest6666Dock, SLOT(slotActivate(bool)));
connect(m_pActTest7777DockShow, SIGNAL(triggered(bool)), m_pTest7777Dock, SLOT(slotActivate(bool)));
connect(m_pActTest8888DockShow, SIGNAL(triggered(bool)), m_pTest8888Dock, SLOT(slotActivate(bool)));
connect(m_pActTest9999DockShow, SIGNAL(triggered(bool)), m_pTest9999Dock, SLOT(slotActivate(bool)));
connect(m_pActTest10101010DockShow, SIGNAL(triggered(bool)), m_pTest10101010Dock, SLOT(slotActivate(bool)));
connect(m_pActTest20202020DockShow, SIGNAL(triggered(bool)), m_pTest20202020Dock, SLOT(slotActivate(bool)));
}
MainWindow::~MainWindow()
{
delete ui;
}
mainwindow.h
c
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QToolBar>
#include <QMouseEvent>
#include "mydock.h"
QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
QToolBar* m_pTBWindow;
QToolBar* m_pTBTest;
QAction* m_pActTest1111DockShow;
QAction* m_pActTest2222DockShow;
QAction* m_pActTest3333WinDockShow;
QAction* m_pActTest4444DockShow;
QAction* m_pActTest5555DockShow;
QAction* m_pActTest6666DockShow;
QAction* m_pActTest7777DockShow;
QAction* m_pActTest8888DockShow;
QAction* m_pActTest9999DockShow;
QAction* m_pActTest10101010DockShow;
QAction* m_pActTest20202020DockShow;
mydock* m_pTest1111Dock;
mydock* m_pTest2222Dock;
mydock* m_pTest3333WinDock;
mydock* m_pTest4444Dock;
mydock* m_pTest20202020Dock;
mydock* m_pTest5555Dock;
mydock* m_pTest6666Dock;
mydock* m_pTest7777Dock;
mydock* m_pTest8888Dock;
mydock* m_pTest9999Dock;
mydock* m_pTest10101010Dock;
private:
Ui::MainWindow *ui;
private slots:
protected:
// 鮠�譬�遘サ蜉ィ莠倶サカ
void mousePressEvent(QMouseEvent *event) override {
QPoint pos = event->pos(); // 逶ク蟇ケ莠守ェ怜哨逧�蝮先��
QPoint globalPos = event->globalPos(); // 蜈ィ螻€蝮先��
qDebug() << pos;
QWidget::mousePressEvent(event);
}
};
#endif // MAINWINDOW_H
mydock.cpp
c
#include "mydock.h"
mydock::mydock(const QString &title) {
m_pTitleBarWidget = new QWidget(this);
m_pTitleBarWidget->setFixedHeight(25+8);
m_pTitleBarWidget->setAccessibleName("DockWidgetTitle");
m_pLabel = new QLabel(m_pTitleBarWidget);
m_pLabel->setIndent( 4 );
m_pLabel->setText(title);
m_pLabel->setFixedHeight(25+1);
setStyleSheet("background-color: rgb(201, 196, 255);");
}
void mydock::slotActivate(bool value)
{
if(m_bIsActive)
{
hide();
m_bIsActive = false;
}
else
{
show();
raise();
m_bIsActive = true;
}
}
mydock.h
c
#ifndef MYDOCK_H
#define MYDOCK_H
#include <QDockWidget>
#include <QLabel>
class mydock : public QDockWidget
{
Q_OBJECT
public:
mydock(const QString &title);
bool m_bIsActive = false;;
QWidget* m_pTitleBarWidget;
QLabel* m_pLabel;
private slots:
void slotActivate(bool);
};
#endif // MYDOCK_H