gta 你不知道的玩法(gtk当中一些好玩的小例子)
gta 你不知道的玩法(gtk当中一些好玩的小例子)方法2:参考本人上一篇文章#include <gtk/gtk.h> static GtkWidget *ourgif; int main(int argc char **argv) { GtkWidget *window; GtkWidget *vbox; GtkWidget *hbox; GtkWidget *label; GtkWidget *image; gint num = 0; gchar *filename; gtk_init(&argc &argv); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); g_signal_connect(G_OBJECT(window) "delete_event" G_CALLBACK(
之前有人问我,为什么要学习GTK?
原因很简单:
首先,GTK是C语言实现的。我们需要明白,对于C程序员而言,大部分都没有接触过图形界面编程,但是对于以后的发展,我们很有必要了解一下图形界面编程。那么问题又来了,我们是学C语言的,我们可能不太乐意学习面向对象语言(如 C Java C# Objective-C 等),现在市场上流行的图形界面工具库基本上都是用面向对象语言开发的。
再者,对于我们 C 程序员,我们可能只需了解一下图形界面开发过程,并不一定以后从事图形界面开发。所以,GTK是一个很好的选择。
实际上,用C语言开发的图形库还有一个MiniGUI,在国内医疗设备应用非常广泛,相反,GTK在国内基本上没人用。但是,我们学习到的个别知识,以后未必一定能用上,对于我们而言,重要的是学习方法。如果觉得 MiniGUI 比 GTK 在国内应用广,就想学习 MiniGUI,那我们是否应该学Android,因为它应用更广。技术是不断的更新的,但是万变不离其宗。
其实,学习 MiniGUI 和 GTK 都差不多。区别在于 MiniGUI 是国内开发, GTK 国外开发的。
学习GTK,我们可以了解到图形界面开发的流程是怎么一个过程,这和 Android 应用开发差不多,假如,有那么一天我们真想做Android开发的工作,我们转过去也容易,因为我们有 C 语言的基础,也有图形界面的基础。
接下来补充几个gtk中好玩的一些效果:
1、gtk窗口移动动画
/* $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 µs) 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" data.w data.h); fflush(stdout);
g_timeout_add(3 timerEvent &data); /* Create .003 sec timer */
gtk_main();
return (0);
}
2、gtk窗口中添加动画(动图)
方法1:
#include <gtk/gtk.h>
static GtkWidget *ourgif;
int main(int argc char **argv)
{
GtkWidget *window;
GtkWidget *vbox;
GtkWidget *hbox;
GtkWidget *label;
GtkWidget *image;
gint num = 0;
gchar *filename;
gtk_init(&argc &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window) "delete_event" G_CALLBACK(gtk_main_quit) NULL);
vbox = gtk_vbox_new(FALSE 0);
gtk_container_add(GTK_CONTAINER(window) vbox);
label = gtk_label_new("直接引用GIF动画");
gtk_box_pack_start(GTK_BOX(vbox) label FALSE FALSE 5);
image = gtk_image_new_from_file("hh.gif");
gtk_box_pack_start(GTK_BOX(vbox) image FALSE FALSE 5);
gtk_widget_show_all(window);
gtk_main();
return TRUE;
}
效果:
方法2:参考本人上一篇文章
3、GTK 的多线程动画
#include <gtk/gtk.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
//the global pixmap that will serve as our buffer
static GdkPixmap *pixmap = NULL;
gboolean on_window_configure_event(GtkWidget * da GdkEventConfigure * event gpointer user_data){
static int oldw = 0;
static int oldh = 0;
//make our selves a properly sized pixmap if our window has been resized
if (oldw != event->width || oldh != event->height){
//create our new pixmap with the correct size.
GdkPixmap *tmppixmap = gdk_pixmap_new(da->window event->width event->height -1);
//copy the contents of the old pixmap to the new pixmap. This keeps ugly uninitialized
//pixmaps from being painted upon resize
int minw = oldw minh = oldh;
if( event->width < minw ){ minw = event->width; }
if( event->height < minh ){ minh = event->height; }
gdk_draw_drawable(tmppixmap da->style->fg_gc[GTK_WIDGET_STATE(da)] pixmap 0 0 0 0 minw minh);
//we're done with our old pixmap so we can get rid of it and replace it with our properly-sized one.
g_object_unref(pixmap);
pixmap = tmppixmap;
}
oldw = event->width;
oldh = event->height;
return TRUE;
}
gboolean on_window_expose_event(GtkWidget * da GdkEventExpose * event gpointer user_data){
gdk_draw_drawable(da->window
da->style->fg_gc[GTK_WIDGET_STATE(da)] pixmap
// Only copy the area that was exposed.
event->area.x event->area.y
event->area.x event->area.y
event->area.width event->area.height);
return TRUE;
}
static int currently_drawing = 0;
//do_draw will be executed in a separate thread whenever we would like to update
//our animation
void *do_draw(void *ptr){
//prepare to trap our SIGALRM so we can draw when we recieve it!
siginfo_t info;
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset SIGALRM);
while(1){
//wait for our SIGALRM. Upon receipt draw our stuff. Then do it again!
while (sigwaitinfo(&sigset &info) > 0) {
currently_drawing = 1;
int width height;
gdk_threads_enter();
gdk_drawable_get_size(pixmap &width &height);
gdk_threads_leave();
//create a gtk-independant surface to draw on
cairo_surface_t *cst = cairo_image_surface_create(CAIRO_FORMAT_ARGB32 width height);
cairo_t *cr = cairo_create(cst);
//do some time-consuming drawing
static int i = 0;
i; i = i % 300; //give a little movement to our animation
cairo_set_source_rgb (cr .9 .9 .9);
cairo_paint(cr);
int j k;
for(k=0; k<100; k){ //lets just redraw lots of times to use a lot of proc power
for(j=0; j < 1000; j){
cairo_set_source_rgb (cr (double)j/1000.0 (double)j/1000.0 1.0 - (double)j/1000.0);
cairo_move_to(cr i j/2);
cairo_line_to(cr i 100 j/2);
cairo_stroke(cr);
}
}
cairo_destroy(cr);
//When dealing with gdkPixmap's we need to make sure not to
//access them from outside gtk_main().
gdk_threads_enter();
cairo_t *cr_pixmap = gdk_cairo_create(pixmap);
cairo_set_source_surface (cr_pixmap cst 0 0);
cairo_paint(cr_pixmap);
cairo_destroy(cr_pixmap);
gdk_threads_leave();
cairo_surface_destroy(cst);
currently_drawing = 0;
}
}
}
gboolean timer_exe(GtkWidget * window){
static int first_time = 1;
//use a safe function to get the value of currently_drawing so
//we don't run into the usual multithreading issues
int drawing_status = g_atomic_int_get(¤tly_drawing);
//if this is the first time create the drawing thread
static pthread_t thread_info;
if(first_time == 1){
int iret;
iret = pthread_create( &thread_info NULL do_draw NULL);
}
//if we are not currently drawing anything send a SIGALRM signal
//to our thread and tell it to update our pixmap
if(drawing_status == 0){
pthread_kill(thread_info SIGALRM);
}
//tell our window it is time to draw our animation.
int width height;
gdk_drawable_get_size(pixmap &width &height);
gtk_widget_queue_draw_area(window 0 0 width height);
first_time = 0;
return TRUE;
}
int main (int argc char *argv[]){
//Block SIGALRM in the main thread
sigset_t sigset;
sigemptyset(&sigset);
sigaddset(&sigset SIGALRM);
pthread_sigmask(SIG_BLOCK &sigset NULL);
//we need to initialize all these functions so that gtk knows
//to be thread-aware
if (!g_thread_supported ()){ g_thread_init(NULL); }
gdk_threads_init();
gdk_threads_enter();
gtk_init(&argc &argv);
GtkWidget *window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
g_signal_connect(G_OBJECT(window) "destroy" G_CALLBACK(gtk_main_quit) NULL);
g_signal_connect(G_OBJECT(window) "expose_event" G_CALLBACK(on_window_expose_event) NULL);
g_signal_connect(G_OBJECT(window) "configure_event" G_CALLBACK(on_window_configure_event) NULL);
//this must be done before we define our pixmap so that it can reference
//the colour depth and such
gtk_widget_show_all(window);
//set up our pixmap so it is ready for drawing
pixmap = gdk_pixmap_new(window->window 500 500 -1);
//because we will be painting our pixmap manually during expose events
//we can turn off gtk's automatic painting and double buffering routines.
gtk_widget_set_app_paintable(window TRUE);
gtk_widget_set_double_buffered(window FALSE);
(void)g_timeout_add(33 (GSourceFunc)timer_exe window);
gtk_main();
gdk_threads_leave();
return 0;
}
效果: