Как я могу «приостановить» приложение для пользователя, чтобы нажать кнопку? GTK - PullRequest
0 голосов
/ 04 февраля 2020

Я делаю карточную игру в C, используя GTK 3.0. У меня есть две функции для двух windows, openMenu (), чтобы открыть меню, и newGame (), чтобы создать новое окно с карточным столом. Игрок играет против двух ботов, которые выбирают свои карты случайным образом. Мне нужен игрок, чтобы начать игру с выбора одной карты. Открыть меню:

static void openMenu(int argc, char *argv[]){
    GtkBuilder *builder;
    GtkWidget *window;
    GObject *button;
    GError *error = NULL;

    gtk_init(&argc, &argv);
    builder = gtk_builder_new_from_file("menu_window_glade.glade");
    window = GTK_WIDGET(gtk_builder_get_object(builder, "menu_window"));
    gtk_builder_connect_signals(builder, NULL);
    gtk_widget_show(window);

    gtk_main();
}

Новая игра:

void newGame(){
    GtkBuilder *builder;
    GtkWidget *window;
    GtkImage *image;
    widgetsPtrs *widgets = malloc(sizeof(widgetsPtrs));
    char imageStr[] = "image00";
    char aImgstr[] = "A0";
    char dImgstr[] = "D0";
    builder = gtk_builder_new_from_file("game_glade.glade");
    window = GTK_WIDGET(gtk_builder_get_object(builder, "game_glade_window"));
    gtk_builder_connect_signals(builder, NULL);
    gtk_widget_show(window);

    shuffleTheDeck();
    printAll(Deck);

    card *player = malloc(sizeof(card));
    card *leftBot = malloc(sizeof(card));
    card *rightBot = malloc(sizeof(card));

    deal(player, 0);
    deal(leftBot, 0);
    deal(rightBot, 0);

    /***************Puts images into buttons***********/
    tmpCard = player;
    for (size_t i = 0; i < 6; i++)
    {
        tmpCard = tmpCard->next;
        imgPath[20] = zero + tmpCard->rank; 
        imgPath[21] = zero + tmpCard->suit;
        gtk_image_set_from_file(GTK_IMAGE(widgets->w_playersHandPtr[i]), imgPath);   
    }

    int a = firstTurnCheck();
    playersTurn(player, leftBot, rightBot);
}

Проблема возникает здесь: у меня возникла идея al oop, которая может быть нарушена, только если Изменен глобальный bool, который изменяется в функции, обслуживающей события щелчка. Однако окно с игровым столом не показывает , поэтому я никогда не могу нажать кнопку, поэтому приложение зависает.

void playersTurn(card *player, card *leftBot, card *rightBot){
    bool DEFENDERTOOKTHECARDS = false;
    bool RBHASMORE = true;
    PLAYERCHOOSING = true;
    int attackCounter = 0;
    int *appearedRanks = calloc(9, sizeof(int));
    card *cardsOnTheTable = malloc(sizeof(card)); //cardsOnTheTable[0] is a pointer to the table
    char answer;

    puts("Player's Turn");
    puts("Choose a card.");
    /*****************The spot where the mistake might be****************/
    while(PLAYERCHOOSING);//PLAYERCHOOSING is a global bool.
    puts("You've chosen a card.");
}

Функция On_card_click:

void on_card_clicked(GtkButton *button, gpointer *data){ 
    gtk_widget_hide(GTK_WIDGET(data));
    PLAYERCHOOSING = false;
}

Ответы [ 3 ]

1 голос
/ 06 февраля 2020

Я не понимаю, почему так много людей любят использовать темы для чего-либо. У GTK есть основной l oop, используйте его (см. этот ответ , чтобы узнать больше). Вы не можете использовать sleep, бесконечные циклы или любые другие блокирующие вызовы, в противном случае вы блокируете основной l oop, который обрабатывает события пользовательского интерфейса.

Так что просто не поставить:

PLAYERCHOOSING = true;

в playersTurn и

PLAYERCHOOSING = false;

в on_card_clicked будет достаточно?

1 голос
/ 04 февраля 2020

Помимо прочего, эта строка является проблемой: (как вы уже догадались в своем комментарии.)

while(PLAYERCHOOSING);//PLAYERCHOOSING is a global bool.

Она войдет и никогда не уйдет.
По крайней мере, она должна иметь возможность чтобы проверить флаг, чтобы увидеть, была ли нажата кнопка:

while(PLAYERCHOOSING)
{
    if(buttonToggled)//define as another global boolean value, and set when button is pressed
    {
        PLAYERCHOOSING = false;
        buttonToggled = false;
    }
    else Sleep(1000); //sleep for 1 second
}

Лучший подход - запустить пользовательский интерфейс в первичном потоке, а затем добавить служебную работу (обнаружение и обработку нажатия кнопки) в секунду. нить. Функция обратного вызова может быть определена как обработчик нажатия кнопки.
(void on_card_clicked(GtkButton *button, gpointer *data) представляется обратным вызовом.)

0 голосов
/ 05 февраля 2020

Большое спасибо @ryyker за совет, который он дал. Решение основано на многопоточности. Как я уже говорил, я никогда не работал с ними раньше, но мне потребовалось 15 минут, чтобы выяснить все, что мне нужно, поэтому мне нечего бояться :) Есть мое решение:

  1. '# include ',
  2. объявить нить pthread_t в newGame (),
  3. add pthread_create (& thread, NULL, PlayersTurn, NULL); в newGame ()
  4. вы можете оставить 'while (PLAYERCHOOSING)' l oop как есть.
  5. скомпилируйте с флагом -lpthread.

Вуаля, вы удивительны.

...