Gtkmm - 关闭窗口然后显示另一个窗口的正确方法

时间:2018-06-12 12:55:37

标签: c++ gtkmm

我正在构建一个gtkmm应用程序。该程序打开一个设置窗口,要求用户指定一些信息,完成完整性检查后,应关闭此窗口,并打开应用程序的窗口。

现在,打开主窗口,隐藏设置窗口完全关闭应用程序。 从设置窗口,我正在做:

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

如何获得上述行为? 显然,您可以从Gtk::App添加和删除窗口。它会做我描述的,它是否意味着我必须将Gtk::App指针传递给我的窗口?感谢。

3 个答案:

答案 0 :(得分:0)

似乎正确的解决方案是将应用程序指针(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;

这项工作,但这可能不是正确的做事方式。

答案 1 :(得分:0)

针对您的回答:delete->this是纯语法错误,即使没有->,编写delete this通常也是一种代码味道。除非这样做,否则您所做的事情似乎会奏效,甚至可能不那么直观。

但是,并非总是可以按此顺序进行操作。例如,您可能不知道下一个Window是什么。也许下一个打开的窗口取决于HTTP响应,可能需要一段时间才能到达。

一般的解决方案是在删除Window之前先调用Application.hold()。调用.hold()会增加GApplication的使用次数,就像添加窗口一样。当其使用计数为零时,该应用程序退出。说它的生命是由Windows控制的,这只是一种大概的解释的快速方法(显然仅与GtkApplication相关,而不与基础GApplication相关)。删除窗口会减少使用次数。

因此,在这种情况下,您现在将使用计数从2改为1-而不是1变为0-因此删除第一个窗口将不再使应用程序退出。然后,在添加第二个窗口之后,不管以后发生多少次,都请调用.release()来删除额外的使用次数,因此其余窗口现在将再次独占控制应用程序的生存期。

答案 2 :(得分:0)

尽管这个问题已经很老了,但我将展示我的方法,该方法可以帮助其他人完成这项任务。

我使用一个包含所有窗口对象的通用应用程序对象: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;
};

将在main()内部创建MainApplication对象,然后将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()。之后,您将处理仅由主应用程序对象显示和隐藏哪个窗口。

相关问题