如何使用 gtkmm 和构建器 XML 文件将小部件(例如按钮)添加到 C++ 应用程序中的窗口

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

我正在开发一个使用 gtkmm(版本 3.24)和外部 XML 文件用 C++ 编写的 GUI 应用程序的简单示例。

感谢this其他问题的回答,我设法按照我想要的方法创建一个空窗口(用于“mainWindow”类声明的头

myWindow.h
文件,用于类定义的另一个
myWindow.cpp
文件,一个
main.cpp
文件,以及带有小部件的
builder.ui
文件)。

我的目标是用小部件填充窗口,也许从一个简单的按钮开始。 但由于我对 C++ 的了解很差,所以我不能。 经过一番研究,我尝试合并类似示例中的代码,特别是来自here的代码,这就是我到目前为止所拥有的:

myWindow.h

#pragma once

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

class MainWindow : public Gtk::Window
{
public:

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

protected:

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

};

myWindow.cpp

#include "myWindow.h"

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

    auto pButton = p_builder->get_widget<Gtk::Button>("button1");
}

main.cpp

#include <iostream>
#include <cstring>

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

#include "myWindow.h"

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

    auto app = Gtk::Application::create(argc, argv);

    auto builder = Gtk::Builder::create_from_file("builder.ui");

    MainWindow* window = nullptr;

    builder->get_widget_derived("mainWindow", window);

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

catch(const Gtk::BuilderError& bdre)
{
    // speciffic handling for BuilderError
    std::cout << "Builder error: " << bdre.what() << std::endl;
}

catch(const std::runtime_error& re)
{
    // speciffic handling for runtime_error
    std::cout << "Other runtime error: " << re.what() << std::endl;
}
catch(const std::exception& ex)
{
    // speciffic handling for all exceptions extending std::exception, except
    // std::runtime_error which is handled explicitly
    std::cout << "Error occurred: " << ex.what() << std::endl;
}
catch(...)
{
    // catch any other errors (that we have no information about)
    std::cout << "Unknown failure occurred. Possible memory corruption" << std::endl;
}

return 0;
}

builder.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <requires lib="gtk+" version="3.22"/>
  <object class="GtkWindow" id="mainWindow">
    <property name="title">Grid</property>
    <property name="default-width">600</property>
    <property name="default-height">400</property>
    <child>
      <object id="button1" class="GtkButton">
        <property name="label">Button</property>
        <layout>
          <property name="column">1</property>
          <property name="row">1</property>
        </layout>
      </object>
    </child>
  </object>
</interface>

当我构建此代码时,出现以下错误:

myWindow.cpp:14:54: error: no matching function for call to ‘Gtk::Builder::get_widget<Gtk::Button>(const char [8])’
   14 |     auto pButton = p_builder->get_widget<Gtk::Button>("button1");

如果我添加

Gtk::Button  *addButton;

作为头文件中的受保护指针

myWindow.h
,我按以下方式使用
get_widget()
函数

p_builder->get_widget("button1", addButton);

在文件

myWindow.cpp
中的构造函数定义中,然后我可以构建可执行文件,但随后出现以下运行时错误:

terminate called after throwing an instance of 'Gtk::BuilderError'
Aborted (core dumped)

没有更多信息(即“try / catch”无法捕获错误详细信息)。

系统日志报告以下内容:

systemd-coredump[826232]: Process 826227 (base) of user 1000 dumped core.#012#012Module libzstd.so.1 from deb libzstd-1.5.5+dfsg2-2build1.1.amd64#012Module libsystemd.so.0 from deb systemd-255.4-1ubuntu8.4.amd64#012Stack trace of thread 826227:#012#0  0x000073d024a9eb1c __pthread_kill_implementation (libc.so.6 + 0x9eb1c)#012#1  0x000073d024a4526e __GI_raise (libc.so.6 + 0x4526e)#012#2  0x000073d024a288ff __GI_abort (libc.so.6 + 0x288ff)#012#3  0x000073d024ea5ffe n/a (libstdc++.so.6 + 0xa5ffe)#012#4  0x000073d024ebae9c n/a (libstdc++.so.6 + 0xbae9c)#012#5  0x000073d024ea5a49 _ZSt9terminatev (libstdc++.so.6 + 0xa5a49)#012#6  0x000073d024ebb128 __cxa_throw (libstdc++.so.6 + 0xbb128)#012#7  0x000073d025614130 _ZN3Gtk12BuilderError10throw_funcEP7_GError (libgtkmm-3.0.so.1 + 0x214130)#012#8  0x000073d0253dc34c _ZN4Glib5Error15throw_exceptionEP7_GError (libglibmm-2.4.so.1 + 0x6834c)#012#9  0x000073d02564819e _ZN3Gtk7Builder13add_from_fileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE (libgtkmm-3.0.so.1 + 0x24819e)#012#10 0x000073d0256481ee _ZN3Gtk7Builder16create_from_fileERKNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE (libgtkmm-3.0.so.1 + 0x2481ee)#012#11 0x000055e7fb40e6c8 n/a (/home/fabio/Documents/programming/C++/Esperimenti_GTK/GTK4/simple_button/build/base + 0x76c8)#012#12 0x000073d024a2a1ca __libc_start_call_main (libc.so.6 + 0x2a1ca)#012#13 0x000073d024a2a28b __libc_start_main_impl (libc.so.6 + 0x2a28b)#012#14 0x000055e7fb40e565 n/a (/home/fabio/Documents/programming/C++/Esperimenti_GTK/GTK4/simple_button/build/base + 0x7565)#012ELF object binary architecture: AMD x86-64

我做错了什么? 我应该在哪里“调用”XML 文件中定义的小部件,以及如何调用?

c++ xml user-interface gtkmm
1个回答
0
投票

所呈现代码中的问题来自于对 Gtk::Builder 工作原理的理解不足。

事实上,一旦从 XML 文件实例化构建器,XML 文件中存在的所有小部件都将被创建并显示在窗口中,无需在代码中“调用”或实例化它们。

一个最小的工作示例,窗口中只有几个小部件(按钮),如下:

myWindow.h

#pragma once

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

class MainWindow : public Gtk::Window
{

public:

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

protected:

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

};

myWindow.cpp

#include "myWindow.h"

#include <gtkmm/builder.h>

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

main.cpp

#include <iostream>
#include <cstring>

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

#include "myWindow.h"

int main(int argc, char** argv)
{
    auto app = Gtk::Application::create(argc, argv);

    auto builder = Gtk::Builder::create_from_file("builder.ui");

    MainWindow* window = nullptr;

    builder->get_widget_derived("mainWindow", window);

    app->run(*window);

   return 0;
}

builder.ui

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object id="mainWindow" class="GtkWindow">
    <property name="title">Pippo</property>
    <property name="default_width">400</property>
    <property name="default_height">300</property>

    <child>
     <object class="GtkGrid" id="grid">
        <property name="visible">True</property>
        <child>
          <object id="button1" class="GtkButton">
            <property name="label">Button 1</property>
            <property name="visible">True</property>
          </object>

          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">0</property>
          </packing>

        </child>

        <child>
          <object id="button2" class="GtkButton">
            <property name="label">Button 2</property>
            <property name="visible">True</property>
          </object>
          <packing>
            <property name="left-attach">1</property>
            <property name="top-attach">0</property>
          </packing>
        </child>

        <child>
          <object id="button3" class="GtkButton">
            <property name="label">Button 3</property>
            <property name="visible">True</property>
          </object>
          <packing>
            <property name="left-attach">2</property>
            <property name="top-attach">0</property>
          </packing>
        </child>

        <child>
          <object id="button4" class="GtkButton">
            <property name="label">Button 4</property>
            <property name="visible">True</property>
          </object>
          <packing>
            <property name="left-attach">0</property>
            <property name="top-attach">1</property>
          </packing>
        </child>

     </object>
    </child>

  </object>
</interface>

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