我能够做到以下几点:
for (int i = 0; i < NUM_LEDS; ++i) {
ledoff = gtk_image_new_from_file("./ledoff.png");
leds[i].pos=ledpos[i];
gtk_layout_put(GTK_LAYOUT(layout), ledoff, leds[i].pos.x, leds[i].pos.y);
leds[i].status=OFF;
}
基本上,这会将一堆“ledoff”图像加载到某个窗口上。
每次点击ledoff
,ledon
时,我需要将图片leds[i].pos.x
更改为leds[i].pos.y
。一开始我认为这只是加载一个新图像并替换前一个图像的问题,但是由于这将完成数千次,我以为我每次都在“malloc”“一个新文件{{1 }}!这是真的?或者我只是替换文件而不添加新文件?
由于
答案 0 :(得分:4)
这是一个工作示例,它在窗口中创建一个50x50“LED”阵列,并允许您通过单击它们来切换它们的状态。它并不是那么有效,正如我在评论中指出的那样,你最好自己将图像绘制到GtkLayout上,但这至少可以作为概念证明。
修改:我已更新示例代码以考虑liberforce's suggestions,这会使事情更清晰,内存效率更高。
#include <gtk/gtk.h>
#define ICON_WIDTH 16
#define ICON_HEIGHT 16
#define NUM_LEDS 2500
typedef enum {
ON,
OFF
} led_status;
typedef struct {
GtkWidget *img;
struct {
gint x;
gint y;
} pos;
led_status status;
} led;
static led leds[NUM_LEDS];
static GdkPixbuf *led_on;
static GdkPixbuf *led_off;
static gboolean click_handler(GtkWidget *widget,
GdkEvent *event,
gpointer user_data)
{
led *info = user_data;
if (info->status == ON) {
gtk_image_set_from_pixbuf(GTK_IMAGE(info->img), led_off);
info->status = OFF;
} else {
gtk_image_set_from_pixbuf(GTK_IMAGE(info->img), led_on);
info->status = ON;
}
return TRUE;
}
int main(int argc, char** argv)
{
GtkWidget *window, *layout;
int i = 0, x, y;
gtk_init(&argc, &argv);
/* Load our images (ignoring errors - as any good sample code would) */
led_on = gdk_pixbuf_new_from_file("led-on.png", NULL);
led_off = gdk_pixbuf_new_from_file("led-off.png", NULL);
/* Initialize our array */
for (x = 0; x < 50; x++) {
for (y = 0; y < 50; y++) {
leds[i].img = gtk_image_new();
leds[i].pos.x = x * ICON_WIDTH;
leds[i].pos.y = y * ICON_HEIGHT;
leds[i].status = OFF;
/* Initialize our image from the pixbuf we've already loaded */
gtk_image_set_from_pixbuf(GTK_IMAGE(leds[i].img), led_off);
i++;
}
}
/* 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);
/* Create the widget */
layout = gtk_layout_new(NULL, NULL);
for (i = 0; i < NUM_LEDS; i++) {
/*
* A GtkImage doesn't have a window, so we need to put it inside
* a GtkEventBox so we can capture events.
*/
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), leds[i].img);
gtk_layout_put(GTK_LAYOUT(layout), eb, leds[i].pos.x, leds[i].pos.y);
}
gtk_container_add(GTK_CONTAINER(window), layout);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
答案 1 :(得分:2)
一种解决方案是为每个将有一个led的位置创建一个GtkImage
。不要使用gtk_image_new_from_file
,因为它会在每次加载图像文件时加载。代替:
gdk_pixbuf_new_from_file
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
回调答案 2 :(得分:0)
我不确定这一点,但您应将2张图像放在屏幕上的相同位置,然后显示您需要的图像并隐藏您不需要的图像。我不知道这是否是一个很好的方法,但我很确定你没有用这种方式分配东西。
gtk_widget_hide(your_image2);
gtk_widget_show(your_image1);
希望它有所帮助。
此致