GTK tutorial 三

尽管GTK提供了很多基础的widget供我们使用,但是总有些时候我们需要创建自己的widget. 当然通过创建一个全新的widget,也有助于我们对GTK的了解。

Creating a composite Widget

接下来我们会创建一个全新的组合widget,通过此widget的创建,来了解当我们调用gtk_*_new来使用GTK提供的的widget时,背后发生的事。

我们创建的widget叫做Tictactoe,如题目所说,它是一个组合widget,类似与FileSelection. 它由一个3x3的toggle button 组成。它的功能是,当同一排、同一列或者对角线上的按钮都被按下时,会触发一个信号。运行结果如下:

 

/*tictactoe.h*/
#ifndef __TICTACTOE_H__
#define __TICTACTOE_H__

#include<glib.h>
#include<glib-object.h>
#include<gtk/gtktable.h>


G_BEGIN_DECLS

#define TICTACTOE_TYPE                  (tictactoe_get_type())
#define TICTACTOE(obj)                  (G_TYPE_CHECK_INSTANCE_CAST((obj), TICTACTOE_TYPE, Tictactoe))
#define TICTACTOE_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST((kclass), TICTACTOE_TYPE, TictactoeClass))
#define IS_TICTACTOE(obj)               (G_TYPE_CHECK_INSTANCE_TYPE((obj), TICTACTOE_TYPE))
#define IS_ITCTACTOE_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE((klass), TICTACTOE_TYPE))

typedef struct _Tictactoe       Tictactoe;
typedef struct _TictactoeClass  TictactoeClass;


struct _Tictactoe
{
    GtkTable table;

    GtkWidget *buttons[3][3];

};

struct _TictactoeClass
{
    GtkTableClass parent_class;

    void (*tictactoe)(Tictactoe *ttt);
};

GType       tictactoe_get_type(void);
GtkWidget*  tictactoe_new(void);
void        tictactoe_clear(Tictactoe *ttt);

G_END_DECLS

#endif
/*tictactoe.c*/
#include <gtk/gtksignal.h>
#include <gtk/gtktable.h>
#include <gtk/gtktogglebutton.h>
#include "tictactoe.h"

enum {
  TICTACTOE_SIGNAL,
  LAST_SIGNAL
};

static void tictactoe_class_init          (TictactoeClass *klass);
static void tictactoe_init                (Tictactoe      *ttt);
static void tictactoe_toggle              (GtkWidget *widget, Tictactoe *ttt);

static guint tictactoe_signals[LAST_SIGNAL] = { 0 };

GType
tictactoe_get_type (void)
{
  static GType ttt_type = 0;

  if (!ttt_type)
    {
      static const GTypeInfo ttt_info =
      {
	sizeof (TictactoeClass),
	NULL,
        NULL,
	(GClassInitFunc) tictactoe_class_init,
        NULL,
	NULL,
        sizeof(Tictactoe),
	0,
	(GInstanceInitFunc) tictactoe_init,
      };

      ttt_type = g_type_register_static (GTK_TYPE_TABLE, "Tictactoe", &ttt_info, 0);
    }

  return ttt_type;
}

static void
tictactoe_class_init (TictactoeClass *klass)
{
  
  tictactoe_signals[TICTACTOE_SIGNAL] = g_signal_new ("tictactoe",
					 G_TYPE_FROM_CLASS (klass),
	                                 G_SIGNAL_RUN_FIRST | G_SIGNAL_ACTION,
	                                 G_STRUCT_OFFSET (TictactoeClass, tictactoe),
                                         NULL, 
                                         NULL,                
					 g_cclosure_marshal_VOID__VOID,
                                         G_TYPE_NONE, 0);


}

static void
tictactoe_init (Tictactoe *ttt)
{
  gint i,j;
  
  gtk_table_resize (GTK_TABLE (ttt), 3, 3);
  gtk_table_set_homogeneous (GTK_TABLE (ttt), TRUE);

  for (i=0;i<3; i++)
    for (j=0;j<3; j++)      {
	ttt->buttons[i][j] = gtk_toggle_button_new ();
	gtk_table_attach_defaults (GTK_TABLE (ttt), ttt->buttons[i][j], 
				   i, i+1, j, j+1);
	g_signal_connect (G_OBJECT (ttt->buttons[i][j]), "toggled",
			  G_CALLBACK (tictactoe_toggle), (gpointer) ttt);
	gtk_widget_set_size_request (ttt->buttons[i][j], 20, 20);
	gtk_widget_show (ttt->buttons[i][j]);
      }
}

GtkWidget*
tictactoe_new ()
{
  return GTK_WIDGET (g_object_new (tictactoe_get_type (), NULL));
}

void	       
tictactoe_clear (Tictactoe *ttt)
{
  int i,j;

  for (i = 0; i<3; i++)
        for (j = 0; j<3; j++)
      {
            g_signal_handlers_block_matched(G_OBJECT(ttt->buttons[i][j]),
                                            G_SIGNAL_MATCH_DATA,
                                            0, 0, NULL, NULL, ttt);
            gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(ttt->buttons[i][j]), FALSE);
            g_signal_handlers_unblock_matched(G_OBJECT(ttt->buttons[i][j]),
                                              G_SIGNAL_MATCH_DATA,
                                              0, 0, NULL, NULL, ttt);
        }

}

static void tictactoe_toggle(GtkWidget *widget, Tictactoe *ttt)
{

    int i, k;

    static int rwins[8][3] = {{0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 1, 2}};
    static int cwins[8][3] = {{0, 1, 2}, {0, 1, 2}, {0, 1, 2}, {0, 0, 0}, {1, 1, 1}, {2, 2, 2}, {0, 1, 2}, {2, 1, 0}};

    int success, found;

    for (k = 0; k < 8; k++)
    {
        success = TRUE;
        found = FALSE;

        for (i = 0; i < 3; i++)
        {
            success = success &&
                      GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
            found = found ||
                    ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
        }

        if (success && found)
        {
            g_signal_emit(G_OBJECT(ttt),
                          tictactoe_signals[TICTACTOE_SIGNAL], 0);
            break;
        }
    }
}
/*ttt_test.c*/
#include<stdlib.h>
#include<gtk/gtk.h>
#include "tictactoe.h"


void win(GtkWidget *widget, gpointer data)
{

    g_print("Yay!\n");
    tictactoe_clear(TICTACTOE(widget));
}

int main(int argc, char *argv[])
{
    GtkWidget *window;
    GtkWidget *ttt;

    gtk_init(&argc,&argv);

    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    
    gtk_window_set_title(GTK_WINDOW(window), "Aspect Frame");

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(exit), NULL);

    gtk_container_set_border_width(GTK_CONTAINER(window), 10);

    ttt = tictactoe_new();

    gtk_container_add(GTK_CONTAINER(window), ttt);
    gtk_widget_show(ttt);

    g_signal_connect(G_OBJECT(ttt), "tictactoe", G_CALLBACK(win), NULL);

    gtk_widget_show(window);

    gtk_main();
}

编译命令如下:

gcc -Wall -g ttt_test.c tictactoe.c  -o ttt_test `pkg-config --cflags gtk+-2.0 pkg-config --libs gtk+-2.0`

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值