Qt 中 QListWidget 获取itemWidget() 失败

前两天在测试的时候,发现QListWidget 类 调用 listWidget->itemWidget(pItem) 函数时返回了Q_NULLPTR,这不是一个平常会遇到的问题,探查了一下资料,找到了问题的原因,记录一下这个问题。

首先,我们创建一个简单的QListWidget,并且自定义其item:

namespace Ui {
	class Item;
}

class Item : public QWidget
{
	Q_OBJECT
public:
	explicit Item(const QString& strName, QWidget *parent = Q_NULLPTR);
	~Item();
	QString getPoseName();

private slots:
	void on_pushButton_clicked();   //  按钮点击的时候发送信号 signal_delete

signals:
	void signal_delete();

private:
	Ui::Item* ui;
};
namespace Ui {
    class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();   //增加item,不进行初始化添加的目的是为了方便的看问题
    void slot_delete();

private:
    Ui::MainWindow *ui;
};

接下来是实现部分:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "ui_item.h"
#include <QDebug>
#define SAFEDELETE(p) if(Q_NULLPTR != (p)) { delete (p);(p) = Q_NULLPTR;}

Item::Item(const QString& strName, QWidget *parent) : QWidget(parent), ui(new Ui::Item)
{
    ui->setupUi(this);
    ui->label->setText(strName);
}

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

QString Item::getPoseName()
{
    return ui->label->text();
}

void Item::on_pushButton_clicked()
{
    emit signal_delete();
}

上面的这部分是Item类的实现。

主界面的按钮槽,点击一次会新增一个item,并且打印相关的信息。item能够新增成功并且打印信息正常。

void MainWindow::on_pushButton_clicked()
{
    static int nIndex = 1;

    Item* pTest = new Item(QString("test_%1").arg(nIndex++));

    QListWidgetItem* pItem = new QListWidgetItem(ui->listWidget);

    qDebug() << "create QWidget" << (pTest != Q_NULLPTR ? pTest->getPoseName() : "pTest == Q_NULL ") << pTest;

    qDebug() << "create listItem" << pItem;

    ui->listWidget->addItem(pItem);
    ui->listWidget->setItemWidget(pItem, pTest);

    connect(pTest, &Item::signal_delete, this, &MainWindow::slot_delete);
}

下面是删除一行的操作:

void MainWindow::slot_delete()
{
    QListWidgetItem* item = ui->listWidget->takeItem(0);    //这边写为0是为了方便测试
    auto pTest = dynamic_cast<Item*>(ui->listWidget->itemWidget(item));

    qDebug() << "delete listItem" << item;
    qDebug() << "delete QWidget" << (pTest != Q_NULLPTR ? pTest->getPoseName() : "pTest == Q_NULL ") << pTest;

    SAFEDELETE(item);
    SAFEDELETE(pTest);
}

运行工程时发现:
在这里插入图片描述

刚开始是没有取打印信息的,是在调试的发现 点击删除按钮后 Item 的数量和 QListWidgetItem 的数量不相等,觉得奇怪,于是加了断点和打印信息看下是不是缺了什么。通过打印信息发现:

新增一行时信息正常,但是在删除一行的时候出现了 pTest 为 Q_NULLPTR;咦!这就奇怪了,我们在新增行的时候明明已经将Item通过setItemWidget函数添加到QListWidgetItem上了,为什么后面取的时候,反而取不到呢?

这个时候第一反应是看下 itemWidget 这个接口是不是会有返回失败的情况,于是打开了帮助文档瞄了一眼:

QWidget *QListWidget::itemWidget(QListWidgetItem *item) const
Returns the widget displayed in the given item.
This function was introduced in Qt 4.1.
See also setItemWidget() and removeItemWidget().

看到是不会返回失败,为了确认,还专门去看了setItemWidget()、removeItemWidget()这俩接口,同样没发现问题。

这个时候就百思不得其解,然后返回继续撸了这整个的流程,看看是不是在某个时候不小心释放了QWidget这个指针,撸完的结果是整个流程并没有问题,也没有在其他任何地方释放Item的指针。

静下来想一想,决定还是再看一看帮助文档,再次翻开帮助文档并认真的读了解释,这一次当看到 displayed 的时候瞬间就明白犯了什么错误了。

大家看一看这两行代码:

QListWidgetItem* item = ui->listWidget->takeItem(0);
auto pTest = dynamic_cast<Item*>(ui->listWidget->itemWidget(item));

首先我们使用了takeItem接口删除并取得一个QListWidgetItem,注意是先从QListWidget上删除一个QListWidgetItem,然后返回删除的这个QListWidgetItem,因此当下面调用itemWidget接口时,这个QListWidgetItem是不可见的。所以该接口返回了Q_NULLPTR。

换成下面:

QListWidgetItem* item = ui->listWidget->item(0);
auto pTest = dynamic_cast<Item*>(ui->listWidget->itemWidget(item));
ui->listWidget->takeItem(0);

我们首先通过item接口获取到QListWidgetItem,然后通过该QListWidgetItem获取QWidget,最后从QListWidget上将该QListWidgetItem删除,程序正常。

在这里插入图片描述

单对这个问题来说,这个问题是很简单的,本应该第一次在查看帮助文档的时候就能够发现问题,但是我只是瞄了一眼,并没有仔细的理解,也就是这些着急造成了时间成本的增加。后续在处理问题时,

应该脚踏实地的弄清楚每一步的操作和其中的涵义,不要急着解决问题,可能会节约很多时间。

  • 5
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值