I am creating a new GTK app (using gtkmm) and the main interface is tabbed, a bit like a web browser.
I want to create a new tab for each document the user opens, with the content of each tab being defined by Glade. I'm new to gtkmm, so I am not sure how to do this.
If I design my tab in Glade as a self-contained window, when I call Gtk::Builder::get_widget()
it returns a pointer to the Gtk::Window
, but I can't pass this to Gtk::Notebook::append_page()
because that function requires a reference and I only have a pointer. I don't want to dereference the pointer, because I believe each call to get_widget()
returns the same pointer - so if I want to add five pages the same, I need to somehow clone the UI structure before adding it to the Gtk::Notebook
- otherwise changing a UI element on one tab will cause it to change on the other four tabs too as they are all pointing to the same UI widgets.
What is the best way to take a window designed in Glade and dynamically add it multiple times to a Gtk::Notebook
?
EDIT:
Putting each tab's definitions into a separate *.glade
file does allow me to load multiple instances so that part is all good.
However I still can't add the loaded structure to the Gtk::Notebook
:
Gtk::Builder::get_widget()
to retrieve the root Gtk::Window
from the .glade
file and add that as the new tab, it won't compile because I have to pass a Gtk::Widget
to append_page()
and it won't accept a Gtk::Window
parameter instead.If I tell it to pick the top-most widget instead, then I get a bunch of runtime errors:
Can't set a parent on widget which has a parent
gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-expand'
gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-fill'
gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `tab-label'
gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `menu-label'
gtkcontainer.c:858: container class `gtkmm__GtkWindow' has no child property named `position'
Gtk:ERROR:gtkcontainer.c:3541:gtk_container_propagate_draw: assertion failed: (gtk_widget_get_parent (child) == GTK_WIDGET (container))
Aborted (core dumped)
If I take the top-most widget and instead call reparent()
and pass the Gtk::Notebook
as the new parent then the new tab does show up with all the widgets correctly arranged, but then I can't control the tab's title.
There must be a 'correct' way to do this, I just can't figure out what it is!
Thanks to help from the gtkmm
mailing list, I have the solution.
In Glade, I had created a Gtk::Window
with a single Gtk::Box
in it, and put all my controls in the Box
. This caused problems when trying to add the Box
as a new tab, because the Box
already had a parent (the Gtk::Window
) so it was troublesome trying to make the Gtk::Notebook
the new parent.
Instead, I found you can right-click on the button for the Gtk::Box
in Glade, and choose "Add widget as toplevel". There is then no need for a Gtk::Window
at all, and as the Box
has no parent, calling Gtk::Notebook::append_page()
and passing the Gtk::Box
works perfectly. I can then use the variant of append_page()
that lets me set the tab's title at the same time.
It is still a requirement however to create a new Gtk::Builder
instance to load the controls for each tab, because each tab needs a new instance of the controls. If you just keep calling Gtk::Builder::get_widget()
on the same object, it returns the same instance of the controls.