2017-04-02 82 views
0

我正在更改圖像的pixbuf數據以響應計時器事件,但僅當我用另一個窗口覆蓋窗口然後發現它時纔會出現更改。我怎樣才能讓變化一出現就立即出現?gtk顯示修改後的圖像

#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; 
} 
+0

IDK GTK,但通常你必須產生窗口的某種「更新」事件。如果可見區域改變,這通常也由窗口管理器生成。 – Olaf

+0

這是以前的問題嗎? [如何刷新,重畫一個窗口(widget)在gtk?](http://stackoverflow.com/questions/32308231/how-to-refresh-redraw-a-window-widget-in-gtk) –

+0

這是另一個。 [你如何強制屏幕刷新GTK 3.8?](http://stackoverflow.com/questions/34912757/how-do-you-force-a-screen-refresh-in-gtk-3-8) –

回答

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; 
}