gtk显示修改后的图像

时间:2017-04-02 17:20:49

标签: c gtk3

我正在更改图像的pixbuf数据以响应计时器事件,但只有当我用另一个窗口覆盖窗口然后将其揭开时才会出现更改。如何在我制作后立即显示更改?

#include <gtk/gtk.h>
#include <stdlib.h>

#define ROWS 400
#define COLS 400  // must be divisible by 4
#define BYTES_PER_PIXEL 3

typedef struct {
  GtkImage *image;
  int stride;
} ImageData;

void free_pixels(guchar *pixels, gpointer data) {
  free(pixels);
}

void setrgb(guchar *a, int row, int col, int stride,
            guchar r, guchar g, guchar b) {
  int p = row * stride + col * BYTES_PER_PIXEL;
  a[p] = r; a[p+1] = g; a[p+2] = b;
}

int update_pic(gpointer data) {
  static int row = 0;
  if (row > 100) return FALSE;

  ImageData *id = (ImageData*)data;
  GdkPixbuf *pb = gtk_image_get_pixbuf(id->image);
  guchar *g = gdk_pixbuf_get_pixels(pb);

  for (int c = 0; c < 200; c++)
    setrgb(g, row, c, id->stride, 255, 0, 0);
  row++;

  // this is not enough to get it to show the updated picture
  gtk_widget_queue_draw(GTK_WIDGET(id->image));

  // adding this does not fix it
  while (g_main_context_pending(NULL))
    g_main_context_iteration(NULL, FALSE);

  return TRUE;
}

int main(int argc, char **argv) {
  GtkWidget *window, *image;
  GdkPixbuf *pb;
  guchar *pixels = calloc(ROWS * COLS, BYTES_PER_PIXEL);
  ImageData id;

  gtk_init(&argc, &argv);

  image = gtk_image_new();
  id.image = GTK_IMAGE(image);
  id.stride = COLS * BYTES_PER_PIXEL;  // COLS is divisible by 4
  pb = gdk_pixbuf_new_from_data(
    pixels,
    GDK_COLORSPACE_RGB,     // colorspace
    0,                      // has_alpha
    8,                      // bits-per-sample
    COLS, ROWS,             // cols, rows
    id.stride,              // rowstride
    free_pixels,            // destroy_fn
    NULL                    // destroy_fn_data
  );
  gtk_image_set_from_pixbuf(GTK_IMAGE(image), pb);
  g_object_unref(pb); // should I do this?

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "image");
  gtk_window_set_default_size(GTK_WINDOW(window), COLS, ROWS);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

  gtk_container_add(GTK_CONTAINER(window), image);

  g_timeout_add(250,         // milliseconds
                update_pic,  // handler function
                &id);        // data

  gtk_widget_show_all(window);
  gtk_main();

  return 0;
}

1 个答案:

答案 0 :(得分:0)

GtkImage不是常规绘图窗口小部件,因为您需要GtkDrawingArea。我认为使用GtkImage执行所需操作的最简单方法是更新GdkPixBuf,然后使用更新的图像设置GtkImage。我已将引用计数增加到PixBuf,但我不是100%确定它是否需要,但它没有任何伤害。

#include <gtk/gtk.h>
#include <stdlib.h>

#define ROWS 400
#define COLS 400  // must be divisible by 4
#define BYTES_PER_PIXEL 3

typedef struct {
  GtkImage *image;
  GdkPixbuf *pb;
  int stride;
} ImageData;

void free_pixels(guchar *pixels, gpointer data) {
  free(pixels);
}

void setrgb(guchar *a, int row, int col, int stride,
            guchar r, guchar g, guchar b) {
  int p = row * stride + col * BYTES_PER_PIXEL;
  a[p] = r; a[p+1] = g; a[p+2] = b;
}

int update_pic(gpointer data) {
  static int row = 0;
  if (row > 100) return FALSE;

  ImageData *id = (ImageData*)data;
  guchar *g = gdk_pixbuf_get_pixels(id->pb);

  for (int c = 0; c < 200; c++)
    setrgb(g, row, c, id->stride, 255, 0, 0);
  row++;

  // Update the image, by setting it.
  gtk_image_set_from_pixbuf(GTK_IMAGE(id->image), id->pb);

  return TRUE;
}

int main(int argc, char **argv) {
  GtkWidget *window;
  guchar *pixels = calloc(ROWS * COLS, BYTES_PER_PIXEL);
  ImageData id;

  gtk_init(&argc, &argv);

  id.stride = COLS * BYTES_PER_PIXEL;  // COLS is divisible by 4
  id.pb = gdk_pixbuf_new_from_data(
    pixels,
    GDK_COLORSPACE_RGB,     // colorspace
    0,                      // has_alpha
    8,                      // bits-per-sample
    COLS, ROWS,             // cols, rows
    id.stride,              // rowstride
    free_pixels,            // destroy_fn
    NULL                    // destroy_fn_data
  );
  id.image = GTK_IMAGE(gtk_image_new_from_pixbuf(id.pb));
  g_object_ref(id.pb);

  window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(window), "image");
  gtk_window_set_default_size(GTK_WINDOW(window), COLS, ROWS);
  gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
  g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);

  gtk_container_add(GTK_CONTAINER(window), image);

  g_timeout_add(250,         // milliseconds
                update_pic,  // handler function
                &id);        // data

  gtk_widget_show_all(window);
  gtk_main();

  g_object_unref(id.pb);

  return 0;
}