GTK2+ Автоматическая настройка размера шрифта метки кнопки

Я делаю игру «Крестики-нолики» в качестве школьного проекта. Я установил 9 кнопок в ряды по 3, поэтому всякий раз, когда пользователь нажимает на одну из них, ее метка меняется на X или O в виде обычного текста.

введите здесь описание изображения

Мне было интересно, возможно ли изменить размер X/O в зависимости от размера окна. Другая идея, которая у меня была, заключалась в том, чтобы использовать изображение X/O вместо простого текста (по крайней мере, потому что я предполагаю, что если я использую большое изображение, оно автоматически уменьшится); Я действительно не хочу этого делать, поскольку функция, которая проверяет, когда игрок выиграл игру, сравнивает текст меток.

Это код, отвечающий за создание и добавление кнопки:

GtkWidget *button;
button = gtk_button_new_with_label("");
gtk_box_pack_start(GTK_BOX(theBox),button,FALSE,TRUE,0);
g_signal_connect(GTK_OBJECT(button),"clicked",GTK_SIGNAL_FUNC(ButtonClicked),EntryBox);
gtk_widget_show(button);

И это моя функция ButtonClicked:

void ButtonClicked(GtkButton *button, gpointer data)
{
  if (strcmp(gtk_button_get_label(button), "") == 0)
    if (count % 2 != 0)
      gtk_button_set_label(button, "X");
}

Кроме того, пока я здесь, у меня есть еще один вопрос: я установил границу окна на 0, но вы все равно можете видеть очень маленькую границу, есть ли способ избавиться от этого?


person Zhior    schedule 29.11.2015    source источник
comment
Как правило, не сравнивайте текст меток, поэтому вы можете добавить prpoperties или указатель пользовательских данных. Как насчет того, чтобы нарисовать его с cairo прямо внутри и "expose-event"?   -  person Iharob Al Asimi    schedule 29.11.2015


Ответы (1)


Вы можете попробовать это, я использовал "expose-event", чтобы нарисовать X и O и пустую ячейку на случай, если пользователь еще не щелкнул ее, а также реализовал простую функцию для проверки победителя. Значение ячейки устанавливается путем передачи данных обработчикам событий.

"button-release-event" позволяет вам что-то делать, когда нажимается ячейка, а затем вы можете изменить следующий ход на другого игрока и установить X или O на ячейку, на которую нажали, в зависимости от того, у какого игрока был ход, когда он был нажат.

Проверь это

#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 = &current_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;
}
person Iharob Al Asimi    schedule 29.11.2015