Слишком глубокая ошибка уровня стека Ruby-Gnome2
-
03-07-2019 - |
Вопрос
У меня есть Gtk::TreeView с Gtk::TreeModel и Gtk::TreeModelFilter.Модель дерева выглядит следующим образом:
category1
--> actual row of data
category2
--> actual row of data
Я хочу фильтровать содержимое @search_entry, но я хочу, чтобы категория 1 отображалась, если строка под ней все еще видна, и чтобы категория 2 была скрыта, если под ней нет видимых строк.Насколько я понимаю, Gtk::TreeModelFilter#set_visible_func заключается в том, что вы получаете модель и итер из «дочерней модели», чтобы вы могли проверить, отображать ли дочерний итер.Эта функция вызывается на каждом итере модели каждый раз, когда я вызываю Gtk::TreeModelFilter#refilter. Поэтому я говорю:если итератор, который вы мне только что дали, находится на первом уровне, получите путь, уменьшите его, преобразуйте в тот же путь в модели фильтра и используйте, существует ли новый путь, для проверки видимости.
@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
Линия
has_visible_children = @tree_filter.convert_child_path_to_path(iter_path) ? true : false
вызывает «ЭТУ ОШИБКУ:уровень стека слишком глубок» для каждого итера.
Здесь происходит бесконечная рекурсия, но я не понимаю, где она происходит и как ее избежать.Я уверен, что думаю об этом неправильно, но я работал над этим пару дней и не добился прорыва.
Решение
refilter
вызывает блок на каждом узле.Однако возвращаемое значение не сохраняется вместе с узлом, поэтому независимо от того, как вы это сделаете, если вам придется смотреть вниз по дереву, вы будете повторять вычисления.
# 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
Другие советы
Я ничего не знаю о Ruby, но эта ошибка явно указывает на слишком большое количество итераций рекурсии.Контекст необходимо сохранять в стеке для каждого вызова, вызывая – ура –
переполнение стека
:-) Добавьте переменную, чтобы отслеживать ваши уровни итераций и распечатать ее с ошибкой.Либо что-то не так с вашими данными, либо с логикой рекурсии, либо с тем и другим.