Вызов функции wxWidgets

Сейчас я пишу программу-тральщик. Есть функция, которая связана с меню. Когда пользователи нажимают на меню «Уровень», программа покажет подменю из нескольких разных уровней (что означает разное количество блоков). Сейчас я только определил функцию «SetNovice», но обнаружил проблему, заключающуюся в том, что мины не будут снова распределяться случайным образом, как это делает конструктор (который привязывает кнопки с функцией «ButtonOnClicked» для установки мин).

В SetNovice я сначала вызываю функцию «RemoveChild()», чтобы удалить btn в GUIPanel, затем удаляю массив «MineField», а затем снова создаю btn и MineField, как это делает конструктор, но мин просто нет. Мины должны быть установлены при вызове функции "ButtonOnClicked". Как я писал в SetNovice при создании btn, я сделал "Bind" btn to ButtonOnClicked, но никакие мины не устанавливаются.

Предполагается, что программа случайным образом сбрасывает мины при вызове SetNovice, но оказывается, что это не так. Почему?

«MineField» — это массив целых чисел, где «-1» — это место, где находятся мины. Но я не уверен, почему в функции «SetNovice», когда я пытаюсь удалить исходный MineField, чтобы изменить размер на новый, функция, к которой привязаны кнопки, не будет устанавливать мины.

Ниже мой GUIWindow.h

#pragma once
#include "wx/wx.h"
#include "wx/mediactrl.h"
#include "wx/hyperlink.h"
#include <wx/thread.h>
#include "cuppMediaCtrl.h"


class GUIWindow : public wxFrame
{
public:
    GUIWindow();
    ~GUIWindow();


public:
    int Width = 20; // default
    int Height = 20; // default
    int score = 0;
    int count = 0;
    wxButton **btn; // an array of pointers
    int* MineField = nullptr; // a pointer, determining if mines exist
    bool ISFirstClick = true;




    wxPanel* GUIPanel = new wxPanel(this, wxID_ANY);
    wxGridSizer* grid;

    wxGridSizer* gridNovice;
    

    wxStatusBar* statusBar = CreateStatusBar(3);

    void ButtonOnClicked(wxCommandEvent &evt);
    void OnQuit(wxCommandEvent& event);
    void ChangeBtnColorRed(wxCommandEvent& evt);
    void ChangeBtnColorWhite(wxCommandEvent& evt);
    void ChangeBtnColorGreen(wxCommandEvent& evt);
    void ChangeBtnColorBlue(wxCommandEvent& evt);
    void ChangeBtnColorTokyoHot(wxCommandEvent& evt);

    void SetNovice(wxCommandEvent& evt);
    void SetIntermediate(wxCommandEvent& evt);
    void SetProfessional(wxCommandEvent& evt);
    void SetMaster(wxCommandEvent& evt);
    void SetGodLevel(wxCommandEvent& evt);



    void Website1(wxCommandEvent& evt);
    void Website2(wxCommandEvent& evt);
    void ShowCreator(wxCommandEvent& evt);

    DECLARE_EVENT_TABLE();

};

Ниже приведен GUIWindow.cpp (я удалил несвязанный код и функции)

#include "GUIWindow.h"

wxBEGIN_EVENT_TABLE(GUIWindow, wxFrame)
    EVT_BUTTON(wxID_ANY, ButtonOnClicked)
wxEND_EVENT_TABLE()


GUIWindow::GUIWindow() : wxFrame(nullptr, wxID_ANY, "地雷遊戲", wxPoint(30, 30), wxSize(700, 700))
{


    btn = new wxButton *[Width * Height]; // btn == an array of pointers (should allocate new memory)
    grid = new wxGridSizer(Width, Height, 0, 0);  // set a grid pointer to control the grid


    MineField = new int[Width * Height]; // This is where mines are distributed, using nField to indicate mines
    wxFont font(18, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD, false);





    wxString str1 = "Current points: ";
    statusBar->SetStatusText(str1, 0);


    wxMenuBar* menuBar = new wxMenuBar();


    wxMenu* menu1 = new wxMenu();
    menuBar->Append(menu1, wxT("About"));


    wxMenu* menu2 = new wxMenu();
    menuBar->Append(menu2, wxT("Game"));


    SetMenuBar(menuBar);
    menu1->Append(10001, wxT("Creator"));


    wxMenu* imp2 = new wxMenu();
    imp2->Append(10011, wxT("Tokyo Hot"));
    imp2->Append(10012, wxT("White"));
    imp2->Append(10013, wxT("Green"));
    imp2->Append(10014, wxT("Red"));
    imp2->Append(10015, wxT("Blue"));
    menu2->AppendSubMenu(imp2, wxT("Theme"));

    

    wxMenu* imp3 = new wxMenu();
    imp3->Append(10020, wxT("Novice"));
    imp3->Append(wxID_ANY, wxT("Intermediate"));
    imp3->Append(wxID_ANY, wxT("Professional"));
    imp3->Append(wxID_ANY, wxT("Master"));
    imp3->Append(wxID_ANY, wxT("God-Level"));
    menu2->AppendSubMenu(imp3, wxT("Level"));

    wxMenu* imp4 = new wxMenu();
    imp4->Append(10002, "Introduction");
    imp4->Append(10003, "Explanation");
    menu1->AppendSubMenu(imp4, "Hints");


    wxMenuItem* quit = new wxMenuItem();
    quit = new wxMenuItem(menu1, wxID_EXIT, wxT("Quit\tCtrl+Q"));
    menu1->Append(quit);



    Connect(wxID_EXIT, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::OnQuit));
    Centre();

    Connect(10001, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ShowCreator));
    Connect(10011, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ChangeBtnColorTokyoHot));
    Connect(10012, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ChangeBtnColorWhite));
    Connect(10013, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ChangeBtnColorGreen));
    Connect(10014, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ChangeBtnColorRed));
    Connect(10015, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::ChangeBtnColorBlue));
    Connect(10020, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::SetNovice));
    Connect(10002, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::Website1));
    Connect(10003, wxEVT_COMMAND_MENU_SELECTED, wxCommandEventHandler(GUIWindow::Website2));


    

    for (int x = 0; x < Width; x++)
    {
        for (int y = 0; y < Height; y++)
        {
            btn[y * Width + x] = new wxButton(GUIPanel, (y * Width + x)); // every pointer points to a button object with class wxButton
            btn[y * Width + x]->SetFont(font);
            
            grid->Add(btn[y * Width + x], 1, wxEXPAND, wxALL);
            btn[y * Width + x]->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GUIWindow::ButtonOnClicked, this);
            MineField[y * Width + x] = 0; //set each block to 0 (default value)
        }
    }



    GUIPanel->SetSizer(grid); // "this" is pointing at the parent wxFrame: GUIWindow
    GUIPanel->Show();
}






GUIWindow::~GUIWindow()
{
    delete[] btn;
}

void GUIWindow::OnQuit(wxCommandEvent& WXUNUSED(event))
{
    Close(true);
}


void GUIWindow::SetNovice(wxCommandEvent& evt)
{

    Width = 10;
    Height = 10;
    score = 0;
    
    GUIPanel->DestroyChildren(); // delete btn, but NOT removing grid.
    delete[] MineField;
    gridNovice = new wxGridSizer(Width, Height, 0, 0);


    wxFont font(18, wxFONTFAMILY_ROMAN, wxFONTSTYLE_ITALIC, wxFONTWEIGHT_BOLD, false);
    

    btn = new wxButton* [Width * Height];
    MineField = new int[Width * Height];



    for (int x = 0; x < Width; x++)
    {
        for (int y = 0; y < Height; y++)
        {
            btn[y * Width + x] = new wxButton(GUIPanel, (y * Width + x)); // every pointer points to a button object with class wxButton
            btn[y * Width + x]->SetFont(font);
            
            gridNovice->Add(btn[y * Width + x], 1, wxEXPAND, wxALL);
            btn[y * Width + x]->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &GUIWindow::ButtonOnClicked, this);
            MineField[y * Width + x] = 0; //set each block to 0 (default value)
        }
    }

    GUIPanel->SetSizer(gridNovice);
    GUIPanel->Show();
}



void GUIWindow::ButtonOnClicked(wxCommandEvent &evt)
{
    // get position of button
    int x = (evt.GetId()) % Width;
    int y = (evt.GetId()) / Width;
    int mine_count = 0;



    wxString s1 = "Believe in Yourself.";
    wxString s2 = "You are the PRIDE of NTUEE !";
    wxString s3 = "TAIWAN need you!!! so DO NOT give up!!!";
    wxString s4 = "We are all together, blessing you.";
    wxString s5 = "Who's the best minesweeper ? YOU!!!";
    wxString s6 = "Get bored? Try other functions in the menu!";
    wxString s7 = "想脫魯 ? 踩地雷吧 XDXDXD";
    wxString phraseArr[] = { s1, s2, s3, s4, s5, s6, s7};
    

    if (ISFirstClick == true)
    {
        int mine = Width * Height / 2;

        while (mine != 0)
        {
            int rx = rand() % Width;
            int ry = rand() % Height;

            if (MineField[ry * Width + rx] == 0 && rx != x && ry != y)
            {
                MineField[ry * Width + rx] = -1; // -1 indicates the mine
                mine--;
            }
        }

        ISFirstClick = false; // avoid mines been redistributed again
    }

    btn[y * Width + x]->Enable(false);

    if (MineField[y * Width + x] == -1)
    {
        wxMessageBox("BOOM!");
        statusBar->SetStatusText(wxT(""), 2); // reset the status bar
        this->count++;

        //reset mines
        this -> score = 0;
        ISFirstClick = true;
        for (int x = 0; x < Width; x++)
        {
            for (int y = 0; y < Height; y++)
            {
                MineField[y * Width + x] = 0;
                btn[y * Width + x]->SetLabel("");
                btn[y * Width + x]->Enable(true);

            }
        }
    }
    

    else
    {   
        if (this->count < 7)
        {
            wxString Newstr = phraseArr[this->count];
            statusBar->SetStatusText(Newstr, 2);
            this->count++;
        }
        else if (this->count >= 7) this->count = 0;
        

        this -> score += 1;
        wxString scoreStr = std::to_string(this->score);
        statusBar->SetStatusText(scoreStr, 1);

        //count the mines surrounding
        for (int i = -1; i < 2; i++)
        {
            for (int j = -1; j < 2; j++)
            {
                if (x + i >= 0 && x + i < Width && y + i >= 0 && y + j < Height)
                {
                    if (MineField[(y + j) * Width + (x + i)] == -1)
                    {
                        mine_count++;
                    }
                }
            }
        }

        if (mine_count >= 0)
        {
            btn[y * Width + x]->SetLabel(std::to_string(mine_count));
        }
    }

    evt.Skip();
}

есть ли какой-либо C? Пожалуйста, отмечайте только тот язык, который вы используете

463035818_is_not_a_number 14.12.2020 12:56
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
1
105
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Попробуйте добавить

GUIPanel->Layout();

до конца метода GUIWindow::SetNovice. Это приведет к тому, что все кнопки, добавленные на панель, будут упорядочены по размеру сетки.


Также линия

btn[y * Width + x] = new wxButton(GUIPanel, (y * Width + x));

потенциально можно настроить кнопки так, чтобы они имели идентификаторы, которые уже назначены другим вещам. Вы должны использовать что-то вроде:

btn[y * Width + x] = new wxButton(GUIPanel, wxID_ANY);

вместо. Если вам нужно отслеживать координаты кнопки для метода ButtonOnClicked, вы можете сделать что-то вроде

  1. добавить карту std::map<wxWindowID,std::pair<int,int>> m_buttonCoords; в класс GUIWindow.
  2. в GUIWindow::SetNovice очистить карту в начале метода и в цикле создания кнопок вызвать m_buttonCoords.insert( std::make_pair(btn[y * Width + x]->GetId(),std::make_pair(x,y)) );
  3. в GUIWindow::ButtonOnClicked извлеките координаты следующим образом:
std::pair<int,int> coords = m_buttonCoords[evt.GetId()];
int x = coords.first;
int y = coords.second;

Возможно, есть лучшие способы, но это первое, о чем я подумал.

Я следовал шагу. Я изменил способ установки идентификаторов всех кнопок в загрузочном SetNovice и конструкторе; однако кажется, что мины все еще не установлены, когда я выбираю уровень новичка. Я действительно понятия не имею об этом.

Danny Hseih 15.12.2020 12:03

Кстати, я использовал m_buttonCoords.clear(); в начале SetNovice.

Danny Hseih 15.12.2020 12:20

Другие вопросы по теме