【问题标题】:Gtkmm - Proper way to close a window and then show anotherGtkmm - 关闭窗口然后显示另一个的正确方法
【发布时间】:2018-06-12 12:55:37
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: c++ gtkmm


    【解决方案1】:

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

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

    【讨论】:

      【解决方案2】:

      虽然这个问题很老了,但我会展示我的方法,这可能有助于其他人处理这项任务。

      我使用一个包含所有窗口对象的通用应用程序对象: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()。之后,您将处理仅由主应用程序对象显示和隐藏的窗口。

      【讨论】:

        【解决方案3】:

        回应您的回答:delete-&gt;this 是纯语法错误,即使没有-&gt;,写delete this 通常也是代码异味。除此之外,您所做的事情似乎会奏效,即使可能不如预期的那么直观。

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

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

        因此,在这种情况下,您现在将使用计数从 2 变为 1(而不是从 1 变为 0),因此删除第一个窗口将不再使应用退出。然后,在您添加第二个窗口之后,无论发生多长时间,调用 .release() 以删除额外的使用计数,因此剩余的窗口现在再次独占控制应用程序的生命周期。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2021-07-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-12-10
          相关资源
          最近更新 更多