Qt bug | QMdiArea使用TabbedView模式下,QTabBar移动tab的bug

文章描述了在Qt5.12中使用QMdiArea的TabbedView模式时遇到的三个问题:1)关闭移动后的tab时焦点无法自动切换;2)切换到桌面后再回来焦点丢失;3)移动tab后标签栏未更新显示。针对这些问题,分别提出了手动切换焦点、使用事件过滤器记录和恢复焦点、以及强制窗口刷新的解决方案。
摘要由CSDN通过智能技术生成

1 问题描述

Qt5.12下,QMdiArea使用TabbedView模式下,QTabBar移动tab有bug。

  1. 假设QTabBar有多个tab,然后当前焦点为tab1,移动tab1的位置,然后关闭tab1,发现此时焦点不能自动切换到其它tab(另一方面,此时mdiArea->activeSubWindow()为空),这是不正常的。
  2. 假设QTabBar有多个tab,然后当前焦点为tab1,移动tab1的位置,然后切换到桌面,然后重新回到软件,发现焦点不在tab1了。
  3. 假设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);
}

bug2的另一个比较好的解决办法

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);
});
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值