C语言 如何在GTK+中启动和停止GIF动画GtkImage

ogsagwnx  于 2023-11-17  发布在  其他
关注(0)|答案(3)|浏览(165)

我有一个用C编写的GTK+应用程序,它加载了一个由GIF动画文件组成的矩阵。这些GtkImages在加载时自动运行动画,然后在动画完成时停止。如何重新启动包含GIF的每个GtkImage的动画,以及在动画完成时是否会生成信号?
谢谢

**编辑:

使用此处介绍的gdk_pixbuf_animation_get_iter()是否可以实现这一点?**
完整代码如下所示。

/*
 * Compile me with:
 *   gcc -o reels reels.c $(pkg-config --cflags --libs gtk+-2.0 gmodule-2.0)
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

/* GTK */
#include <gdk/gdkx.h>
#include <gtk/gtk.h>

/**** prototypes ****/

static void destroy (GtkWidget*, gpointer);
GdkPixbuf *create_pixbuf(const gchar * filename);
GtkWidget *SetupWindow(gchar *data, const gchar *filename);
static void destroy (GtkWidget *window, gpointer data);
void btnSpin_clicked(GtkWidget *button, gpointer data);
void btnExit_clicked(GtkWidget *button, gpointer data);

/********************/

GtkWidget   *images[3][5];

static void destroy (GtkWidget *window, gpointer data)
{
  gtk_main_quit ();
}

void btnSpin_clicked(GtkWidget *button, gpointer data)
{
    printf("Spin Button pressed.\n");

    return;
}

void btnExit_clicked(GtkWidget *button, gpointer data)
{
    gtk_main_quit();

    return;
}

GtkWidget *SetupWindow(gchar *data, const gchar *filename)
{
    GdkPixmap *background;
    GdkPixbuf *pixbuf;
    GdkScreen *ourscreen;
    GdkColormap *colormap;
    GtkStyle *style;
    GdkColor fg;
    GdkColor bg;
    GError *error = NULL;
    GdkRectangle *rect;
    GtkWidget *window;

    pixbuf = gdk_pixbuf_new_from_file (filename,&error);
    if (error != NULL) {
        if (error->domain == GDK_PIXBUF_ERROR) {
            g_print ("Pixbuf Related Error:\n");
        }
        if (error->domain == G_FILE_ERROR) {
            g_print ("File Error: Check file permissions and state:\n");
        }

        g_printerr ("%s\n", error[0].message);
    }

    gdk_pixbuf_render_pixmap_and_mask (pixbuf, &background, NULL, 0);
    style = gtk_style_new ();
    style->bg_pixmap[0] = background;
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title (GTK_WINDOW (window), data);
    // gtk_window_maximize(GTK_WINDOW(window));
    gtk_window_set_modal (GTK_WINDOW (window),TRUE);
    gtk_window_set_default_size(GTK_WINDOW(window),628,530);
    gtk_widget_set_style (GTK_WIDGET(window), GTK_STYLE(style));
    gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER_ALWAYS);
    gtk_container_set_border_width(GTK_CONTAINER(window), 0);
    //gtk_window_set_resizable(GTK_WINDOW(window), (gboolean) FALSE);
    gtk_window_set_decorated( GTK_WINDOW(window), FALSE );    

    return(window);
}

int main (int argc, char *argv[])
{
    GdkPixbufAnimation *animation;
    GtkWidget *image;
    int x,y;    
    GdkPixbuf *pixBuf;
    GdkPixmap *pixMap;
    gchar filename[20];
    GtkWidget *btnSpin, *btnExit;

    GtkWidget *frame;       /* for absolute positionining of widgets */
    GtkWidget *window;
    int posx, posy;

    gtk_init (&argc, &argv);

    window = SetupWindow("Demo", "background.gif");
    g_signal_connect (G_OBJECT (window), "destroy", G_CALLBACK (destroy), NULL);

    frame = gtk_fixed_new();
    gtk_container_add(GTK_CONTAINER(window), frame);

    btnSpin = gtk_button_new_with_label("Spin");
    gtk_widget_set_size_request(btnSpin, 80, 35);
    gtk_fixed_put(GTK_FIXED(frame), btnSpin, 229, 485);
    g_signal_connect(G_OBJECT( btnSpin ), "clicked", G_CALLBACK(btnSpin_clicked), NULL );

    btnExit = gtk_button_new_with_label("Exit");
    gtk_widget_set_size_request(btnExit, 80, 35);
    gtk_fixed_put(GTK_FIXED(frame), btnExit, 320, 485);
    g_signal_connect(G_OBJECT( btnExit ), "clicked", G_CALLBACK(btnExit_clicked), NULL );

    /* setup animated gifs */
    for( y = 0; y < 3; y++ )
    {
        posy = (y*120) + 20;
        for( x = 0; x < 5; x++ )
        {
            posx = (x*120) + 20;
            /* set each Image widget to spin GIF */
            sprintf( filename,"%d-%d.gif", y+1,x+1 );
            images[y][x] = gtk_image_new_from_file(filename);
            gtk_fixed_put(GTK_FIXED(frame), images[y][x], posx, posy);
        }
    }

    gtk_widget_show_all(window);

    gtk_main ();

    return 0;
}

字符串

d7v8vwbk

d7v8vwbk1#

在看了GtkImage source code之后,我担心没有动画完成时产生的信号。但是,您应该可以通过调用gtk_image_set_from_file()gtk_image_set_from_animation()重新启动动画。
为了完全解决你最初的问题,我建议你创建一个GtkImage的子类。它的行为应该和GtkImage完全一样,除了animation_timeout应该发送一个信号,如果delay < 0围绕line 1315
关于创建GObject的子类的信息(注意GtkImage是一个GObject)可以在here中找到。

oxcyiej7

oxcyiej72#

基于用户1202136的回答,下面的代码片段显示了解决方案。我发布这个,以防其他人发现它有用。
基本思想是使用GdkPixbufAnimationgdk_pixbuf_animation_new_from_filegtk_image_set_from_animation
下面的代码片段展示了如何做到这一点。

GtkWidget *images[3][5];
GdkPixbufAnimation *animations[3][5];

/* Initial setup of animated gifs */
for( y = 0; y < 3; y++ )
{
    for( x = 0; x < 5; x++ )
    {
        /* set each Image widget to spin GIF */
        sprintf( filename,"%d-%d.gif", y+1,x+1 );
        images[y][x] = gtk_image_new();
        animations[y][x] = gdk_pixbuf_animation_new_from_file ( filename , &error);
        gtk_image_set_from_animation (GTK_IMAGE(images[y][x]), animations[y][x]);
        gtk_fixed_put(GTK_FIXED(frame), images[y][x], (x*120) + 20, (y*120) + 20);
    }
}

/*  now to restart the animations use the images and animations array already stored in memory,
    no need to re-read the animations from disk so this happens quickly
*/

/* restart animated gifs */
for( y = 0; y < 3; y++ )
{
    for( x = 0; x < 5; x++ )
    {
        gtk_image_set_from_animation(GTK_IMAGE(images[y][x]), animations[y][x]);
    }
}

字符串

sz81bmfz

sz81bmfz3#

我知道这个问题已经很老了,但我还是要说点什么,以帮助一些勇敢的航海家。
我用另一种方式使用“iter”对象和cairo来绘制带有动画的绘图区域,因为我的应用程序工作起来很有魅力。

GtkWidget *drawing_area;
GdkPixbufAnimationIter *iter;
GdkPixbufAnimation *pb;
GdkPixbuf *pixbuf;

gboolean on_drawing_area_draw( __attribute__((unused))GtkWidget *widget, cairo_t *cr, __attribute__((unused)) gpointer data)
{
gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); // tells cairo to use pixbuf as source

cairo_paint(cr); // fill the drawing area with the animation

return FALSE;
}

static gboolean mytimer(gpointer user_data) 
{
GTimeVal time;

g_get_current_time(&time);

gdk_pixbuf_animation_iter_advance(iter, &time); // advance/keep still based on time (= or >)

pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter); // get new pixbuf

gtk_widget_queue_draw(drawing_area);

g_timeout_add(gdk_pixbuf_animation_iter_get_delay_time(iter), mytimer, NULL);

return FALSE;
}

void init()
{
GTimeVal time;

pb = gdk_pixbuf_animation_new_from_file("image.gif", NULL); // load animation from file into pixbuf

g_get_current_time(&time);

iter = gdk_pixbuf_animation_get_iter (pb, &time); // get an iter object using time as reference

pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter); // get the first frmae

mytimer(NULL); // do again
}

字符串
然后,你可以通过将与最后一帧相同的 *time参数 * 传递给“gdk_pixbuf_animation_iter_advance()”来停止动画,你可以通过释放 iter 对象并请求一个新对象来重新开始。如果你什么都不做,它将继续重复动画。
唯一需要注意的是,您必须使用libgdk_pixbuf 2.42.0或更高版本,因为在处理“iter”对象时,有一个bug会导致内存泄漏。

相关问题