你可以试试这个,我用"expose-event"
绘制X
和O
并且如果用户没有点击这些事,也imlpemented一个简单的函数来检查得主空单元格。单元格值是通过将数据传递给事件处理程序来设置的。
的"button-release-event"
允许在单击单元格时,你做什么,然后你就可以在下一回合更改为其它播放器和设置X
或O
到单击的单元格,这取决于球员必须转弯时,它是clicke。
入住这
#include <gtk/gtk.h>
#include <stdlib.h>
#include <math.h>
enum Player
{
FirstPlayer,
SecondPlayer
};
enum TicTacValue
{
None,
Empty,
Unset,
X,
O
};
struct GameData
{
enum TicTacValue value;
enum Player *player;
struct GameData *data;
gint row;
gint column;
};
enum TicTacValue
evaluate(enum TicTacValue previous, enum TicTacValue next)
{
if (previous == Unset)
return next;
if (previous != next)
return None;
return next;
}
void
check_winner(struct GameData *data)
{
enum TicTacValue rows[3] = {Unset, Unset, Unset};
enum TicTacValue diagonals[2] = {Unset, Unset};
enum TicTacValue columns[3] = {Unset, Unset, Unset};
enum TicTacValue winner;
for (size_t i = 0 ; i < 9 ; ++i)
{
columns[i % 3] = evaluate(columns[i % 3], data[i].value);
rows[i/3] = evaluate(rows[i/3], data[i].value);
switch (i)
{
case 4:
diagonals[0] = evaluate(diagonals[0], data[i].value);
diagonals[1] = evaluate(diagonals[1], data[i].value);
break;
case 0:
case 8:
diagonals[0] = evaluate(diagonals[0], data[i].value);
break;
case 2:
case 6:
diagonals[1] = evaluate(diagonals[1], data[i].value);
break;
}
}
winner = diagonals[0] | diagonals[1];
winner = winner | columns[0] | columns[1] | columns[2];
winner = winner | rows[0] | rows[1] | rows[2];
if (winner < Unset)
return;
fprintf(stderr, "Player %d WINS (-)\n", winner - Unset);
}
gboolean
on_click(GtkWidget *widget, GdkEventButton *event, gpointer data)
{
struct GameData *game_data;
game_data = (struct GameData *) data;
if (game_data->value != Empty)
return FALSE;
if (*(game_data->player) == FirstPlayer)
{
game_data->value = X;
*(game_data->player) = SecondPlayer;
}
else
{
game_data->value = O;
*(game_data->player) = FirstPlayer;
}
gtk_widget_queue_draw(widget);
check_winner(game_data->data);
return FALSE;
}
void
draw_delmiter_line(cairo_t *cairo, gint x1, gint y1, gint x2, gint y2)
{
cairo_save(cairo);
cairo_set_source_rgb(cairo, 0.65, 0.65, 0.65);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE);
cairo_set_line_width(cairo, 1);
cairo_move_to(cairo, x1, y1);
cairo_line_to(cairo, x2, y2);
cairo_stroke(cairo);
cairo_restore(cairo);
}
void
draw_x(cairo_t *cairo, gint width, gint height)
{
gint size;
size = width/3.5;
cairo_save(cairo);
cairo_set_source_rgb(cairo, 0.25, 0.4, 1.0);
cairo_set_line_width(cairo, 2.5);
cairo_translate(cairo, width/2, height/2);
cairo_move_to(cairo, -size, -size);
cairo_line_to(cairo, +size, +size);
cairo_move_to(cairo, +size, -size);
cairo_line_to(cairo, -size, +size);
cairo_stroke(cairo);
cairo_restore(cairo);
}
void
draw_o(cairo_t *cairo, gint width, gint height)
{
cairo_save(cairo);
cairo_set_source_rgb(cairo, 1.0, 0.25, 0.25);
cairo_set_line_width(cairo, 2.5);
cairo_arc(cairo, width/2, height/2, width/3, 0, 2.0 * M_PI);
cairo_stroke(cairo);
cairo_restore(cairo);
}
gboolean
on_expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
{
GdkWindow *window;
cairo_t *cairo;
const struct GameData *game_data;
gint width;
gint height;
window = gtk_widget_get_window(widget);
cairo = gdk_cairo_create(window);
game_data = (const struct GameData *) data;
gdk_window_get_size(window, &width, &height);
if (game_data->row != 2)
draw_delmiter_line(cairo, 0, height, width, height);
if (game_data->column != 3)
draw_delmiter_line(cairo, width, 0, width, height);
if (game_data->value == X)
draw_x(cairo, width, height);
else if (game_data->value == O)
draw_o(cairo, width, height);
cairo_destroy(cairo);
return FALSE;
}
int
main(int argc, char **argv)
{
GtkWidget *window;
GtkWidget *horizontal[3];
GtkWidget *vertical;
struct GameData data[9];
enum Player current_player;
gtk_init(&argc, &argv);
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
vertical = gtk_vbox_new(TRUE, 0);
for (size_t i = 0 ; i < 3 ; ++i)
{
horizontal[i] = gtk_hbox_new(TRUE, 0);
gtk_box_pack_start(GTK_BOX(vertical), horizontal[i], TRUE, TRUE, 0);
}
current_player = FirstPlayer;
for (size_t i = 0 ; i < 9 ; ++i)
{
GtkWidget *cell;
cell = gtk_drawing_area_new();
data[i].value = Empty;
data[i].player = ¤t_player;
data[i].data = data;
data[i].row = i/3;
data[i].column = i % 3;
g_signal_connect(G_OBJECT(cell), "expose-event", G_CALLBACK(on_expose), &data[i]);
g_signal_connect(G_OBJECT(cell), "button-release-event", G_CALLBACK(on_click), &data[i]);
gtk_widget_add_events(cell, GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_PRESS_MASK);
gtk_box_pack_start(GTK_BOX(horizontal[data[i].row]), cell, TRUE, TRUE, 0);
}
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
gtk_container_add(GTK_CONTAINER(window), vertical);
gtk_widget_set_size_request(window, 300, 300);
gtk_window_set_resizable(GTK_WINDOW(window), FALSE);
gtk_widget_show_all(window);
gtk_main();
return 0;
}
的标签文本不要拿作为一般规则,这就是为什么你可以添加prpoperties或用户数据指针。那么用* cairo *直接在和'“expose-event”中绘制它呢? –