代码之家  ›  专栏  ›  技术社区  ›  jdizzle

GTK窗口运动动画?

  •  3
  • jdizzle  · 技术社区  · 14 年前

    I want to move my GTK_WINDOW across the screen automatically. Currently I have it in a draw/move loop, but that's terribly choppy. I'm very new to GTK programming (and gui programming in general). What am I missing?

    1 回复  |  直到 13 年前
        1
  •  5
  •   James Waldby - jwpat7    13 年前

    你还没说过你想要什么样的道路。如果路径是一些简单的时间函数,也就是说,如果你有一种计算窗口在任何给定的时间都在哪里的方法,你可以试试下面代码中所示的方法。对于示例中的简单菜单,它在Linux系统上运行良好,并产生相当平滑的动作。

    The key to the method is that instead of moving the window a given distance per timer event, it finds out the current time and moves the window to the location it should be at, at that time. Thus, the time derivative of speed of motion should be constant, which avoids ragged or choppy motion even if timer events occur irregularly. (如 g-timeout-add() description ,很容易出现不规则。)

    In this example, the path is from top left of window to bottom left and back, repeatedly. The constant 'HalfTime' in timerEvent() controls how long it takes to move from corner to corner. The constant 3 in the g_timeout_add() call sets the timer interval to 0.003 seconds, or about 333 moves per second (MPS). (You may want to try more-reasonable rates, such as 20, 30, 40, etc MPS; I used the number 3 because I didn't look up g-timeout-add() 在使用它之前,假设延迟大约是秒,大约33毫秒,而不是毫秒,大约333毫秒。如果你的窗口内容相当复杂,那么更少的MPS将是实用的。此外,我尝试了一些较低的速度,并得到更多的印象,斩波。

    /* $Id: app12.c $
     Re: animating position of a top-level Gtk window
     jiw July 2011 -- Offered without warranty under GPL v3
     terms per http://www.gnu.org/licenses/gpl.html  */
    #include <stdlib.h>
    #include <stdio.h>
    #include <string.h>
    #include <math.h>
    #include <gtk/gtk.h>
    typedef struct DATA { GTimer *timer; GtkWidget *window; int w, h; }
      DataStruct;
    
    gboolean timerEvent(void *dataset) {
      enum { HalfTime=8, CycTime=2*HalfTime };
      gulong micros;
      DataStruct *data =dataset;
      double t = fabs(fmod (g_timer_elapsed (data->timer, &micros), CycTime));
      int x = (t*data->w)/HalfTime, y = (t*data->h)/HalfTime;
      gtk_window_move (GTK_WINDOW(data->window),
           t<HalfTime? x : 2*data->w-x, t<HalfTime? y : 2*data->h-y);
      return TRUE; /* Keep timeout running */
    }
    
    int main(int argc, char **argv) {
      GtkWidget *vbox, *b;
      GdkScreen *gds;
      DataStruct data;
      data.timer = g_timer_new();
      gtk_init (&argc, &argv);
      data.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
      gtk_window_set_default_size (GTK_WINDOW(data.window), 200, 150);
      g_signal_connect (G_OBJECT(data.window), "destroy",
                G_CALLBACK(gtk_main_quit), NULL);
      vbox = gtk_vbox_new (FALSE, 0);
      gtk_container_add (GTK_CONTAINER(data.window), vbox);
      b = gtk_button_new_with_label ("Click to Exit");
      gtk_box_pack_start (GTK_BOX(vbox), b, TRUE, TRUE, TRUE);
      g_signal_connect (b, "clicked", G_CALLBACK(gtk_main_quit), NULL);
      gtk_widget_show_all (data.window);
    
      gds = gdk_screen_get_default ();  /* Get pointer to screen  */
      data.w = gdk_screen_get_width (gds);  /* Find out screen width  */
      data.h = gdk_screen_get_height (gds); /* Find out screen height */
      printf ("Screen size = %d by %d\n", data.w, data.h); fflush(stdout);
      g_timeout_add(3, timerEvent, &data);  /* Create .003 sec timer   */
      gtk_main();
      return (0);
    }