2016-07-30 2 views
0

私はQtの新機能です。ウィジェットの削除方法は非常に混乱しています。私はビデオを読んでいて、ビデオフレームが読み込まれている間にQProgressbarを表示しておき、ビデオがロードされたらこのQProgressbarを削除したかったのです。ウィジェットへのポインタの削除Qt C++

私は2種類の方法でそれを行っている:

  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(); 
    

    を使用してウィジェットはすべての子供で削除されますが、それは起こらなかったので、この関数を再度実行するたびに、新しいウィジェットが作成され、前のウィジェットを隠したり削除したりせずに作成されます(注:ウィジェットからラベルとプログレスバーを削除しようとしました彼らは内部から消えるだろう電子ウィジェットが、これは実現しなかった「(PB)を削除;」)

  2. 使用したオブジェクト私は同じコードを実行したが、代わりにポインタのオブジェクトを使用して、それが持っている

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

私が望んでいたとおりに正確に実行し、関数を実行するたびに古いウィジェットが破棄され、新しいウィジェットが作成されます。

注:ポインタの場合は、メインウィンドウを閉じると、ウィジェットはまだ存在し、プログラムを終了するまで手動で終了しません。 - オブジェクトの場合、メインウィンドウを閉じるとすべてが閉じられ、プログラムは正しく終了します。

私はこの出来事があると私は典型的なCで任意のメモリリーク

+1

私はメモリ管理がC++でどのように機能するかについては、[ブック](http://stackoverflow.com/a/388282/3484570)を読んでお勧めします。それから[Qtがどう違うのか](http://doc.qt.io/qt-5/objecttrees.html)を読んでください。 – nwp

+0

'QProgressBar'を削除する代わりに、単純に非表示にすることができます。あなたは次のストリームのためにとにかくそれを必要とすることができます。 – maxik

答えて

0

なくても、そのベクトル内のすべてのポインタを削除するには、ウィジェットへのポインタのベクトルを持っていた場合にどのように++ルールを書く」だろう、なぜ誰かが私に説明する必要が for new "となります。さらに進んだルールは、おそらく「new」または「delete」と書いてRIAAパターンに埋めるのではないでしょうか。 Qtは独自のメモリ管理パラダイムを導入するため、この点でルールを変更します。これは親子関係に基づいています。 QWidgetは、newであり、parentWidget()とすることができる。 parentWidget()が破壊されると、そのすべての子が破壊されます。したがって、Qtでは、スタック上にオブジェクトをnewで割り当て、それらに親を与え、自分自身でメモリをdeleteすることはありません。規則はQLayoutでより複雑になります。そのような場合は、Qtオブジェクトがウィジェットの所有権を取得することがあります。

あなたの場合、おそらくdeleteLaterコールは必要ありません。これは、Qtの内部イベントループにメッセージを投稿します。メッセージには、「あなたがチャンスを取ったときに私を削除してください!クラスがwdを管理したい場合は、それにthisの親を与えてください。クラスが削除されると、親子ツリー全体が削除されます。

+0

私の場合、{this}ポインタはQobjectから継承しない通常のC++クラスを指しています。このクラスのデストラクタが呼び出されると、wdを削除したり、ポインタを初期化する(ポインタとして初期化する)ことさえしません。あなたがウィジェットポインタに{delete}と言うとき、Qtはそれほど気にしないことを私は理解しています。だから私はどのようにメモリからそのようなウィジェットを削除することができます。 QScrollbarにラベルを動的に割り当てる必要があります。このQScrollbarが更新され、古いラベルが削除された後に新しいラベルがQScrollbarに割り当てられると、 – Tarek

+0

この回答は廃止され、C++ 98では廃止されました。典型的なC++ルールは、リソースをスマートポインタなどのリソース管理クラスに管理するデリゲートです。あなたは手で 'delete'sを書くべきではありません.C++はCが必要な場所ではありません。 –

+0

素晴らしい読解力。あなたはRIAAについて話した文2で空白にしましたか? –

0

これはすべて簡単です。 QObject-derivedクラスは他のC++クラスとまったく同じですが、例外として、QObjectに子がある場合は、そのデストラクタ内の子を削除します。 QWidget is-a QObject. If you have an instance allocated using new`を忘れないようにしてください。削除するか、何か(スマートポインタ!)を実行する必要があります。もちろん

、あなたが動的に割り当てられませんでしたdelete何かしようとするので、エラーです:

  1. あなたが動的にQObjectを割り当てていない場合は、はないdeleteLaterまたはdeleteそれを行います。

  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

あなたの答えは非常に有益であり、私にはたくさん教えられましたが、私はまだdelete(wd)が動作していない理由を理解していません..あなたが削除(親ウィジェット)を使用すると言うと破棄する必要があります。私にはまったく起こりませんでした。これは、{std :: vector labelPointers}のようなベクターを使用した場合、さらに複雑に見えました。このlabelPointersベクターのメモリを解放するのは不可能です。もっと説明してください。 – Tarek

+0

@Tarek完全なコードは表示されないので、ここではお手伝いできません。あなたがその質問に示すものは、まったく不十分です。言い換えれば、それはすべて私のためにうまく動作します。言葉を使わないでください。コードを使用する。あなたの例は短いはずです。たいていの場合、50-75行を1つのファイルにまとめます。不要なものはすべて削除してください。例えば[私の答えのgithubリポジトリ](https://github.com/KubaO/stackoverflown)のインスピレーション。それらのほとんどは非常に短く、すべてコンパイルする必要があります。 –

関連する問題