#!/usr/bin/env python # [SNIPPET_NAME: gtk3 treeview using a treestore] # [SNIPPET_CATEGORIES: gtk3] # [SNIPPET_TAGS: widgets, gtk3] # [SNIPPET_DESCRIPTION: GTK3 treeview in treestore, show the data in a expandable hierarchy] # [SNIPPET_AUTHOR: Oliver Marks ] # [SNIPPET_LICENSE: GPL] from gi.repository import Gdk, Gtk, GLib #http://jason.zwolak.org/technoblog/2010/08/drag-and-drop-with-gtk2-and-perl/ class application_gui: """Tutorial 10 text input, display a treeview in expandable tree format.""" count = 0 def __init__(self): #load in our glade interface xml = Gtk.Builder() xml.add_from_file('tut10.glade') #grab our widget using get_object this is the name of the widget from glade, window1 is the default name self.window = xml.get_object('window1') self.text = xml.get_object('entry1') #load our widgets from the glade file self.widgets = {} self.widgets['treeview'] = xml.get_object('treeview1') treeview(self.widgets['treeview'], self.text) #connect to events, in this instance just quit our application self.window.connect('delete_event', Gtk.main_quit) self.window.connect('destroy', lambda quit: Gtk.main_quit()) #show the window else there is nothing to see :) self.window.show() class treeview: treeview = None treemodel = None selected = 'workspace' def __init__(self, treeview, entry): self.entry = entry self.treeview = treeview self.treeview.connect('row-activated', self.selection) self.treeview.connect('button_press_event', self.mouse_click) #self.fixed_area.drag_dest_set(Gtk.DestDefaults.ALL, [], Gdk.DragAction.MOVE) self.treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [("example", 0, 0)], Gdk.DragAction.COPY) self.treeview.enable_model_drag_dest([("example", 0, 0)], Gdk.DragAction.COPY) #treeview.enable_model_drag_source(gtk.gdk.BUTTON1_MASK, [("example", 0, 0)], Gdk.DragAction.ACTION_COPY) #treeview.enable_model_drag_dest([("example", 0, 0)], gtk.gdk.ACTION_COPY) self.treeview.connect("drag_data_received", self.onDragDataReceived) #create a storage model in this case a treemodel self.treemodel = Gtk.TreeStore(str) self.treeview.set_model(self.treemodel) #add columns usually only one in case of the treeview column = Gtk.TreeViewColumn("Objects") self.treeview.append_column(column) #add in a text renderer so we can see the items we add cell = Gtk.CellRendererText() column.pack_start(cell, False) column.add_attribute(cell, "text", 0) self.populate() self.menu() #~ def iterCopy(self, treeview, model, iter_to_copy, target_iter, pos): #~ #~ data_column_0 = model.get_value(iter_to_copy, 0) #~ data_column_1 = model.get_value(iter_to_copy, 1) #~ if (pos == gtk.TREE_VIEW_DROP_INTO_OR_BEFORE) or (pos == gtk.TREE_VIEW_DROP_INTO_OR_AFTER): #~ new_iter = model.prepend(target_iter, None) #~ elif pos == gtk.TREE_VIEW_DROP_BEFORE: #~ new_iter = model.insert_before(None, target_iter) #~ elif pos == gtk.TREE_VIEW_DROP_AFTER: #~ new_iter = model.insert_after(None, target_iter) #~ model.set_value(new_iter, 0, data_column_0) #~ model.set_value(new_iter, 1, data_column_1) #~ if model.iter_has_child(iter_to_copy): #~ for i in range(0, model.iter_n_children(iter_to_copy)): #~ next_iter_to_copy = model.iter_nth_child(iter_to_copy, i) #~ self.iterCopy(treeview, model, next_iter_to_copy, new_iter, gtk.TREE_VIEW_DROP_INTO_OR_BEFORE) def walk(self, treeiter): if model.iter_has_child(treeiter): for i in range(0, model.iter_n_children(treeiter)): yield model.iter_nth_child(treeiter, i) def onDragDataReceived(self, treeview, drag_context, x, y, selection, info, eventtime): """on data recieve we remove the item and insert in the new location, the insert location must have the same depth""" model, iter_source = treeview.get_selection().get_selected() source_path = model.get_path(iter_source) print 'source iter path %s' % source_path destination_path, pos = treeview.get_dest_row_at_pos(x, y) print 'destination iter path %s' % destination_path source_iter = model.get_iter(source_path) destination_iter = model.get_iter(destination_path) #model.remove(source_iter) print source_iter print destination_iter print 'insert' model.move_after(source_iter, destination_iter) #self.append_tree(destination_iter) #~ if self.checkSanity(model, iter_to_copy, target_iter): #~ self.iterCopy(treeview, model, iter_to_copy, target_iter, pos) #~ drag_context.finish(gtk.TRUE, gtk.TRUE, eventtime) #~ treeview.expand_all() #~ else: #~ drag_context.finish(gtk.FALSE, gtk.FALSE, eventtime) def populate(self): self.treemodel.clear() #populate the treeview with a largish tree for item1 in range(0, 5): iter_level_1 = self.append_tree('Item ' + str(item1)) for item2 in range(0, 5): iter_level_2 = self.append_tree('Sub Item ' + str(item2), iter_level_1) for item3 in range(0, 5): self.append_tree('Sub Sub Item ' + str(item3), iter_level_2) def append_tree(self, name, parent=None): """ append to the treeview if parent is null append to root level. if parent is a valid iter (possibly returned from previous append) then append under the parent """ myiter = self.treemodel.insert_after(parent, None) self.treemodel.set_value(myiter, 0, name) return myiter def menu(self): """ popover menu shown on right clicking a treeview item. """ self.treeview_menu = Gtk.Menu() for item in range(0, 5): menu_item = Gtk.MenuItem("Menu " + str(item)) self.treeview_menu.append(menu_item) def mouse_click(self, tv, event): if event.button == 3: # right mouse button pressed popup the menu self.treeview_menu.show_all() self.treeview_menu.popup(None, None, None, None, 1, 0) def selection(self, tv, treepath, tvcolumn): """ on double click get the value of the item we clicked """ model = tv.get_model() treeiter = model.get_iter(treepath) self.selected = model.get_value(treeiter, 0) self.entry.set_text(self.selected) application = application_gui() Gtk.main()