一种解决方案是GtkImage
为每个有 LED 的位置创建一个。不要使用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 创建一个 GtkImage(而不是在每次更改显示的图像时销毁/创建一个)。
编辑:这是对 Sean Bright 提交的改进,其中我修复了一些错误。
#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
回调的返回值
- 我删除了结构,因为我们只需要一个布尔值来了解 LED 状态。它甚至可以是存储在 GtkImage 中的一个属性,但将后端逻辑与用户界面分开通常是个好主意。
- 我使用 GtkTable 而不是 GtkLayout,因为我认为不需要像素精确地放置 LED。不过,在 GTK 3 中,GtkTable 被 GtkGrid 取代。然而,GtkTable 在使用 gtk_table_add_defaults 时遇到了困难,因为调整窗口大小会导致重新计算 2500 个小部件的大小,所以我只使用了最简单的大小计算选项。