Hello, everybody.
I’m trying to reuse a .UI file that I previously used with Gtk 4 (vanilla C), but this time around with Gtkmm.
The problem I’m getting is that, by following the Gtk::Builder part of the Gtkmm documentation, the file is being rejected with the following message:
BuilderError: src/app/res/ui/forms/qxplayer-window.ui:9:1 Template declaration (class 'QxplayerWindow', parent 'GtkApplicationWindow') where templates aren't supported
The following is my code, adapted from this example.
main.cpp
#include <gtkmm.h>
#include <iostream>
#include "app/qxplayer_window.hpp"
namespace {
Gtk::Window *pDialog = nullptr;
Glib::RefPtr<Gtk::Application> app;
void on_button_clicked() {
if (pDialog)
pDialog->set_visible(false); // set_visible(false) will cause
// Gtk::Application::run() to end.
}
void on_app_activate() {
// Load the GtkBuilder file and instantiate its widgets:
auto refBuilder = Gtk::Builder::create();
try {
refBuilder->add_from_file("src/app/res/ui/forms/qxplayer-window.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 = Gtk::Builder::get_widget_derived<QxPlayerWindow>(
refBuilder, "QxplayerWindow");
if (!pDialog) {
std::cerr << "Could not get the dialog" << std::endl;
return;
}
app->add_window(*pDialog);
pDialog->set_visible(true);
}
} // anonymous namespace
int main(int argc, char **argv) {
app = Gtk::Application::create("org.gtkmm.example");
// Instantiate a dialog when the application has been activated.
// This can only be done after the application has been registered.
// It's possible to call app->register_application() explicitly, but
// usually it's easier to let app->run() do it for you.
app->signal_activate().connect([]() { on_app_activate(); });
return app->run(argc, argv);
}
Is this because Gtkmm’s Builder only supports Glade files? Am I missing something else?
I’ve already tried searching for this situation on Google and in this forum, but I didn’t find anything. Also, the API reference doesn’t mention this anywhere, from what I could see.
Thank you.
Edit: I forgot to add the .UI file
qxplayer_window.ui
<?xml version='1.0' encoding='UTF-8'?>
<!-- Created with Cambalache 0.10.3 -->
<interface>
<!-- interface-name qxplayer.ui -->
<!-- interface-authors Arthur Araruna <ararunaufc@gmail.com>
Alunos da disciplina QXD0010 - T01A - 2022.2 -->
<requires lib="gtk" version="4.6"/>
<template class="QxplayerWindow" parent="GtkApplicationWindow">
<property name="height-request">400</property>
<property name="width-request">600</property>
<child type="titlebar">
<object class="GtkHeaderBar">
<child type="start">
<object class="GtkButton" id="b_about">
<property name="action-name">app.about</property>
<property name="icon-name">help-about-symbolic</property>
<property name="tooltip-text">Ver informações sobre o QxPlayer</property>
</object>
</child>
<child type="start">
<object class="GtkButton" id="b_shortcuts">
<property name="action-name">win.show-help-overlay</property>
<property name="has-tooltip">True</property>
<property name="icon-name">preferences-desktop-keyboard-shortcuts-symbolic</property>
<property name="tooltip-text">Ver atalhos de teclado</property>
</object>
</child>
<child type="title">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="margin-top">3</property>
<property name="margin-bottom">3</property>
<property name="valign">GTK_ALIGN_CENTER</property>
<child>
<object class="GtkLabel" id="l_title">
<property name="label">QxPlayer</property>
<property name="css-classes">title</property>
</object>
</child>
<child>
<object class="GtkRevealer">
<child>
<object class="GtkLabel" id="l_media_title">
<property name="label">(sem título)</property>
<property name="margin-top">2</property>
<style>
<class name="subtitle"/>
<class name="qx-media-title-empty"/>
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkGrid">
<property name="column-spacing">5</property>
<property name="margin-bottom">5</property>
<property name="margin-end">5</property>
<property name="margin-start">5</property>
<property name="margin-top">5</property>
<property name="row-spacing">10</property>
<child>
<object class="GtkInfoBar" id="ib_message">
<property name="message-type">GTK_MESSAGE_WARNING</property>
<property name="revealed">False</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkLabel" id="l_message">
<property name="label">Mensagem de teste</property>
</object>
</child>
<layout>
<property name="column">0</property>
<property name="column-span">2</property>
<property name="row">0</property>
<property name="row-span">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="spacing">2</property>
<child>
<object class="GtkToggleButton" id="tb_playpause">
<property name="action-name">app.playback-playing</property>
<property name="has-tooltip">True</property>
<property name="icon-name">media-playback-start-symbolic</property>
<property name="tooltip-text">Iniciar / pausar reprodução</property>
<property name="valign">start</property>
</object>
</child>
<child>
<object class="GtkButton" id="b_previous">
<property name="action-name">app.playlist-prev</property>
<property name="has-tooltip">True</property>
<property name="icon-name">media-skip-backward-symbolic</property>
<property name="tooltip-text">Reiniciar / reproduzir faixa anterior</property>
</object>
</child>
<child>
<object class="GtkButton" id="b_next">
<property name="action-name">app.playlist-next</property>
<property name="has-tooltip">True</property>
<property name="icon-name">media-skip-forward-symbolic</property>
<property name="tooltip-text">Reproduzir próxima faixa</property>
</object>
</child>
<child>
<object class="GtkLabel" id="l_audio_position">
<property name="label">00:00</property>
<property name="margin-start">5</property>
</object>
</child>
<child>
<object class="GtkScale" id="s_seek">
<property name="hexpand">True</property>
<property name="round-digits">0</property>
<property name="adjustment">ad_seek</property>
<property name="sensitive">False</property>
<!-- <binding name="sensitive"> -->
<!-- <lookup name="state"> -->
<!-- <closure type="GSimpleAction" function="g_action_map_lookup_action"> -->
<!-- <closure type="GActionMap" function="g_application_get_default"></closure> -->
<!-- <constant type="gchararray">playback-playing</constant> -->
<!-- </closure> -->
<!-- </lookup> -->
<!-- </binding> -->
</object>
</child>
<child>
<object class="GtkLabel" id="l_audio_duration">
<property name="label">00:00</property>
<property name="margin-end">5</property>
</object>
</child>
<child>
<object class="GtkToggleButton" id="tb_repeat">
<property name="action-name">app.playback-repeating</property>
<property name="has-tooltip">True</property>
<property name="icon-name">media-playlist-repeat-symbolic</property>
<property name="tooltip-text">Controla a repetição da reprodução</property>
</object>
</child>
<child>
<object class="GtkVolumeButton" id="vb_volume">
<property name="use-symbolic">True</property>
<property name="adjustment">ad_volume</property>
</object>
</child>
<layout>
<property name="column">0</property>
<property name="column-span">2</property>
<property name="row">2</property>
<property name="row-span">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkBox">
<property name="homogeneous">True</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<property name="valign">start</property>
<child>
<object class="GtkButton" id="b_add_file">
<property name="action-name">app.playlist-insert</property>
<property name="has-tooltip">True</property>
<property name="icon-name">list-add-symbolic</property>
<property name="tooltip-text">Adicionar à playlist</property>
</object>
</child>
<child>
<object class="GtkButton" id="b_remove_file">
<property name="action-name">app.playlist-remove</property>
<property name="has-tooltip">True</property>
<property name="icon-name">list-remove-symbolic</property>
<property name="tooltip-text">Remover seleção da playlist</property>
</object>
</child>
<layout>
<property name="column">0</property>
<property name="column-span">1</property>
<property name="row">1</property>
<property name="row-span">1</property>
</layout>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="child">
<object class="GtkListView" id="lv_playlist">
<property name="css-classes">rich-list</property>
<property name="hexpand">True</property>
<property name="show-separators">True</property>
<property name="vexpand">True</property>
<signal name="activate" handler="item_activated_cb"/>
</object>
</property>
<layout>
<property name="column">1</property>
<property name="column-span">1</property>
<property name="row">1</property>
<property name="row-span">1</property>
</layout>
</object>
</child>
</object>
</child>
</template>
<object class="GtkAdjustment" id="ad_seek">
<property name="value">0</property>
<property name="lower">0</property>
<property name="upper">1</property>
<property name="step-increment">5</property>
<property name="page-increment">10</property>
<property name="page-size">0</property>
</object>
<object class="GtkAdjustment" id="ad_volume">
<property name="value">1</property>
<property name="lower">0</property>
<property name="upper">1</property>
<property name="step-increment">0.05</property>
<property name="page-increment">0.1</property>
<property name="page-size">0</property>
</object>
</interface>