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刪除,程序正常。

在這裏插入圖片描述

單對這個問題來說,這個問題是很簡單的,本應該第一次在查看幫助文檔的時候就能夠發現問題,但是我只是瞄了一眼,並沒有仔細的理解,也就是這些着急造成了時間成本的增加。後續在處理問題時,

應該腳踏實地的弄清楚每一步的操作和其中的涵義,不要急着解決問題,可能會節約很多時間。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章