I'm working on a GTKmm application(a simple text editor, as an exercise), in which I have a notebook to which I want to add a tab. The notebook shows, but the newly added tab doesn't. I'm doing it in the following way:
void MainWindow::AddTabToNotebook()
{
Gtk::Box box;
notebook->append_page(box);
notebook->show_all();
}
MainWindow
is a class that inherits Gtk::Window
and contains a pointer to Gtk::Notebook
which is loaded from a Glade file using Gtk::Builder
. Whenever I click the button that calls the function I get the following message in the terminal: Gtk-CRITICAL **: gtk_notebook_get_tab_label: assertion 'list != NULL' failed. Any help is appreciated.
MainWindow.h:
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <gtkmm.h>
class MainWindow : public Gtk::Window
{
protected:
Gtk::Button* buttonOpenFile;
Gtk::Button* buttonSave;
Gtk::Button* buttonSaveAs;
Gtk::Button *dialogButonOpen;
Gtk::TextView *text;
Gtk::MenuButton *buttonMenu;
Gtk::Notebook *notebook;
Gtk::FileChooserDialog *openFileDialog;
Glib::RefPtr<Gtk::Builder> builder;
void AddTabToNotebook();
void OnButtonOpenFileClick();
void OnButtonSaveClick();
void OnButtonSaveAsClick();
void OnFileChosen();
void OnDialogButtonOpenClick();
public:
MainWindow(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &refGlade);
~MainWindow();
};
#endif
MainWindow.cpp:
#include"MainWindow.h"
#include<iostream>
#include<gtkmm.h>
MainWindow::MainWindow(BaseObjectType *cobject, const Glib::RefPtr<Gtk::Builder> &refGlade)
:Gtk::Window(cobject),
builder(refGlade)
{
builder->get_widget("buttonOpenFile", buttonOpenFile);
builder->get_widget("buttonSave", buttonSave);
builder->get_widget("buttonSaveAs", buttonSaveAs);
builder->get_widget("buttonMenu", buttonMenu);
builder->get_widget("openFileDialog", openFileDialog);
builder->get_widget("dialogButtonOpen", dialogButonOpen);
builder->get_widget("notebook", notebook);
buttonOpenFile->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnButtonOpenFileClick));
dialogButonOpen->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::OnDialogButtonOpenClick));
buttonSave->signal_clicked().connect(sigc::mem_fun(*this, &MainWindow::AddTabToNotebook));
show_all_children();
}
MainWindow::~MainWindow()
{}
void MainWindow::OnButtonOpenFileClick()
{
if(openFileDialog)
{
openFileDialog->show();
}
}
void MainWindow::OnDialogButtonOpenClick()
{
auto file=openFileDialog->get_file();
std::cout<<file->get_path();
if(openFileDialog)
{
openFileDialog->close();
}
}
void MainWindow::AddTabToNotebook()
{
Gtk::Box box;
notebook->append_page(box);
notebook->show_all();
}
The glade file:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.2 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<object class="GtkWindow" id="MainWindow">
<property name="name">MainWindow</property>
<property name="width-request">800</property>
<property name="height-request">600</property>
<property name="can-focus">False</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkBox">
<property name="height-request">30</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">start</property>
<property name="hexpand">True</property>
<child>
<object class="GtkButton" id="buttonOpenFile">
<property name="label" translatable="yes">Open file</property>
<property name="name">buttonOpenFile</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Open a file</property>
<signal name="clicked" handler="OnButtonOpenFileClicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonSave">
<property name="label" translatable="yes">Save changes</property>
<property name="name">buttonSave</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="tooltip-text" translatable="yes">Save changes to the current document</property>
<signal name="clicked" handler="OnButtonSaveChangesClicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="buttonSaveAs">
<property name="label" translatable="yes">Save As...</property>
<property name="name">buttonSaveAs</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<signal name="clicked" handler="OnButtonSaveAsClicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkMenuButton" id="buttonMenu">
<property name="name">buttonMenu</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="use-popover">False</property>
<signal name="toggled" handler="OnButtonMenuToggled" swapped="no"/>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">3</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkViewport">
<property name="height-request">780</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkNotebook" id="notebook">
<property name="name">notebook</property>
<property name="width-request">200</property>
<property name="height-request">200</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkTextView">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">page 1</property>
</object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<placeholder/>
</child>
<child type="tab">
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child>
</object>
</child>
</object>
</child>
</object>
<object class="GtkFileChooserDialog" id="openFileDialog">
<property name="name">openFileDialog</property>
<property name="width-request">800</property>
<property name="height-request">600</property>
<property name="can-focus">False</property>
<property name="type-hint">dialog</property>
<child internal-child="vbox">
<object class="GtkBox">
<property name="width-request">800</property>
<property name="height-request">600</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">2</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
<property name="layout-style">end</property>
<child>
<object class="GtkButton" id="dialogButtonOpen">
<property name="label" translatable="yes">Open</property>
<property name="name">dialogButtonOpen</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
Whatever I try to append to the notebook, be it a Gtk::Box
or Gtk:TextView
, the new tab doesn't show.
Note: This is a work in progress, so the save button's clicked signal is responsible for adding a new tab(blank document)to the notebook.
The problem is that:
Gtk::Notebook
does not take ownership of the widget you are adding.I was able to make your example work by adding a widget (here a Gtk::Label
) attribute to your window (so it outlives the callback):
class MainWindow : public Gtk::Window
{
protected:
Gtk::Button* buttonOpenFile;
Gtk::Button* buttonSave;
Gtk::Button* buttonSaveAs;
Gtk::Label label; // <-- See here
Gtk::Button *dialogButonOpen;
...
and then show()
ing it explicitly in the callback:
void MainWindow::AddTabToNotebook()
{
notebook->append_page(label);
label.set_text("test");
label.show();
}
on Ubuntu and Gtkmm 3.24.20. You can achieve the same thing by using the Glade file, I leave this part to you.