1

「GtkSharp TreeView チュートリアル」を読みました。著者は、基になる ListStore の TreeModelFilter をセットアップして使用する方法を説明しています (チュートリアル セクション「データのフィルタリング」の下)。この手法は、基礎となる階層 TreeStore では機能しないようです。マルチレベルの TreeStore をフィルタリングし、結果を TreeView に表示したいと考えています。それは私に本当に苦労を与えています。それを行うためのチュートリアル、サンプル、または提案はありますか?

以下はコードです。基本的にチュートリアルと同じコードですが、ListStore ではなく TreeStore の構築と作成に対処するための変更が加えられています。{TreeStore は、連絡先の「名前」と「電子メール アドレス」を保存するために使用され、ルート「友人」と「親戚」の子に分割 (および保存) されます }

// compilation requires references to:
// gtk-sharp, atk-sharp and glib-sharp


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("FRIENDS");

        // 2 children of first root
        contacts.AppendValues(treeiter, "Ogre", "stinky@hotmale.com");
        contacts.AppendValues(treeiter, "Bee", "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;
    }
}

[Windows Vista で mono 2.6.4 /monodevelop 2.4 / gtk-sharp 2.12 を使用しています。]

4

3 に答える 3

1

ツリー モデルで行をフィルタリングする場合、すべての親も表示されている場合にのみ行が表示されるようです。フィルター関数は親ノードを非表示にするため、テキストが一致しても子ノードは表示されません。この問題を説明するためにコードを変更しました。

ここで、親ノードの 1 つが「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;

}

}

現在の構造で最も簡単な解決策は、モデルの非表示列の値に基づいて、フィルター関数が常に「コンテナー」ノード (友人と親戚) に対して TRUE を返すようにすることです。希望どおりに見えるわけではありませんが、機能します。

GTK+ Treeview チュートリアルは、しばらく更新されていませんが、TreeView のすべてのニーズに対して非常に役立つリソースです。コードと例は C で記述されていますが、そのほとんどは GTK# にも適用されます。

于 2010-08-25T13:20:29.483 に答える
1

コードが正しく機能するようにするには、次の方法でコードを変更することをお勧めします。

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));
    }

この変更により、フィルタリング条件を満たす可能性のある子ノードについてすべてのノードがチェックされます。いずれかが検出された場合、ノードは破棄されません。

于 2013-11-20T13:33:53.590 に答える