您现在的位置是:首页 >技术交流 >QTableview 隐藏单元格内控件无效的原因网站首页技术交流

QTableview 隐藏单元格内控件无效的原因

Ellie是个昵称 2023-05-22 16:00:02
简介QTableview 隐藏单元格内控件无效的原因

QTableview 隐藏单元格内控件无效的原因

背景:

在QTableview的单元格中创建多个QComboBox,当某条件成立时,隐藏特定单元格中的QComboBox,使得该单元格为空。

DEMO:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QStandardItemModel>
#include <QMainWindow>

#include <QComboBox>

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    void init();
    void changeData();

private:
    QStandardItemModel *mpDataModel;    ///< 表格数据模型

    QList<QComboBox*> mComboList;

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    init();
    changeData();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    mpDataModel = new QStandardItemModel;

    mpDataModel->setRowCount(10 );
    mpDataModel->setColumnCount(1);

    ui->tableView->setModel(mpDataModel);

    QStringList strList;
    strList<<"1"<<"2";

    for(int i=0; i<10; i++)
    {
        QComboBox *combo = new QComboBox(this);
        combo->addItems(strList);

        mComboList.append(combo);

        QModelIndex index = mpDataModel->index(i, 0);
        ui->tableView->setIndexWidget(index, combo);
    }
}

void MainWindow::changeData()
{
        //第一种方式
//    int row1 = 1;
//    QWidget *widget = ui->tableView->indexWidget(mpDataModel->index(row1,0));
//    QComboBox *combo = dynamic_cast<QComboBox*>(widget);
//    if(combo != nullptr)
//    {
//        combo->setVisible(false);
//    }

    //第二种方式
//    widget->hide();

    //第三种方式
//    mComboList.at(row)->setVisible(false);

    //第四种方式
    int row2 = 1;
    ui->tableView->setIndexWidget(mpDataModel->index(row2,0),nullptr);

}

demo中创建了一个简单的主窗口,包含一个表格视图 (QTableView)。表格视图有 10 行和 1 列,每个单元格都包含一个下拉列表 (QComboBox)。

init() 函数设置了表格视图,创建一个包含两个选项 (“1” 和 “2”) 的下拉列表 (QComboBox),并将其添加到表格视图的每个单元格中。最后,将每个 QComboBox 对象添加到 mComboList 向量中。

changeData()试图隐藏表格视图中的某个特定单元格内的 QComboBox。

运行结果:除了第四种方式,其余方式隐藏无效。

分析原因:

<帮助手册>

在这里插入图片描述

<源代码:qabstractitemview.cpp>

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YcEfhX0U-1681821716291)(C:UsersAdministratorAppDataRoamingmarktextimages2023-04-07-17-22-35-image.png)]

探讨setIndexWidget函数的作用:

如果在放入新控件时,当前单元格存在旧控件,那么d->persistent.remove(oldWidget);会将旧控件从persistent 集合中移除,防止内存泄漏,同时确保旧控件不再与模型索引关联。除此之外,会将其从编辑器列表中移除,并取消对它的事件过滤,deleteLater将其安排在稍后删除。

排查隐藏失败的原因:

在demo中:

1、该下拉列表框已经被正确添加到了视图中,目标隐藏位置确实存在QComboBox控件:

语句:

qDebug() << ui->tableView->indexWidget(mpDataModel->index(row1,0));

输出:在这里插入图片描述

2、控件的visible属性没有在其他代码部分重新设置为true

3、控件没有被其他控件遮挡

4、控件所在的父控件没有设置setVisible(false)

5、强制视图重新绘制后也无法隐藏

语句:

ui->tableView->viewport()->update();

6、控件的可见性属性确实被设置为false

语句:

bool isVisible = combo->testAttribute(Qt::WA_WState_Visible);
qDebug() << "Is visible: " << isVisible;

输出:在这里插入图片描述

合理推测隐藏失败原因:

在tableview被创建时,单元格存在默认的控件:在放入下拉框前打印

语句:

for(int row=0; row<10;row++)
{
    qDebug() << ui->tableView->indexWidget(mpDataModel->index(row,0));
}

输出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yHbw8l8p-1681821716292)(C:UsersAdministratorAppDataRoamingmarktextimages2023-04-18-20-37-54-image.png)]

我们使用setIndexWidget时,将新控件代替了旧控件,此时旧控件已经从视图中移除。如果我们删除或隐藏新控件,该单元格中没有可以显示的控件,也许这样导致了删除或隐藏失败,保留原视图显示。

欢迎一起讨论!

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。