GtkImage
1つの解決策は、LEDが存在するポジションごとに1つ作成することです。gtk_image_new_from_file
画像ファイルが読み込まれるたびに読み込まれるため、使用しないでください。その代わり:
gdk_pixbuf_new_from_file
2つの画像ファイルのそれぞれを呼び出す
- 各画像ウィジェットを作成するために呼び出し
gtk_image_new
、すぐに使用して適切なピクセルバッファでそれらを初期化します
gtk_image_set_from_pixbuf
- 表示される画像を変更する必要がある場合は、以前に作成した対応する画像を取得し、で表示される
GtkImage
画像を変更します。gtk_image_set_from_pixbuf
これにより、メモリ消費量を低く抑えることができます。割り当てられるピクセルバッファは2つだけであり(GtkImageインスタンスから参照カウントされます)、LEDごとに1つのGtkImageのみを作成します(表示される画像を変更するたびに1つを破棄/作成するのではありません)。
編集:これはショーンブライトの提出物の改善であり、私はいくつかの間違いを修正しました。
#include <gtk/gtk.h>
#define MAX_LEDS_PER_LINE 50
#define NUM_LEDS 2500
static GdkPixbuf * led_on;
static GdkPixbuf * led_off;
static gboolean click_handler(GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
gboolean *is_led_on = user_data;
GList * children = gtk_container_get_children (GTK_CONTAINER (widget));
*is_led_on = ! *is_led_on; /* invert led state */
gtk_image_set_from_pixbuf (GTK_IMAGE(children->data), (*is_led_on) ? led_on : led_off);
g_list_free (children);
return TRUE; /* stop event propagation */
}
int main(int argc, char** argv)
{
GtkWidget *window, *table;
gboolean leds[NUM_LEDS];
int i = 0;
gtk_init(&argc, &argv);
/* Create a window */
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_title(GTK_WINDOW(window), "LEDs");
gtk_signal_connect(GTK_OBJECT(window),
"destroy",
G_CALLBACK(gtk_main_quit),
NULL);
/* Load leds on/off images */
led_on = gdk_pixbuf_new_from_file ("on.png", NULL);
led_off = gdk_pixbuf_new_from_file ("off.png", NULL);
/* Create the container */
int n_rows = (NUM_LEDS / MAX_LEDS_PER_LINE) + 1;
int n_cols = (NUM_LEDS / MAX_LEDS_PER_LINE) + 1;
table = gtk_table_new (n_rows, n_cols, FALSE);
/* Create the leds */
for (i = 0; i < NUM_LEDS; i++)
{
leds[i] = FALSE; /* FALSE means OFF, TRUE means ON */
/*
* A GtkImage doesn't have a window, so we need to put it inside
* a GtkEventBox so we can capture events.
*/
GtkWidget *image = gtk_image_new ();
gtk_image_set_from_pixbuf (GTK_IMAGE(image), led_off);
GtkWidget *eb = gtk_event_box_new();
g_signal_connect(G_OBJECT(eb),
"button-press-event",
G_CALLBACK(click_handler),
&leds[i]);
gtk_container_add(GTK_CONTAINER(eb), image);
int row = i / MAX_LEDS_PER_LINE;
int col = i % MAX_LEDS_PER_LINE;
gtk_table_attach (GTK_TABLE(table),
eb,
row, row + 1,
col, col + 1,
0,
0,
0,
0);
}
gtk_container_add(GTK_CONTAINER(window), table);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
ここで、最初の発言を実装し、いくつかの点を改善しました。
click_handler
コールバックの署名を修正しました
click_handler
コールバックの戻り値を修正しました
- 導かれた状態を知るためにブール値が必要なだけなので、構造体を削除しました。GtkImageに格納されているプロパティである可能性もありますが、多くの場合、バックエンドロジックをユーザーインターフェイスから分離することをお勧めします。
- LEDをピクセル単位で正確に配置する必要がないため、GtkLayoutの代わりにGtkTableを使用しました。ただし、GTK 3では、GtkTableはGtkGridに置き換えられています。ただし、GtkTableではgtk_table_add_defaultsに問題がありました。これは、ウィンドウのサイズを変更すると2500ウィジェットのサイズが再計算されるため、最も単純なサイズ計算オプションを使用しただけです。