在C++中,如何使用gtkmm库中的get_widget_driven()函数

问题描述 投票:0回答:1

我正在学习如何使用基于 GTK 库的图形用户界面构建 C++ 应用程序。

如其他问题中所述,我正在尝试使用外部 XML 文件和“构建器”。 经过一番研究,我相信要使用的关键工具是 gtkmm 中的

get_widget_derived()
函数,但我无法获得可用的最小示例。

到目前为止我所做的是:

window.h

#pragma once
#include <gtkmm.h>

class MainWindow : public Gtk::Window
{
public:
  MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder);
  ~MainWindow() override;

protected:
  //Signal handlers:

  Glib::RefPtr<Gtk::Builder> m_refBuilder;
};

window.cpp

#include "window.h"

MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refBuilder)
: Gtk::Window(cobject),  m_refBuilder(refBuilder)
{}

MainWindow::~MainWindow()
{}

main.cpp

#include "window.h"
#include <iostream>
#include <cstring>


namespace
{

MainWindow* pDialog = nullptr;
Glib::RefPtr<Gtk::Application> app;


template <typename T_Widget, typename... Args> inline
void get_widget_derived(const Glib::ustring& name, T_Widget*& widget, Args&&... args)
{
    // Initialize output parameter:
    widget = nullptr;

    // Get the widget from the GtkBuilder file.
    using cwidget_type = typename T_Widget::BaseObjectType;
    auto pCWidget = (cwidget_type*) Gtk::Builder::get_cwidget(name);

    //The error was already reported by get_cwidget().
    if(!pCWidget)
      return;

    //Check whether there is already a C++ wrapper instance associated with this C instance:
    Glib::ObjectBase* pObjectBase = Glib::ObjectBase::_get_current_wrapper((GObject*)pCWidget);

    //If there is already a C++ instance, then return it again:
    if(pObjectBase)
    {
      widget = dynamic_cast<T_Widget*>( Glib::wrap((GtkWidget*)pCWidget) );
      //Newer, more spec-complaint, versions of g++ cannot resolve a specific wrap() function in a template.

      //The dynamic cast checks that it is of the correct type.
      //Somebody might be trying to call get_widget_derived() after already calling get_widget(),
      //or after already calling get_widget_derived() with a different derived C++ type.
      if(!widget)
      g_critical("Gtk::Builder::get_widget_derived(): dynamic_cast<> failed. An existing C++ instance, of a different type, seems to exist.");
    }
    else
    {
      //Create a new C++ instance to wrap the existing C instance:


      Glib::RefPtr<Gtk::Builder> refThis(this);
      refThis->reference(); //take a copy.
      widget = new T_Widget(pCWidget, refThis, std::forward<Args>(args)...);

    }
}



void on_app_activate()
{

  // Load the GtkBuilder file and instantiate its widgets:
  auto refBuilder = Gtk::Builder::create();
  try
  {
    refBuilder->add_from_file("derived.ui");
  }
  catch(const Glib::FileError& ex)
  {
    std::cerr << "FileError: " << ex.what() << std::endl;
    return;
  }
  catch(const Glib::MarkupError& ex)
  {
    std::cerr << "MarkupError: " << ex.what() << std::endl;
    return;
  }
  catch(const Gtk::BuilderError& ex)
  {
    std::cerr << "BuilderError: " << ex.what() << std::endl;
    return;
  }

  // Get the GtkBuilder-instantiated dialog:

  pDialog = get_widget_derived<MainWindow>(refBuilder, "mainWindow");

  if (!pDialog)
  {
    std::cerr << "Could not get the dialog" << std::endl;
    return;
  }

  // It's not possible to delete widgets after app->run() has returned.
  // Delete the dialog with its child widgets before app->run() returns.
  pDialog->signal_hide().connect([] () { delete pDialog; });

  app->add_window(*pDialog);
  pDialog->set_visible(true);
}
} // anonymous namespace

int main(int argc, char** argv)
{

  app = Gtk::Application::create("org.gtkmm.example");

  app->signal_activate().connect([] () { on_app_activate(); });

  return app->run(argc, argv);
}

builder.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="3.22"/>
  <object class="GtkWindow" id="mainWindow">
    <property name="default_width">400</property>
    <property name="default_height">300</property>
  </object>
</interface>

如果我尝试构建此代码,我会收到错误:

error: cannot call member function ‘GtkWidget* Gtk::Builder::get_cwidget(const Glib::ustring&)’ without object
   23 |     auto pCWidget = (cwidget_type*) Gtk::Builder::get_cwidget(name);

应该实例化什么对象,在哪里实例化?

c++ gtk gtkmm3
1个回答
0
投票

如果您是 C++ 新手,我知道您可能会对未记录的 Gtkmm API 感到有点困惑。我也在使用 3.24,这是一个工作示例。

窗口.h

首先,当你开始自己做时,你需要在某个地方有一个

MainWindow
定义/声明。以下是声明:

#include <gtkmm/builder.h>
#include <gtkmm/window.h>

class MainWindow : public Gtk::Window
{

public:

  MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& p_builder);

protected:

  Glib::RefPtr<Gtk::Builder> m_builder;

};

所以我继承了

Gtk::Window
并且在构造函数中,我传递了 C 指针和构建器。这正是构建器必须完成的工作方式(这是在线记录的内容)。

窗口.cpp 定义如下:

#include "window.h"

MainWindow::MainWindow(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& p_builder)
: Gtk::Window(cobject)
, m_builder{p_builder}
{
}

main.cpp

这是

main
函数。这是您创建构建器实例的位置。请注意,在 3.24 中,
get_widget_derived
不是自由函数,而是类
Gtk::Builder
的方法:

#include <iostream>
#include <cstring>

#include <gtkmm/application.h>

#include "window.h"

int main(int argc, char** argv)
{
    // Create an application object. This is mandatory since it initializes
    // the toolkit. If you don't do this, widgets won't show.
    auto app = Gtk::Application::create(argc, argv);

    // Since you want to use the builder, you need to instantiate one. You
    // can do this directly using your UI file.
    auto builder = Gtk::Builder::create_from_file("builder.ui");

    // At this point, you are ready to create your window. The builder is
    // going to create an instance for you, and you get a handle to this
    // istance to later use.
    // First, you create a MainWindow pointer, which points to nothing. It
    // is going to be used by the builder to get you the handle.
    MainWindow* window = nullptr;

    // Then, using you builder instance. You call get_widget_derived and
    // pass the pointer to get the handle.
    builder->get_widget_derived("mainWindow", window);

    // You then show the window by using you handle (i.e window).
    return app->run(*window);
}

如果您想使用较新版本的 Gtkmm,则需要使用 JHBuild 自行构建。我不推荐它,除非你有充分的理由。根据我的经验,这并不是那么简单。

© www.soinside.com 2019 - 2024. All rights reserved.