3

私は次のことを行うことができました:

  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たびに画像を変更することです。最初は、新しいイメージをロードして前のイメージを置き換えるだけだと思っていましたが、これは何千回も行われるため、毎回新しいファイルを「malloc」していると思いました。これは本当ですか?または、ファイルを置き換えるだけで、新しいファイルを追加しませんか?leds[i].pos.xleds[i].pos.ygtk_image_new_from_file

ありがとう

4

3 に答える 3

4

これは、ウィンドウに50x50の「LED」アレイを作成し、それらをクリックしてステータスを切り替えることができる実例です。これはそれほど効率的ではありません。コメントで指摘したように、GtkLayoutに自分で画像を描画する方が良いですが、これは少なくとも概念実証として機能します。

編集:サンプルコードを更新して、 liberforceの提案を考慮に入れました。これにより、物事がよりクリーンになり、メモリ効率が向上します。

#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;
}
于 2013-01-16T20:39:23.083 に答える
2

GtkImage1つの解決策は、LEDが存在するポジションごとに1つ作成することです。gtk_image_new_from_file画像ファイルが読み込まれるたびに読み込まれるため、使用しないでください。その代わり:

  • gdk_pixbuf_new_from_file2つの画像ファイルのそれぞれを呼び出す
  • 各画像ウィジェットを作成するために呼び出し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ウィジェットのサイズが再計算されるため、最も単純なサイズ計算オプションを使用しただけです。
于 2013-01-17T09:40:30.683 に答える
0

これはわかりませんが、2つの画像を画面上の同じ位置に配置してから、必要な画像を表示し、不要な画像を非表示にする必要があります。それが良い方法かどうかはわかりませんが、あなたがこの方法を使って物を割り当てているのではないと確信しています。

gtk_widget_hide(your_image2);
gtk_widget_show(your_image1);

それが役に立てば幸い。

よろしく、

于 2013-01-16T18:04:13.283 に答える