首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >gtkmm:如何在GtkBuilder文件中使用自定义小部件?

gtkmm:如何在GtkBuilder文件中使用自定义小部件?
EN

Stack Overflow用户
提问于 2022-05-08 01:53:34
回答 1查看 208关注 0票数 1

我正在编写一个gtkmm-4应用程序,并希望在GtkBuilder XML中使用自定义小部件。如果小部件是由C++构造的,那么它可以正常工作。但是,当使用XML构造时,它不会呈现。

注意:这个问题可能被认为是 的重复。我并不是要在我的小部件中使用Glade;我的小部件只是不适用于普通的手写XML.

我很抱歉发布了这么多代码,但我相信这是我所能得到的最低限度的代码。

自定义小部件代码

  • joystick.hpp

代码语言:javascript
复制
#ifndef _TASDI2_JOYSTICK_HPP_
#define _TASDI2_JOYSTICK_HPP_
#include <gtkmm.h>

namespace tasdi2 {
  class Joystick : public Gtk::Widget {
  public:
    Joystick();
    virtual ~Joystick() {}

    virtual Gtk::SizeRequestMode get_request_mode_vfunc() const override {
      return Gtk::Widget::get_request_mode_vfunc();
    }

    virtual void measure_vfunc(
      Gtk::Orientation orientation, int for_size, int& minimum, int& natural,
      int& minimum_baseline, int& natural_baseline) const override;
    
    void on_map() override;
    void on_unmap() override;
    
    void snapshot_vfunc(const Glib::RefPtr<Gtk::Snapshot> &snapshot) override;
    
    
    
    Glib::PropertyProxy<int> property_xpos() {
      return prop_xpos.get_proxy();
    }
    Glib::PropertyProxy_ReadOnly<int> property_xpos() const {
      return prop_xpos.get_proxy();
    }
    Glib::PropertyProxy<int> property_ypos() {
      return prop_ypos.get_proxy();
    }
    Glib::PropertyProxy_ReadOnly<int> property_ypos() const {
      return prop_ypos.get_proxy();
    }
  private:
    Glib::Property<int> prop_xpos;
    Glib::Property<int> prop_ypos;
  };
}  // namespace tasdi2
#endif

  • joystick.cpp

代码语言:javascript
复制
#include "joystick.hpp"
#include <gdkmm.h>
#include <gtkmm.h>
#include <iostream>
#include <numbers>

namespace {
  inline void circle(
    const Glib::RefPtr<Cairo::Context>& cairo, double cx, double cy, double r) {
    cairo->arc(cx, cy, r, 0, 2 * std::numbers::pi);
  }

  inline void line(
    const Glib::RefPtr<Cairo::Context>& cairo, double x1, double y1, double x2,
    double y2) {
    cairo->move_to(x1, y1);
    cairo->line_to(x2, y2);
  }
}  // namespace

namespace tasdi2 {
  Joystick::Joystick() :
    Glib::ObjectBase("Tasdi2Joystick"),
    Gtk::Widget(),
    prop_xpos(*this, "xpos", 0),
    prop_ypos(*this, "ypos", 0) {
    set_hexpand();
    set_hexpand_set();
    set_vexpand();
    set_vexpand_set();
  }

  void Joystick::measure_vfunc(
    Gtk::Orientation orientation, int for_size, int& minimum, int& natural,
    int& minimum_baseline, int& natural_baseline) const {
    minimum          = 128;
    natural          = 160;
    minimum_baseline = -1;
    natural_baseline = -1;
    return;
  }

  void Joystick::on_map() { Gtk::Widget::on_map(); }
  void Joystick::on_unmap() { Gtk::Widget::on_unmap(); }

  void Joystick::snapshot_vfunc(const Glib::RefPtr<Gtk::Snapshot>& snapshot) {
    const auto space = get_allocation();
    const Gdk::Rectangle rect(0, 0, space.get_width(), space.get_height());
    std::cout << "Allocation area: " << space.get_x() << ", " << space.get_y() << ", " << space.get_width() << ", " << space.get_height() << "\n";

    auto cairo = snapshot->append_cairo(rect);

    const double w  = space.get_width();
    const double h  = space.get_height();
    const double cx = w / 2;
    const double cy = h / 2;
    // colors
    const Gdk::RGBA color_bg0("#7F7F7F");
    const Gdk::RGBA color_bg1("#FFFFFF");
    const Gdk::RGBA color_oln("#000000");
    const Gdk::RGBA color_cln("#0000FF");
    const Gdk::RGBA color_dot("#FF0000");

    cairo->rectangle(0, 0, w, h);
    Gdk::Cairo::set_source_rgba(cairo, color_bg0);
    cairo->fill();

    circle(cairo, cx, cy, cx);
    Gdk::Cairo::set_source_rgba(cairo, color_bg1);
    cairo->fill_preserve();

    line(cairo, cx, 0, cx, h);
    line(cairo, 0, cy, w, cy);
    Gdk::Cairo::set_source_rgba(cairo, color_oln);
    cairo->stroke();
  }
}  // namespace tasdi2

MVE测试代码

  • In XML

代码语言:javascript
复制
#include <gtkmm.h>
#include "joystick.hpp"

static const std::string ui_data = R"(
<interface>
  <object class="GtkAspectFrame" id="root">
    <property name="margin-start">10</property>
    <property name="margin-end">10</property>
    <property name="margin-top">10</property>
    <property name="margin-bottom">10</property>
    
    <child>
      <object class="gtkmm__CustomObject_Tasdi2Joystick" />
    </child>
  </object>
</interface>
)";

class MainWindow : public Gtk::Window {
public:
  MainWindow() :
    builder(Gtk::Builder::create_from_string(ui_data)) {
    
    set_child(*builder->get_widget<Gtk::AspectFrame>("root"));
    set_size_request(256, 256);
  }
protected:
  Glib::RefPtr<Gtk::Builder> builder;
};

int main(int argc, char* argv[]) {
  auto app = Gtk::Application::create("io.github.jgcodes2020.testapp");
  app->signal_startup().connect([&]() {
    tasdi2::Joystick joystick;
  });
  return app->make_window_and_run<MainWindow>(argc, argv);
}

  • in C++

代码语言:javascript
复制
#include <gtkmm.h>
#include "joystick.hpp"

static const std::string ui_data = R"(
<interface>
  <object class="GtkAspectFrame" id="root">
    <property name="margin-start">10</property>
    <property name="margin-end">10</property>
    <property name="margin-top">10</property>
    <property name="margin-bottom">10</property>
  </object>
</interface>
)";

class MainWindow : public Gtk::Window {
public:
  MainWindow() :
    builder(Gtk::Builder::create_from_string(ui_data)) {
    
    auto& root = *builder->get_widget<Gtk::AspectFrame>("root");
    root.set_child(stick);
    
    set_child(root);
    set_size_request(256, 256);
  }
protected:
  Glib::RefPtr<Gtk::Builder> builder;
  tasdi2::Joystick stick;
};

int main(int argc, char* argv[]) {
  auto app = Gtk::Application::create("io.github.jgcodes2020.testapp");
  return app->make_window_and_run<MainWindow>(argc, argv);
}

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-05-09 00:58:12

使用上面关于包含派生小部件的注释,我查看了Gnome developer站点上的示例代码,并查看了您的"Joystick“小部件的类构造函数。我没有使用标准构造函数,因为它对于直接构建在代码中的任何小部件都是有用的。然后,使用开发人员站点上的派生小部件示例,将"joystick.hpp“头文件修改为包含构建器构造器原型,如下所示。

代码语言:javascript
复制
Joystick();
Joystick(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& refGlade); /* New builder function for a derived widget */
virtual ~Joystick() {}

然后,在文件"tasdi2“中的"joystick.cpp”命名空间中,我添加了派生的构建器构造函数,基本上是在"Joystick“类的标准构造函数中克隆细节。

代码语言:javascript
复制
Joystick::Joystick(BaseObjectType* cobject, const Glib::RefPtr<Gtk::Builder>& /* refGlade */)
: // To register custom properties, you must register a custom GType.  If
  // you don't know what that means, don't worry, just remember to add
  // this Glib::ObjectBase constructor call to your class' constructor.
  // The GType name will be gtkmm__CustomObject_Tasdi2Joystick.
  Glib::ObjectBase("Tasdi2Joystick"),
  Gtk::Widget(cobject),
  prop_xpos(*this, "xpos", 0),
  prop_ypos(*this, "ypos", 0)
{
    set_hexpand();
    set_hexpand_set();
    set_vexpand();
    set_vexpand_set();
}

最后,在"main.cpp“的"XML”版本中,我修改了代码以适应派生的小部件。在XML文本正文中,我添加了一个"ID“属性,以便在程序的后面调用派生的构建器函数时有一个小部件的挂钩。

代码语言:javascript
复制
<object class="gtkmm__CustomObject_Tasdi2Joystick" id="stick_range"/>

在添加"ID“属性的同时,我还在"MainWindow”构造函数中包含了自定义操纵杆小部件的构建。

代码语言:javascript
复制
  MainWindow() :
    builder(Gtk::Builder::create_from_string(ui_data)) {
    set_child(*builder->get_widget<Gtk::AspectFrame>("root"));
    set_size_request(256, 256);
    tasdi2::Joystick * stick_range = nullptr;
    stick_range = Gtk::Builder::get_widget_derived<tasdi2::Joystick>(builder, "stick_range");
    if (stick_range == nullptr) 
       printf("Joystick widget definition was not found\n");
  }

将"XML“版本的"main.cpp”与其他更改组合在一起的净结果显示了小部件。

您可能已经从前面的注释中了解到了这些内容,但是如果没有,这些附加的代码段可能对您有帮助。

致以问候。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72157547

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档