2017-04-02 10 views
0

Ich ändere die Pixbuf-Daten eines Bildes als Reaktion auf ein Timer-Ereignis, aber die Änderungen erscheinen nur, wenn ich zum Beispiel das Fenster mit einem anderen Fenster verdecke und es dann freilege. Wie kann ich die Änderungen anzeigen lassen, sobald ich sie vorgenommen habe?gtk display geändertes Bild

#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, aber normalerweise müssen Sie eine Art "update" -Ereignis für das Fenster generieren. Dies wird normalerweise auch vom Window-Manager generiert, wenn sich der sichtbare Bereich ändert. – Olaf

+0

Wird diese vorherige Frage verwendet? [Wie zu aktualisieren, ein Fenster (Widget) in GTK neu zu zeichnen?] (Http://stackoverflow.com/questions/32308231/how-to-refresh-redraw-a-window-widget-in-gtk) –

+0

Hier ist ein weiterer . [Wie erzwingen Sie eine Bildschirmaktualisierung in GTK 3.8?] (Http://stackoverflow.com/questions/34912757/how-do-you-force-a-screen-refresh-in-gtk-3-8) –

Antwort

0

GtkImage ist keine allgemeine Zeichnung Widget, für die Sie GtkDrawingArea brauchen würde. Ich denke, der einfachste Weg zu tun, was Sie wollen mit der GtkImage ist, aktualisieren Sie Ihre GdkPixBuf dann setzen Sie die GtkImage mit dem aktualisierten Bild. Ich habe die Referenzzahl auf die PixBuf erhöht, aber ich bin nicht 100% sicher, dass es benötigt wird, aber es schadet nicht.

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