5

タイマーを使用してアニメーションを実行するGtk+コードを記述しています。ほとんどの場合、アプリケーションを閉じるアイコンをクリックすると、ターミナルに次のメッセージが表示されます。CCairo

Gtk-CRITICAL **:gtk_widget_queue_draw:アサーション `GTK_IS_WIDGET(widget)'が失敗しました

アプリケーションを閉じた瞬間にタイマーが起動し、メインウィンドウウィジェットにアクセスしましたが、その後破棄されたため、これはうまくいっていると思います。Gtkウィジェットがまだ有効で参照できるかどうかを判断するための通常の方法は何ですか?

問題のあるコードは次のとおりです。

gboolean rotate_cb( void *degrees )
{
    rotation += DegreesToRadians((*(int*)(degrees)));
    // Tell our window that it should repaint itself (ie. emit an expose event)
    /* need to only call gtk_widget_queue_draw() if window is still valid / exists */
    gtk_widget_queue_draw(window);
    return( TRUE );
}

windowまだアクティブで有効かどうかをテストする方法があるはずだと思いますか?

4

3 に答える 3

11

あなたの問題は非常に微妙です。これは通常、GObject/GtkObjectの所有権と破棄のルールが原因で発生します。それらに思い出させてください:

  • GObjectsは単にカウント参照されます。カウントが0に達すると、それらは破棄されます。新しく作成されたオブジェクトのカウントは1です。
  • GInitiallyUnownedsもカウント参照され、カウントが0に達すると破棄されます。ただし、新しく作成されたオブジェクトには浮動カウントがあります。つまり、カウントが最初にインクリメントされるときは実際にはインクリメントされませんが、フローティングカウントは沈められます。つまり、通常の参照に変換されます。

GtkObjects GInitiallyUnownedオブジェクトであるため、マジックフローティングカウントがあります。

しかし、あなたはおそらくこれをすべて知っているでしょう...さて、私の質問:

表示されているメインのGtkWindowのカウンターを所有しているのは誰ですか?

それは実際には簡単です。GTKフレームワークにはこれらのリストがあり、表示されているすべてのの参照を保持していますGtkWindow。しかし、別の質問:

GTKフレームワークはいつGtkWindowの参照を解放しますか?

gtk_widget_destroy()機能とdestroy信号を覚えていますか?GtkWindowそれらはまさにそのためのものです:あなたが呼び出すトップレベルを削除したいとき、それは実際のウィンドウを削除してオブジェクトへの参照を解放するGTKフレームワークによって受信されるgtk_widget_destroy()シグナルをアクティブにします。destroy

そして、ここにあなたの問題の理由があります:GTKフレームワークがへの唯一の既存の参照を保持している場合GtkWindow、オブジェクトは実際に解放されます。その後、タイマーがそれにアクセスしようとすると、ウィンドウがなくなったため、タイマーは失敗します。

そして、ここで、ついに、(うまくいけば)解決策が来ます:

  • g_object_ref()/g_object_ref_sink()タイマーを開始するときにウィンドウを呼び出します。destroyまた、ウィンドウのシグナルにハンドラーを登録します。
  • ウィンドウのシグナルのハンドラーでdestroy:ウィンドウを呼び出しg_object_unref()てタイマーを停止します。

destroy当然、この部分的な解決策も機能するはずです。これは、信号を送信しないとウィンドウが破壊されないためです。

  • destroyウィンドウのシグナルにハンドラーを登録します。
  • ウィンドウの信号のハンドラーでdestroy:タイマーを停止します。

ただし、実際にオブジェクトへのポインタを保持している場合は、オブジェクトのref-counterをインクリメントすることをお勧めします。

于 2012-06-14T19:44:09.307 に答える
3

メモリに存在しなくなったオブジェクトの状態、つまり未定義のメモリのチャンクの状態を照会するため、方法はありません。同じメモリアドレスに別のウィジェットが作成されている場合など、このような関数は失敗する可能性があります。GTK_IS_WIDGET()原則として、そのマクロを使用することもできますが、ほとんどの場合正しく機能することが保証されていません。

問題を解決する正しい方法は、代わりに、破棄されたrotate_cb()ときにコールバックを削除することです。そのためのクラスにwindowは「破壊」信号があります。GtkWidgetしたがって、「破棄」に接続し、そのハンドラーで削除するrotate_cb()(または何もしないフラグを設定するrotate_cb())必要があります。

于 2012-06-14T19:24:32.583 に答える
3

g_object_weak_ref()これらの場合にも役立ちます

弱参照は、オブジェクトがファイナライズされたときの通知に使用されます。

弱いrefコールバックを(例によって)接続して、ウィジェットが破棄される前にウィジェットwidget_destroy_cbから切断することができるため、ウィジェットが破棄されたら呼び出さないでください。rotate_cbrotate_cb

于 2012-06-15T23:06:32.497 に答える