gtk当中一些好玩的小例子_data

文章正文
发布时间:2020-08-05 23:21

之前有人问我,为什么要学习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 */

#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", 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(&currently_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;

}

效果:

首页
评论
分享
Top