C# 如何设置Gtk#TreeModelFilter来过滤底层TreeStore?

C# 如何设置Gtk#TreeModelFilter来过滤底层TreeStore?,c#,mono,gtk#,gtktreeview,C#,Mono,Gtk#,Gtktreeview,我已经阅读了本文,作者在其中描述了如何为底层ListStore设置和使用TreeModelFilter(在教程的“过滤数据”部分下)。这项技术似乎不适用于底层的层次结构树顶。我想过滤一个多级树存储并在树视图中显示结果。这让我很难过。是否有任何教程、示例或建议 下面是代码。它的代码基本上与本教程相同,只是在处理TreeStore而不是ListStore的构造和填充方面做了一些更改。 {TreeStore用于保存联系人的“姓名”和“电子邮件地址”,分为(并保存为)根“朋友”和“亲戚”的子级。} [我

我已经阅读了本文,作者在其中描述了如何为底层ListStore设置和使用TreeModelFilter(在教程的“过滤数据”部分下)。这项技术似乎不适用于底层的层次结构树顶。我想过滤一个多级树存储并在树视图中显示结果。这让我很难过。是否有任何教程、示例或建议

下面是代码。它的代码基本上与本教程相同,只是在处理TreeStore而不是ListStore的构造和填充方面做了一些更改。 {TreeStore用于保存联系人的“姓名”和“电子邮件地址”,分为(并保存为)根“朋友”和“亲戚”的子级。}


[我在windows vista上使用mono 2.6.4/monodevelop 2.4/gtk sharp 2.12。]

似乎在筛选树模型中的行时,一行只有在其所有父行都可见时才可见。由于筛选函数隐藏父节点,因此即使文本匹配,它也不会显示子节点。我修改了您的代码以说明此问题:

现在,一个父节点以“test”开头。如果键入“test”,您将看到筛选工作正常

using System;
using Gtk;

public class TreeViewExample
{

public static void Main ()

{

    Gtk.Application.Init ();

    new TreeViewExample ();

    Gtk.Application.Run ();

}


Gtk.Entry filterEntry;
Gtk.TreeModelFilter filter;



public TreeViewExample ()
{

    // Create a Window

    Gtk.Window window = new Gtk.Window ("TreeView Example");

    window.SetSizeRequest (500,200);

    window.DeleteEvent+=delegate {Application.Quit();};



    // Create an Entry used to filter the tree

    filterEntry = new Gtk.Entry ();



    // Fire off an event when the text in the Entry changes

    filterEntry.Changed += OnFilterEntryTextChanged;



    // Create a nice label describing the Entry

    Gtk.Label filterLabel = new Gtk.Label ("Search:");



    // Put them both into a little box so they show up side by side

    Gtk.HBox filterBox = new Gtk.HBox ();

    filterBox.PackStart (filterLabel, false, false, 5);

    filterBox.PackStart (filterEntry, true, true, 5);



    // Create our TreeView

    Gtk.TreeView tv = new Gtk.TreeView ();



    // Create a box to hold the Entry and Tree

    Gtk.VBox box = new Gtk.VBox ();



    // Add the widgets to the box

    box.PackStart (filterBox, false, false, 5);

    box.PackStart (tv, true, true, 5);



    window.Add (box);





    //setting up columns and renderers





    Gtk.TreeViewColumn nameColumn = new Gtk.TreeViewColumn{Title="Name"}; 

    Gtk.CellRendererText nameCell = new Gtk.CellRendererText ();        

    nameColumn.PackStart (nameCell, true);









    Gtk.TreeViewColumn emailColumn = new Gtk.TreeViewColumn {Title="Email"}; 

    Gtk.CellRendererText emailCell = new Gtk.CellRendererText ();

    emailColumn.PackStart (emailCell, true);







    // Add the columns to the TreeView

    tv.AppendColumn (nameColumn);

    tv.AppendColumn (emailColumn);







    // Tell the Cell Renderers which items in the model to display

    nameColumn.AddAttribute (nameCell, "text", 0);

    emailColumn.AddAttribute (emailCell, "text", 1);







    // Create a model that will hold two strings 

    Gtk.TreeStore contacts = new Gtk.TreeStore (typeof (string), typeof (string));





    // Add some hierarchical data



    Gtk.TreeIter treeiter;





    //first root

    treeiter= contacts.AppendValues("testFRIENDS"); 



        // 2 children of first root

        contacts.AppendValues(treeiter, "testOgre", "stinky@hotmale.com");

        contacts.AppendValues(treeiter, "testBee", "stingy@coolguy.com");







    // second root

    treeiter= contacts.AppendValues("RELATIVES"); 



        // 3 children of second root

        contacts.AppendValues (treeiter,"Mommy","mother@family.com");

        contacts.AppendValues (treeiter,"Daddy", "father@family.com");

        contacts.AppendValues (treeiter,"tom", "cousin@family.com");









    filter = new Gtk.TreeModelFilter (contacts, null);



    // Specify the function that determines which rows to filter out and which ones to display

    filter.VisibleFunc = new Gtk.TreeModelFilterVisibleFunc (FilterTree);



    // Assign the filter as our treeview's model

    tv.Model = filter;



    // Show the window and everything on it

    window.ShowAll ();

}



private void OnFilterEntryTextChanged (object o, System.EventArgs args)

{

    // Since the filter text changed, tell the filter to re-determine which rows to display

    filter.Refilter ();

}



private bool FilterTree (Gtk.TreeModel model, Gtk.TreeIter iter)

{

    string contactname = model.GetValue (iter, 0).ToString ();



    if (filterEntry.Text == "")

        return true;



    if (contactname.IndexOf (filterEntry.Text) > -1)

        return true;

    else

        return false;

}
}

使用当前结构的最简单解决方案是,根据模型中隐藏列中的值,让“容器”节点(朋友和亲戚)的filter函数始终返回TRUE。它看起来不会完全像你想要的那样,但它会工作的


虽然有一段时间没有更新,但是对于您的所有TreeView需求来说,仍然是非常有用的资源。代码和示例使用C语言编写,但大部分代码仍然适用于GTK。

为了实现代码的正确功能,我建议您以以下方式修改代码:

1.添加新字段
private filterBool=false到你的班级

2.将
FilterTree
方法修改为此状态:

private bool FilterTree (Gtk.TreeModel model, Gtk.TreeIter iter)
{
string contactname = model.GetValue (iter, 0).ToString ();

if (filterEntry.Text == "")
    return true;

if (contactname.IndexOf (filterEntry.Text) > -1)
    return true;

if (model.IterHasChild(iter)) 
{
    filerBool = false;
    investigateChildNodes(model, iter); //method checking if currently investigated
                               //node has any child fulfilling filter contitions
    return filerBool;
}
return false;
}
3.添加缺少的方法

 private void investigateChildNodes(TreeModel model, TreeIter iter) 
    {       
        TreeIter childIter;
        model.IterChildren(out childIter, iter); 
        do
        {
            if (model.GetValue(childIter, 0).ToString().IndexOf(filterEntry.Text) > -1)
                filerBool = true;

            if (model.IterHasChild(childIter))
                investigateChildNodes(model, childIter);

        } while (model.IterNext(ref childIter));
    }

通过此修改,将检查每个节点是否存在可能满足筛选条件的子节点。如果检测到任何节点,则不会丢弃该节点

Tinki版本工作完美。我唯一不喜欢的是私有变量。这可以通过在InvestigateChildrenNodes函数中使用返回值来消除

    private bool InvestigateChildNodes(TreeModel model, TreeIter iter)
    {
        TreeIter childIter;
        model.IterChildren(out childIter, iter);

        bool result = false;
        do
        {
            if (model.GetValue(childIter, 0).ToString().Contains(FilterEntry.Text))
            {
                result = true;
                break;
            }

            if (model.IterHasChild(childIter))
            {
                result = InvestigateChildNodes(model, childIter);
                if (result)
                    break;
            }

        } while (model.IterNext(ref childIter));
        return result;
    }

它是144 L.O.C。。。此评论框不允许。请编辑您的问题,将其包括在内,以获得建议。我想我必须学习很多关于Gtk#TreeView/TreeModel设计模式和库中的其他设施的知识,然后才能开始在Gtk中实现这一级别的定制和对数据绑定的细粒度控制。
    private bool InvestigateChildNodes(TreeModel model, TreeIter iter)
    {
        TreeIter childIter;
        model.IterChildren(out childIter, iter);

        bool result = false;
        do
        {
            if (model.GetValue(childIter, 0).ToString().Contains(FilterEntry.Text))
            {
                result = true;
                break;
            }

            if (model.IterHasChild(childIter))
            {
                result = InvestigateChildNodes(model, childIter);
                if (result)
                    break;
            }

        } while (model.IterNext(ref childIter));
        return result;
    }