I am building a GUI (Python binding of GTK3) where one Gtk Scrolled Window (from Glade) can contain different treeviews. The program launches with an empty window and the first time around everything works with:
self.scrolled_window.add_with_viewport(treeview)
self.main_window.show_all()
Edit: Picture of the test program (see source below):
The second time around I get the following error:
(main.py:15905): Gtk-CRITICAL **: gtk_scrolled_window_add_with_viewport: assertion 'gtk_bin_get_child (GTK_BIN (child_widget)) == NULL' failed
I think that I might need to empty the viewport or scrolled window first, but don't know how that is done and can't find any documentation for it.
Edit: When using self.scrolled_window.remove(self.scrolled_window.get_child()) I don't see the dataset at the start up and error messages appear when switching layers.
Edit: I updated the code once more so the example data is there right from the start.
The glade file (test_project.glade):
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.16.1 -->
<interface>
<requires lib="gtk+" version="3.10"/>
<object class="GtkWindow" id="window1">
<property name="can_focus">False</property>
<property name="default_width">440</property>
<property name="default_height">250</property>
<signal name="destroy" handler="on_window1_destroy" swapped="no"/>
<child>
<object class="GtkBox" id="box1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow1">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolledwindow2">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="shadow_type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox" id="box2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<child>
<object class="GtkButton" id="add_layer">
<property name="label" translatable="yes">add layer</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_add_layer_clicked" 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="add_data">
<property name="label" translatable="yes">add data</property>
<property name="name">add_data</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<signal name="clicked" handler="on_add_data_clicked" swapped="no"/>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
</child>
</object>
</interface>
The python code:
#!/usr/bin/python3
from gi.repository import Gtk
import random
class BottomTreeView(Gtk.TreeView):
def __init__(self, store):
Gtk.TreeView.__init__(store)
self.store = store
renderer = Gtk.CellRendererText()
column = Gtk.TreeViewColumn("Dataset", renderer, text=0)
self.append_column(column)
for x in range(10):
self.store.append(None, [str(random.random())])
class MainWindow(object):
def __init__(self, builder):
self.main_window = builder.get_object("window1")
self.sw1 = builder.get_object("scrolledwindow1")
self.sw2 = builder.get_object("scrolledwindow2")
self.layernumber = 0
self.topstore = Gtk.TreeStore(str, object)
self.topview = Gtk.TreeView(self.topstore)
renderer1 = Gtk.CellRendererText()
column1 = Gtk.TreeViewColumn("Name", renderer1, text=0)
self.topview.append_column(column1)
self.sw1.add_with_viewport(self.topview)
#Adding test data in a dumb way
self.store1 = Gtk.TreeStore(str)
for x in range(10):
self.store1.append(None, [str(random.random())])
self.view1 = Gtk.TreeView(self.store1)
self.rend1 = Gtk.CellRendererText()
self.col1 = Gtk.TreeViewColumn("Dataset", self.rend1, text=0)
self.view1.append_column(self.col1)
self.sw2.add_with_viewport(self.view1)
self.topstore.append(None, ["Layer 1", self.view1])
self.store2 = Gtk.TreeStore(str)
for x in range(10):
self.store2.append(None, [str(random.random())])
self.view2 = Gtk.TreeView(self.store2)
self.rend2 = Gtk.CellRendererText()
self.col2 = Gtk.TreeViewColumn("Dataset", self.rend2, text=0)
self.view2.append_column(self.col2)
self.topstore.append(None, ["Layer 2", self.view2])
self.select = self.topview.get_selection()
self.select.connect("changed", self.on_tree_selection_changed)
self.main_window.show_all()
def on_add_layer_clicked(self, widget):
self.layernumber += 1
store = Gtk.TreeStore(str)
bottom = BottomTreeView(store)
self.topstore.append(None, [str(self.layernumber), bottom])
def on_add_data_clicked(self, widget):
self.selection = self.topview.get_selection()
model, treeiter = self.selection.get_selected()
print("Adding data to {0}".format(model[treeiter][0]))
datasheet = model[treeiter][1]
datasheet.store.append(None, [str(random.random())])
def on_window1_destroy(self, widget):
Gtk.main_quit()
def on_tree_selection_changed(self, selection):
print("\n>>> Selection changed")
model, treeiter = selection.get_selected()
print(">>> Model: {0}, Treeiter: {1}".format(model, treeiter))
if treeiter != None:
print(">>> You selected Layer {0}.".format(model[treeiter][1]))
tree_obj = model[treeiter][1]
#The following lines mess up the program from the startup
#self.sw2.remove(self.sw2.get_child())
#self.sw2.add_with_viewport(tree_obj)
#self.main_window.show_all()
def main():
builder = Gtk.Builder()
objects = builder.add_objects_from_file("test_project.glade",
("window1", ""))
window_instance = MainWindow(builder)
builder.connect_signals(window_instance)
Gtk.main()
if __name__ == "__main__":
main()