Search code examples
cwidgetgtk

How to remove an image from a widget gtk c?


I am currently working on an user interface with gtk. What I've done for now is that you can select an image from your file and display it with the button "open". The problem is that when I open a second image it add the image to the window without removing the current one. I would like to know how to change the displayed image when the user choose to open another image. My code:


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

#include "SDL/SDL.h"
#include "SDL/SDL_image.h"

#include "../Threshold/delete_color.h"


#define GTK_STOCK_CANCEL ((GtkStock)"gtk-cancel")


GtkWidget *image; 
gchar* path;


void cb_quit(GtkWidget *p_widget, gpointer user_data)
{
    gtk_main_quit();
    (void)p_widget;
    (void)user_data;
}

void solve(const gchar* path)
{
    SDL_Surface* image;

    // Binarization
    image = binarization((char*) file_name);
    SDL_SaveBMP(image, "binarize.bmp");

    // Rotation
    //rotation(image);
    SDL_SaveBMP(image, "rotation.bmp");

    // Grid Detection
    SDL_SaveBMP(image, "grid.bmp");

    // Case detection
    // TODO
    
    // Get the grid.txt
    // TODO
    
    // Get the grid solution
    // TODO

    // Create the solution image
    // TODO
}
static void set_image(const gchar *file_name, gpointer user_data)
{
    GtkWidget *pVBox;
    GdkPixbuf *pixbuf;
    GError *error = NULL;

    pVBox = (GtkWidget*) user_data;
    
    int width = gtk_widget_get_allocated_width(pVBox);
    int height = gtk_widget_get_allocated_height(pVBox);

    pixbuf = gdk_pixbuf_new_from_file("result.bmp", &error);

    if (!error)
    {
        GdkPixbuf *pixbuf_mini = NULL;
        pixbuf_mini = gdk_pixbuf_scale_simple(pixbuf,
                width,
                height - 200,
                GDK_INTERP_NEAREST);

        image = gtk_image_new_from_pixbuf(pixbuf_mini);
        gtk_container_add(GTK_CONTAINER(pVBox), image);
        gtk_widget_show(image);
    }
}

void cb_open(GtkWidget *p_widget, gpointer user_data)
{
    GtkWidget *p_dialog = NULL;
    p_dialog = gtk_file_chooser_dialog_new("Open file", NULL,
            GTK_FILE_CHOOSER_ACTION_OPEN,
            GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
            GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
            NULL);

    if(gtk_dialog_run (GTK_DIALOG (p_dialog)) == GTK_RESPONSE_ACCEPT)
    {
        gchar *file_name = NULL;
        path = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (p_dialog));
        file_name = path;
        g_print("%s\n", path);
        set_image(file_name, user_data);
        g_free (file_name), file_name = NULL;
    }

    gtk_widget_destroy(p_dialog);
    (void)p_widget;
}

int main(int argc, char **argv)
{
    GtkWidget *p_window = NULL;
    GtkWidget *p_main_box = NULL;

    // Initialisation
    gtk_init (&argc, &argv);

    // Main window
    p_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(p_window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(p_window), 600, 400);
    g_signal_connect (G_OBJECT (p_window), "destroy",
            G_CALLBACK (cb_quit), NULL);

    // Main container
    p_main_box = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER (p_window), p_main_box);

    // Exit button
    {
        GtkWidget *p_button = NULL;
        p_button = gtk_button_new_with_label("Exit");
        g_signal_connect(G_OBJECT (p_button), "clicked", G_CALLBACK (cb_quit), NULL);
        gtk_box_pack_start(GTK_BOX (p_main_box), p_button, FALSE, FALSE, 0);
    }

    // Open button
    {
        GtkWidget *p_button = NULL;
        p_button = gtk_button_new_with_label ("Open");
        g_signal_connect (G_OBJECT (p_button), "clicked", G_CALLBACK (cb_open), (gpointer*) p_main_box);
        gtk_box_pack_start (GTK_BOX (p_main_box), p_button, FALSE, FALSE, 0);
    }

    // Display
    gtk_widget_show_all(p_window);
    g_print("%s\n", path);
    gtk_main();
    return EXIT_SUCCESS;
}

Solution

  • You can try multiple approaches.

    1. Remove old image and add new image
      Use gtk_container_get_children to retrieve your old image if present and remove it using gtk_container_remove. Then add as you have done before.

    2. You can replace the content of the image
      Again, use gtk_container_get_children to retrieve your old image if present and replace the content using gtk_image_set_from_pixbuf.

    3. (additionally to 1 or 2 above)
      You can also create an image already when you create the container and use the pointer to that image as user_data for your callback. That would remove the need for retrieving the child from your container.