2009-03-04 4 views
0

J'ai un Gtk :: TreeView avec un Gtk :: TreeModel et un Gtk :: TreeModelFilter. Le modèle d'arbre est comme ceci:Erreur de niveau de pile trop grave Ruby-Gnome2

category1 
    --> actual row of data 
category2 
    --> actual row of data 

Je veux filtrer le contenu de @search_entry, mais je veux category1 à afficher si une ligne en dessous est encore visible, et category2 à cacher s'il n'y a pas les rangées sous elle sont encore visibles. Ma compréhension de Gtk :: TreeModelFilter # set_visible_func est que vous obtenez le modèle et l'iter du "modèle enfant", de sorte que vous pouvez vérifier si vous voulez afficher l'enfant. Cette fonction est appelée sur chaque itérateur du modèle à chaque fois que j'appelle Gtk :: TreeModelFilter # refilter. Donc je dis: si l'iter que vous venez de me donner est au premier niveau, récupérez le chemin, descendez un, convertissez en le même chemin sur le modèle du filtre et utiliser si le nouveau chemin existe pour tester la visibilité.

@store = Gtk::TreeStore.new(Gdk::Pixbuf, String, String, Menagerie::Program, TrueClass) 
@tree_filter = Gtk::TreeModelFilter.new(@store) 
@treeview.model = @tree_filter 

# @first_time gets set to false after the model is loaded the first time 
@first_time = true 
@tree_filter.set_visible_func do |model, iter| 
    has_visible_children = true 
    begin 
    iter_path = iter.path 
    if iter_path.depth == 1 && @first_time != true 
     iter_path.down! 
     has_visible_children = @tree_filter.convert_child_path_to_path(iter_path) ? true : false 
    end 
    rescue => e 
    puts "THIS ERROR: " + e.message 
    end 
    unless @search_entry.text == "" 
    if [1,2].collect {|i| iter[i] =~ /#{@search_entry.text}/i }.any? 
     true 
    elsif iter[4] == true and has_visible_children 
     true 
    else 
     false 
    end 
    else 
    true 
    end 
end 

La ligne

has_visible_children = @tree_filter.convert_child_path_to_path(iter_path) ? true : false 

provoque une "cette erreur: niveau de pile trop profond" pour chaque sortie iter.

Il y a une récurrence infinie qui se passe ici, mais je ne vois pas où ça se passe ni comment je peux l'éviter. Je suis sûr que j'y pense de la mauvaise façon, mais je l'ai piraté quelques jours sans une percée.

Répondre

1

refilter appelle le bloc sur chaque noeud. Cependant, la valeur de retour n'est pas enregistrée avec le nœud, donc peu importe comment vous le faites, si vous devez regarder dans l'arborescence, vous répéterez les calculs.

# Simplified version - returns true if search_text found in iter or any of its 
# first-level children. 
# Let's assume you add a method to GTK::TreeIter: 
# def has_text? search_text 
#  self[1] =~ /#{search_text}/i or self[2] =~ /#{search_text}/i 
# end 
@tree_filter.set_visible_func do |model, iter| 
    next true if @search_entry.text.empty? # No filtering if no search text 
    next true if iter.path.depth == 0  # Always show root node 
    next true if iter.has_text? @search_entry.text 

    if child_iter = iter.first_child # Then we have children to check 
    has_visible_children = false 
    loop do 
     has_visible_children ||= child_iter.has_text? @search_entry.text 
     break unless child_iter.next! # returns false if no more children 
    end 
    next has_visible_children 
    end 

    next false # Not root, doesn't contain search_text, has no children 
end 
+0

D'accord, je vois. Nous pouvons tout comprendre à partir du TreeModel, sans nous soucier du TreeModelFilter. Et vous avez nettoyé mon code! Merci, Sarah. – method

1

Je ne connais rien à Ruby, mais cette erreur pointe clairement vers trop d'itérations de récursivité. Le contexte doit être stocké sur la pile pour chaque appel, ce qui - hourra - un

stack overflow

:-) Ajouter une variable pour suivre vos niveaux d'itérations et l'imprimer avec l'erreur. Il y a quelque chose qui ne va pas avec vos données ou la logique de récurrence, ou les deux.

Questions connexes