Gtkmm - правильный способ закрыть окно, а затем показать другое

Я создаю приложение gtkmm. Программа открывается с окном настроек, в котором пользователю предлагается указать некоторую информацию, и когда проверки работоспособности выполнены, это окно должно быть закрыто, и должно открыться главное окно приложения.

Прямо сейчас, открыв главное окно и скрыв окно настроек, полностью закройте приложение. В окнах настроек я делаю:

MainWindow* main_window = new MainWindow();
main_window->show();                       
this->hide();                              

Как я могу добиться описанного выше поведения? Очевидно, вы можете добавлять и удалять окна с Gtk::App. Будет ли он делать то, что я описал, и означает ли это, что мне придется передать своему окну указатель Gtk::App? Спасибо.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать 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
0
1 440
3

Ответы 3

Кажется, что правильное решение - передать окну указатель приложения (m_app), добавить к нему новое окно, показать это окно и скрыть текущее. Удаление текущего из приложения позволит функции run () вернуть:

MainWindow* main_window = new MainWindow(m_app);
m_app->add_window(*main_window);                
main_window->show();                            
this->hide();                                   
m_app->remove_window(*this);                    
delete->this;

Это работает, но это может быть неправильным способом.

В ответ на ваш ответ: delete->this - это чистая синтаксическая ошибка, и даже без -> запись delete this обычно является запахом кода. За исключением этого, то, что вы сделали, похоже, будет работать, если, возможно, не будет настолько интуитивно понятным, насколько могло бы быть.

Однако делать что-то в такой последовательности не всегда возможно. Например, вы можете не знать, каким будет следующий Window. Возможно, какое окно откроется следующим, зависит от ответа HTTP, получение которого может занять некоторое время.

Общее решение - вызвать Application.hold() перед удалением Window. Вызов .hold() увеличивает счетчик использования GApplication, как и добавление окна. Приложение завершает работу, когда его счетчик использования равен нулю. Сказать, что его жизнь контролируется окнами, - это просто быстрый способ приблизиться к объяснению этого (и, очевидно, относится только к GtkApplication, а не к базовому GApplication). Удаление окна уменьшает счетчик использования.

Итак, в этом случае вы теперь перейдете от счетчика использования от 2 к 1, а не от 1 к 0, поэтому удаление 1-го окна больше не приведет к закрытию приложения. Затем, после того, как вы добавите 2-е окно, хотя это произойдет намного позже, вызовите .release(), чтобы удалить дополнительный счетчик использования, чтобы оставшиеся окна теперь снова управляют временем жизни приложения исключительно.

Хотя вопрос довольно старый, я покажу свой подход, который может помочь кому-то другому справиться с этой задачей.

Я использую общий объект приложения, который содержит все объекты окна: MainApplication.cpp

MainApplication::MainApplication(int argc, char **argv)
{
    // Creating the main application object as first
    mainApp = Gtk::Application::create(argc, argv, APPLICATION_ID);

    // Create the entry window
    createEntryWindow();
}

int MainApplication::run()
{
    if (!isRunning) {

        // Set the current window to entry window for startup
        currentWindow = entryWindow;
        return mainApp->run(*entryWindow);
    } else {
        return -1;
    }
}

void MainApplication::createEntryWindow()
{
    // Load the entry_window.glade layout with the Gtk::Builder Api
    Glib::RefPtr<Gtk::Builder> builder = Gtk::Builder::create_from_file("../layout/entry_window.glade");

    // Calls the constructor of my own derived widget class which details are specified inside the builder file
    builder->get_widget_derived(WND_ENTRY, entryWindow);

    // Set this main application object to the new window
    entryWindow->setMainApplicationContext(this);
}

MainApplication.h

static const int WS_ENTRY = 100;
static const int WS_SOMETHING = 200;

class MainApplication {
public:
    MainApplication(int argc, char* argv[]);

    int run();

    void switchCurrentWindow(int specifier);

private:
    void createEntryWindow();

private:
    Glib::RefPtr<Gtk::Application> mainApp;
    Gtk::Window* currentWindow = nullptr;
    EntryWindow* entryWindow = nullptr;

    bool isRunning = false;
};

Объект MainApplication будет создан внутри main (), после чего вызывается run (): main.cpp

int main(int argc, char* argv[])
{
    // Create main application object
    MainApplication mainApplication(argc, argv);

    // Starts the event loop
    // No events propagate until this has been called
    return mainApplication.run();
}

EntryWindow.cpp выглядит так (простой пример):

EntryWindow::EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade)
    : Gtk::Window(object), builder(refGlade)
{
    // Set widgets to builder
    builder->get_widget(btnName, btn);

    // Set on click methods for signal_clicked
    btn->signal_clicked().connect(sigc::mem_fun(*this, &EntryWindow::onBtnClicked));
}

void EntryWindow::onBtnClicked()
{
    mainApplicationContext->switchCurrentWindow(WS_SOMETHING);
}

void EntryWindow::setMainApplicationContext(MainApplication* mainApplication)
{
    this->mainApplicationContext = mainApplication;
}

EntryWindow.h:

class EntryWindow : public Gtk::Window {
public:
    EntryWindow(BaseObjectType* object, const Glib::RefPtr<Gtk::Builder>& refGlade);
    void setMainApplicationContext(MainApplication* mainApplication);

protected:
    void onBtnClicked();

protected:
    const Glib::RefPtr<Gtk::Builder> builder;
    Gtk::Button* btn;

private:
    MainApplication* mainApplicationContext = nullptr;
    const Glib::ustring btnName = BTN_NAME;    
};

Итак, теперь, когда была нажата кнопка, вы можете переключать окна с помощью следующей функции внутри класса MainApplication:

void MainApplication::switchCurrentWindow(int specifier)
{
    // Check if the passed specifier exist
    int tmpSpecifier = 0;
    switch (specifier) {
        case WS_ENTRY:
            tmpSpecifier = WS_ENTRY;
            break;
        case WS_SOMETHING:
            tmpSpecifier = WS_SOMETHING;
            break;
        default:
            tmpSpecifier = 0;
    }

    // If the specifier exist
    if (tmpSpecifier != 0) {

        // Increase the use counter of the main application object
        mainApp->hold();

        // Hide the current window
        currentWindow->hide();

        // Remove the current window
        mainApp->remove_window(*currentWindow);
    } else {
        return;
    }

    switch (tmpSpecifier) {
        case WS_ENTRY:
            currentWindow = entryWindow;
            break;
        case WS_SOMETHING:
            currentWindow = somethingWindow;
            break;
    }

    // Add the new current window
    mainApp->add_window(*currentWindow);

    // Show the new window
    currentWindow->show();

    // Decrease the use counter of the main application object
    mainApp->release();
}

Резюме: Создайте объект, содержащий все окна. Поэтому всякий раз, когда вам нужно новое окно, вы должны создавать его внутри этого объекта. Этот основной объект приложения будет вызываться функцией main (), и там он вызовет run (), когда приложение будет готово к запуску. После этого вы будете определять, какое окно отображается и скрывается только основным объектом приложения.

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