C 单击鼠标更改图像

C 单击鼠标更改图像,c,gtk,gtk2,C,Gtk,Gtk2,我已经能够做到以下几点: 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; } f

我已经能够做到以下几点:

  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;
  }
for(int i=0;i
基本上,这会将一组“LED”图像加载到某个窗口上

我需要的是每次单击
led[I].pos.x
led[I].pos.y时,将图像
ledoff
更改为
ledon
。起初,我以为这只是加载一个新图像并替换上一个图像的问题,但后来由于这将被执行数千次,我认为每次我从文件中执行
gtk_image_new_时,我都在“malloc'ing”一个新文件!这是真的吗?还是我只是替换了文件而没有添加新文件


谢谢

我不确定这一点,但您应该将两张图像放在屏幕上相同的位置,然后显示您需要的图像,隐藏您不需要的图像。我不知道这是否是一个很好的方法,但我很确定你没有用这种方式分配东西

gtk_widget_hide(your_image2);
gtk_widget_show(your_image1);
希望能有帮助


关于,

这里是一个工作示例,它在窗口中创建一个50x50“LED”阵列,并允许您通过单击它们来切换其状态。这并不是很有效,正如我在评论中指出的,你最好自己在GtkLayout上绘制图像,但这至少可以作为概念证明

Edit:我已经更新了示例代码,以将其考虑在内,从而使事情更干净、内存效率更高

#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;
}
#包括
#定义图标宽度16
#定义图标高度16
#定义个数
类型定义枚举{
在…上
关
}领导地位;
类型定义结构{
GtkWidget*img;
结构{
金特x;
金特y;
}pos;
led_状态;
}led;
静态发光二极管[NUM_发光二极管];
静态GdkPixbuf*led_亮起;
静态GdkPixbuf*led_关闭;
静态gboolean点击处理程序(GtkWidget*小部件,
GdkEvent*事件,
gpointer用户(U数据)
{
led*信息=用户数据;
如果(信息->状态==打开){
gtk_图像设置(gtk_图像(信息->图像),led关闭);
信息->状态=关闭;
}否则{
gtk_图像设置(gtk_图像(信息->图像),发光二极管亮起);
信息->状态=打开;
}
返回TRUE;
}
int main(int argc,字符**argv)
{
GtkWidget*窗口,*布局;
int i=0,x,y;
gtk_init(&argc,&argv);
/*加载我们的图像(忽略错误-就像任何好的示例代码一样)*/
led_on=gdk_pixbuf_new_from_文件(“led on.png”,NULL);
led_off=gdk_pixbuf_new_from_文件(“led off.png”,NULL);
/*初始化我们的数组*/
对于(x=0;x<50;x++){
对于(y=0;y<50;y++){
发光二极管[i]。img=gtk_image_new();
发光二极管[i]。位置x=x*图标宽度;
发光二极管[i]。位置y=y*图标高度;
发光二极管[i]。状态=关闭;
/*从已加载的pixbuf初始化图像*/
来自pixbuf的gtk_图像设置(gtk_图像(led[i].img),led_关闭);
i++;
}
}
/*创建一个窗口*/
窗口=gtk_窗口_新建(gtk_窗口_顶层);
gtk_窗口设置标题(gtk_窗口(窗口),“LED”);
gtk_信号_连接(gtk_对象(窗口),
“摧毁”,
G_回调(gtk_main_退出),
无效);
/*创建小部件*/
布局=gtk_布局_新建(空,空);
对于(i=0;i
一种解决方案是为每个有led的位置创建一个
GtkImage
。不要使用
gtk\u image\u new\u from\u file
,因为它会在每次加载图像文件时加载。相反:

  • 为两个图像文件中的每一个调用
    gdk\u pixbuf\u new\u from\u file
  • 调用
    gtk\u image\u new
    创建每个图像小部件,并立即 使用正确的像素缓冲区初始化它们
    gtk\u图像\u设置\u来自\u pixbuf
  • 当您需要更改显示的图像时,只需获取相应的先前创建的
    GtkImage
    ,然后从
gtk\u image\u set\u更改显示的图像即可 这确保了低内存消耗:您只分配了2个像素缓冲区(以及从GtkImage实例中计数的引用),并且每个led只创建一个GtkImage(而不是每次更改显示的图像时销毁/创建一个)

编辑:这里是肖恩·布莱特提交的一个改进版本,其中我修正了一些错误

#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;
}
#包括
#每行定义最大发光二极管数50
#定义个数
静态GdkPixbuf*led_亮起;
静态GdkPixbuf*led_关闭;
静态gboolean点击处理程序(GtkWidget*小部件,
GdkEvent*事件,
gpointer用户(U数据)
{
gboolean*是否亮起=用户数据;
GList*children=gtk_容器_获取_子对象(gtk_容器(小部件));
*发光二极管是否亮起=!*发光二极管是否亮起;/*反转发光二极管状态*/
gtk_图像设置(gtk_图像(子对象->数据),(*led_是否亮起)?led_亮起:led_熄灭);
g_清单_免费(儿童);
返回TRUE;/*停止事件传播*/
}
int main(int argc,字符**argv)
{
GtkWidget*窗口,*表格;
gboolean发光二极管[NUM_发光二极管];
int i=0;
gtk_init(&argc,&argv);
/*创建一个窗口*/
窗口=gtk_