1 问题描述
Qt5.12下,QMdiArea使用TabbedView模式下,QTabBar移动tab有bug。
- 假设QTabBar有多个tab,然后当前焦点为tab1,移动tab1的位置,然后关闭tab1,发现此时焦点不能自动切换到其它tab(另一方面,此时mdiArea->activeSubWindow()为空),这是不正常的。
- 假设QTabBar有多个tab,然后当前焦点为tab1,移动tab1的位置,然后切换到桌面,然后重新回到软件,发现焦点不在tab1了。
- 假设QTabBar有4个tab,标签栏的宽度只能显示3个tab,假设当前显示2号~4号tab,使用QTabBar::moveTab移动4号tab到1号位置,标签栏没能刷新显示4号tab
2 复现及解决
widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
class QMdiArea;
class QPushButton;
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = 0);
~Widget();
private:
QMdiArea *mdiArea;
QPushButton *pushButton;
};
#endif // WIDGET_H
widget.cpp
#include "widget.h"
#include <QMdiArea>
#include <QMdiSubWindow>
#include <QTextEdit>
#include <QDebug>
#include <QTabBar>
#include <QPushButton>
#include <QVBoxLayout>
Widget::Widget(QWidget *parent)
: QWidget(parent)
{
resize(350, 250);
//创建控件
mdiArea = new QMdiArea;
pushButton = new QPushButton("pushButton");
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(mdiArea);
layout->addWidget(pushButton);
this->setLayout(layout);
//创建子窗口
QMdiSubWindow *firstTab = mdiArea->addSubWindow(new QTextEdit("i'm the first tab"));
firstTab->setWindowTitle("first tab");
QMdiSubWindow *secondTab = mdiArea->addSubWindow(new QTextEdit("i'm the second tab"));
secondTab->setWindowTitle("second tab");
QMdiSubWindow *thirdTab = mdiArea->addSubWindow(new QTextEdit("i'm the third tab"));
thirdTab->setWindowTitle("third tab");
QMdiSubWindow *fourthTab = mdiArea->addSubWindow(new QTextEdit("i'm the fourth tab"));
fourthTab->setWindowTitle("fourth tab");
//初始化mdiArea
mdiArea->setViewMode(QMdiArea::TabbedView);
mdiArea->setTabsMovable(true);
mdiArea->setTabsClosable(true);
QTabBar *tabBar = mdiArea->findChild<QTabBar *>();
//测试bug1
QObject::connect(tabBar, &QTabBar::tabMoved, this, [ = ]()
{
qDebug() << "tabMoved. " << "active subwindow:"
<< mdiArea->activeSubWindow()->windowTitle();
});
//测试bug1
QObject::connect(tabBar, &QTabBar::tabCloseRequested, this, [ = ](int index)
{
QString str;
str = "Index" + QString::number(index) + " tabCloseRequested.";
if (mdiArea->activeSubWindow())
{
str += " active subwindow:";
str += mdiArea->activeSubWindow()->windowTitle();
qDebug() << str;
}
else
{
str += " activeSubWindow is null";
qDebug() << str;
}
});
//测试bug2、bug3
connect(pushButton, &QPushButton::clicked, this, [ = ]
{
qDebug() << "before move, " << "tabBar curIndex:" << tabBar->currentIndex();
qDebug() << "before move, " << "mdiArea curActive:" << mdiArea->activeSubWindow()->windowTitle();
qDebug() << "before move, " << mdiArea->subWindowList();
tabBar->moveTab(3, 0);
qDebug() << "after move, " << "tabBar curIndex:" << tabBar->currentIndex();
qDebug() << "after move, " << "mdiArea curActive:" << mdiArea->activeSubWindow()->windowTitle();
qDebug() << "after move, " << mdiArea->subWindowList();
});
}
Widget::~Widget()
{
}
2.1 复现及解决bug1
复现
运行第2节的程序,运行结果如图
将fourth tab移动到左侧,程序输出 tabMoved. active subwindow: “fourth tab”
然后关闭fourth tab,程序输出 Index2 tabCloseRequested. activeSubWindow is null
表现效果如下图所示,
解决
从上文可以看到,关闭fourth tab后,Qt无法正确切换到下一个tab,正常情况下,Qt应该自动切换到third tab才对。
我暂时找不到出现这个现象的原因,这里我的做法是用代码做一个切换焦点的操作。
//测试bug1
QObject::connect(tabBar, &QTabBar::tabCloseRequested, this, [ = ](int index)
{
QString str;
str = "Index" + QString::number(index) + " tabCloseRequested.";
if (mdiArea->activeSubWindow())
{
str += " active subwindow:";
str += mdiArea->activeSubWindow()->windowTitle();
qDebug() << str;
}
else
{
str += " activeSubWindow is null";
qDebug() << str;
//新增以下代码段,用于修复bug1
QList<QMdiSubWindow *> subwins = mdiArea->subWindowList(QMdiArea::StackingOrder);
if (!subwins.isEmpty())
{
mdiArea->setActiveSubWindow(subwins.last());
}
}
});
2.2 复现及解决bug2
复现
运行第2节的程序,运行结果如图
然后拉伸窗口,显示所有tab,如图所示
点击pushButton(tabBar->moveTab(3, 0);),运行结果如图所示,
程序输出如下
before move, tabBar curIndex: 3
before move, mdiArea curActive: “fourth tab”
before move, (QMdiSubWindow(0x2cd22b8), QMdiSubWindow(0x81b1ae0), QMdiSubWindow(0x81b2060), QMdiSubWindow(0x81b2640))
tabMoved. active subwindow: “fourth tab”
after move, tabBar curIndex: 0
after move, mdiArea curActive: “fourth tab”
after move, (QMdiSubWindow(0x81b2640), QMdiSubWindow(0x2cd22b8), QMdiSubWindow(0x81b1ae0), QMdiSubWindow(0x81b2060))
从程序运行结果和输出结果来看,一切正常,这时切换到桌面,然后重新回到软件,结果如下图,发现焦点不在fourth tab了,这是不正确的。
解决
我暂时找不到出现这个现象的原因,这里我做法是使用事件过滤器记录切出软件时的焦点位置,切回软件时重新设置焦点位置。
bool Widget::eventFilter(QObject *obj, QEvent *event)
{
//新增以下代码,用于修复bug2
if (event->type() == QEvent::ApplicationStateChange)
{
static int index = 0;
Qt::ApplicationState state = QGuiApplication::applicationState();
if (state == Qt::ApplicationActive)
{
QTabBar *tabBar = mdiArea->findChild<QTabBar *>();
tabBar->setCurrentIndex(index);
return false;
}
else if (state == Qt::ApplicationInactive)
{
QTabBar *tabBar = mdiArea->findChild<QTabBar *>();
index = tabBar->currentIndex();
return false;
}
}
// pass the event on to the parent class
return QWidget::eventFilter(obj, event);
}
2.3 复现及解决bug3
复现
运行第2节的程序,运行结果如图
点击pushButton(tabBar->moveTab(3, 0);),运行结果如图所示
从图片可知,fourth tab已经移动了位置,但是标签栏没有刷新,使得fourth tab显示在标签栏,这是不正确的。
解决
我暂时找不到出现这个现象的原因,这里我做法是强制刷新窗口。
//测试bug2、bug3
connect(pushButton, &QPushButton::clicked, this, [ = ]
{
tabBar->moveTab(3, 0);
//新增以下代码,用于修复bug3
int w = this->width();
int h = this->height();
this->resize(w + 1, h);
this->resize(w, h);
});