2016-07-30 32 views
0

我是Qt新手,我對如何刪除小部件感到困惑。我正在閱讀視頻,並且在視頻幀正在讀取時我想顯示一個QProgressbar,然後在視頻加載時刪除此QProgressbar。刪除指向小部件的指針Qt C++

我有兩種不同的方式做到了:

  1. 使用指針

    QWidget* wd = new QWidget(); 
    QProgressBar* pB = new QProgressBar(wd); 
    QLabel* label = new QLabel(wd); 
    //setting geometry and updating the label and progressbar 
    wd->deleteLater(); 
    wd->hide(); 
    

    這個代碼寫一個類內部,我是假設,當這個類的析構函數被調用時,小部件將被刪除與所有的孩子,但沒有發生,每次我再次運行此功能一個新的小部件創建而不隱藏或刪除前一個(注:我試圖從小部件中刪除標籤和進度條假設他們會從內心消失E中的組件,但是這並沒有發生「刪除(PB);」)

  2. 使用對象

    QWidget wd; 
        QProgressBar pB(&wd); 
        QLabel label(wd); 
        //setting geometry and updating the label and progressbar 
        wd.deleteLater(); 
        wd.hide(); 
    

當我運行相同的代碼,但使用的替代對象的指針,它有按照我的意願運行,每次運行該功能時,舊的小部件都將被銷燬,並創建一個新的小部件。

注意: - 同樣當我關閉主窗口,在指針的情況下,小部件WD仍然存在,程序不會終止,直到我手動關閉他們 - 在對象的情況下,當我關閉主窗口一切都關閉,程序正確終止。

如果我有指針到小部件的載體刪除矢量內所有的指針沒有任何內存泄漏

+1

我推薦閱讀[一本書](http://stackoverflow.com/a/388282/3484570)關於內存管理如何在C++中工作。然後閱讀[Qt如何以不同的方式](http://doc.qt.io/qt-5/objecttrees.html)。 – nwp

+0

您可以簡單地將其隱藏,而不是刪除'QProgressBar'。無論如何,你可能需要它來爲下一個流。 – maxik

回答

0

在典型的C++的規則是,我需要有人來解釋我爲什麼會這樣,以及如何「寫每new一個delete「。更爲先進的規則是「可能不會寫newdelete,而是將其改爲在RIAA模式中」。 Qt在這方面改變了規則,因爲它引入了自己的內存管理範例。它基於父母/子女關係。 QWidget s即new ed可以給出parentWidget()。當parentWidget()被摧毀時,其所有的孩子都將被毀滅。因此,在Qt中,通常的做法是使用new分配堆棧上的對象,給它們一個父項,而不是自己的內存。這些規則變得更加複雜,QLayout這樣變得有時候Qt對象會獲取窗口小部件的所有權,有時它們不會。

就你而言,你可能不需要撥打deleteLater。它向Qt的內部事件循環發佈消息。消息說:「當你有機會時刪除我!」如果你想讓班級管理wd,只需給它一個this的父母。然後,當您的課程被刪除時,整個父/子樹將被刪除。

+0

在我的情況下,{this}指針指向一個普通的C++類,而不是從Qobject繼承。當這個類的析構函數被調用時,它仍然不會刪除wd,甚至不會隱藏它(在將它初始化爲指針的情況下)。正如我從你那裏瞭解到的那樣,當我說{刪除}一個小部件指針時,Qt並不在乎。那麼我怎樣才能從內存中刪除這樣的小部件。我需要在QScrollbar中動態分配標籤,每當我按下按鈕時,此QScrollbar被刷新,刪除舊標籤後在QScrollbar中分配新標籤 – Tarek

+0

此答案已過時,即使使用C++ 98也已過時。典型的C++規則是:將資源管理委託給資源管​​理類,例如智能指針。你不應該手工編寫任何'刪除' - 如果必要的話,C++不是C的。 –

+0

美妙的閱讀理解。在談到RIAA的時候,你有沒有把第二句話排除在外? –

0

這一切都很簡單。 QObject派生類就像任何其他C++類一樣,但有一個例外:如果一個QObject有孩子,它將刪除它的析構函數中的孩子。請記住QWidget是-a QObject. If you have an instance allocated using new`,你必須刪除它,或者確保某個東西(一個智能指針!)。

當然,試圖delete東西你沒有動態分配是一個錯誤,即:

  1. 如果沒有動態分配一個QObjectdeleteLaterdelete它。

  2. 如果您沒有動態分配QObject的子項,請確保它們在對象被破壞之前已經消失。

此外,不要隱藏你即將銷燬部件。沒有用。

自行管理部件的壽命,你應該使用智能指針:

class MyClass { 
    QScopedPointer<QWidget> m_widget; 
public: 
    MyClass() : 
    widget{new QWidget}; 
    { 
    auto wd = m_widget->data(); 
    auto pb = new QProgressBar{wd}; 
    auto label = new QLabel{wd}; 
    } 
}; 

當你破壞MyClass,該範圍的指針的析構函數將刪除控件實例,其QObject::~QObject析構函數將刪除其孩子。

當然,這一切都不是必要的:你應該簡單地創建對象作爲類的直接成員:

class MyClass { 
    // The order of declaration has meaning! Parents must precede children. 
    QWidget m_widget; 
    QProgressBar m_bar{&m_widget}; 
    QLabel m_label{&m_widget}; 
public: 
    MyClass() {} 
}; 

通常你會使用佈局子控件:

class MyClass { 
    QWidget m_widget; 
    QVBoxLayout m_layout{&m_widget}; 
    QProgressBar m_bar; 
    QLabel m_label; 
public: 
    MyClass() { 
    m_layout.addWidget(&m_bar); 
    m_layout.addWidget(&m_label); 
    } 
}; 

將小部件添加到佈局時,會將它們還原到佈局已設置的小部件。

編譯器生成的析構函數如下所示。你不能編寫這樣的代碼,因爲編譯器生成的代碼會雙重銷燬已經銷燬的對象,但是讓我們假裝你可以。

MyClass::~MyClass() { 
    m_label.~QLabel(); 
    m_bar.~QProgressBar(); 
    m_layout.~QVBoxLayout(); 
    // At this point m_widget has no children and its `~QObject()` destructor 
    // won't perform any child deletions. 
    m_widget.~QWidget(); 
} 
+0

你的答案是非常豐富的,並教會了我很多,但我仍然不明白爲什麼刪除(wd)不工作..正如你所說當我使用刪除(父窗口部件)它應該被銷燬,也是兒童,但這根本沒有發生在我身上。這甚至看起來更復雜,當我使用{std :: vector labelPointers}這樣的向量時,它就像是不可能釋放這個labelPointers向量的內存,你能解釋更多嗎? – Tarek

+0

@Tarek你不顯示完整的代碼,所以我們不能幫你在這裏。你在這個問題上顯示的是完全不足的。換句話說,它對我來說都很好。不要用文字。使用代碼。你的例子應該很短。最多考慮50-75行,全部在一個文件中。刪除不必要的東西看看例如[我的答案的github存儲庫](https://github.com/KubaO/stackoverflown)獲取靈感。他們中的大多數很短,他們都應該編譯。 –