これは、リソースの使用を扱うGTK2に関する私の最後の質問のフォローアップです。
GtkImages
アプリケーションは画像を適切に表示していますが、ディスクからロードされ、絶対位置に固定フレームに配置されるたびに、メモリがリークしているように見えます。
数秒ごとに呼び出される次の基本的な方法を使用して、さまざまな画像のセットを読み込んで表示しています。
int DisplaySymbols( GameInfo *m )
{
// variable declarations removed for brevity
// error checking needs to be added
GtkWidget *image;
pos_y = 150;
for( y = 0; y < 3; y++ )
{
pos_x = 187;
for( x = 0; x < 5; x++ )
{
image=gtk_image_new_from_file( fileName );
gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y);
pos_x += symbols[i].pixel_width;
}
pos_y += symbols[i].pixel_height;
}
gtk_widget_show_all(window);
return( 0 );
}
リソースの使用に関するドキュメントの一部を読みましたが、メモリリークを防ぐために呼び出しをGTK+
使用する方法を完全に理解することはできません。API
私が持っているいくつかの考えや質問:
- フレームに配置された画像をより簡単に管理するために、固定フレームに画像保持ウィジェットを作成する必要がありますか?
- 私のコードは何をしているのか、していないので、メモリがリークしていますか?
GtkImage
ウィジェットをリリースしない可能性がありますか? - 使用するたびにディスクからイメージをロードするのは少し非効率的なようです。それらをメモリに読み込んで、必要に応じてフレームに表示するにはどうすればよいですか?
部分的なソースコードは次のとおりです。
//Compile me with: gcc -o leak leak.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
// include files removed for brevity
/* GTK */
#include <gdk/gdkx.h>
#include <gtk/gtk.h>
typedef struct
{
unsigned int pixel_width, pixel_height;
gchar fileName[20];
}symbol_t;
static symbol_t symbols[] =
{
/* only showing 2 of eight - brevity */
{ 118, 107, "images/LO.jpg" },
{ 118, 107, "images/L1.jpg" }
};
typedef struct
{
char SpinResult[3][5]; // index of images pointing into symbols struct
}GameInfo;
GameInfo egm;
GtkWidget *frame; /* for absolute positionining of widgets */
GtkWidget *window;
/**** prototypes ****/
// remove for brevity
/********************/
// init random number generator
int Init( void )
{
// create random number - brevity
}
// Determine spin outcome and store into egm.SpinResult array
int DoSpin( GameInfo *egm )
{
// generate matrix of indexes into symbols structure
// so we know what symbols to display in the frame
}
int DisplaySymbols( GameInfo *egm )
{
// variable declarations removed - brevity
GtkWidget *image;
pos_y = 150;
for( y = 0; y < 3; y++ )
{
pos_x = 187;
for( x = 0; x < 5; x++ )
{
image = gtk_image_new_from_file( symbols[i].fileName );
gtk_fixed_put(GTK_FIXED(frame), image, pos_x, pos_y);
pos_x += symbols[i].pixel_width;
}
pos_y += symbols[i].pixel_height;
}
gtk_widget_show_all(window);
return( 0 );
}
void btnSpin_clicked(GtkWidget *button, gpointer data)
{
DoSpin( &egm );
DisplaySymbols( &egm );
return;
}
GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
// window setup code removed for brevity
return(window);
}
int main (int argc, char *argv[])
{
GtkWidget *btnSpin, *btnExit;
float spinDelay = 2.0;
Init();
gtk_init (&argc, &argv);
window = SetupWindow("Tournament", "images/Midway_Madness_Shell.jpg");
g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);
frame = gtk_fixed_new();
gtk_container_add(GTK_CONTAINER(window), frame);
btnSpin = gtk_button_new_with_label("Spin");
gtk_widget_set_size_request(btnSpin, 70, 40);
gtk_fixed_put(GTK_FIXED(frame), btnSpin, 720, 540);
g_signal_connect(G_OBJECT( btnSpin ), "clicked", G_CALLBACK(btnSpin_clicked), NULL );
btnExit = gtk_button_new_with_label("Exit");
gtk_widget_set_size_request(btnExit, 70, 40);
gtk_fixed_put(GTK_FIXED(frame), btnExit, 595, 540);
g_signal_connect(G_OBJECT( btnExit ), "clicked", G_CALLBACK(btnExit_clicked), NULL );
DoSpin( &egm );
DisplaySymbols( &egm );
gtk_widget_show_all(window);
gtk_main ();
return( 0 );
}
GTK2
オブジェクトの定義を提供しているように見えるドキュメントから読んだものを適用する方法を理解するのに苦労しているので、この問題を解決する方法の詳細な説明といくつかのサンプルコードに非常に感謝しますそして関数呼び出し。非常に徹底的な対応が必要な場合は、見事な報奨金を提供できます。
すべてのコードがあると便利な場合は、ここで提供します。
編集:メモリリークは2つの方法で修正されました。
- nobar
GtkFixed
によって提案されたように、イメージを再描画する前に、コンテナーを破棄して再作成します。 ポインタの2次元配列を使用し
GtkWidget
て、描画時に各画像へのポインタを保持します。画像を再描画するときは、2次元配列のウィジェットポインタが最初に次のように破棄されます。int ReleaseImages(void){u_int8_t y、x;
/* release images */ for( y = 0; y < 3; y++ ) { for( x = 0; x < 5; x++ ) { gtk_widget_destroy( ptrImages[y][x] ); } } return( 0 );
}
これで、画像リソースが解放され、新しい画像を再描画できます。