2010-08-25 15 views
0

J'ai lu le "GtkSharp TreeView tutorial" dans lequel l'auteur décrit comment installer et utiliser un TreeModelFilter pour un ListStore sous-jacent (sous la section tutorial "Filtering Data"). La technique ne semble pas fonctionner pour un TreeStore hiérarchique sous-jacent. Je veux filtrer un TreeStore à plusieurs niveaux et montrer les résultats dans un TreeView. Cela me donne un vrai moment difficile. Y a-t-il des tutoriels, des exemples ou des suggestions pour le faire?Comment configurer un Gtk # TreeModelFilter qui filtre un TreeStore sous-jacent?

Voici le code. C'est fondamentalement le même code que le tutoriel excepté les changements pour traiter la construction et la population d'un TreeStore plutôt que d'un ListStore. {Le TreeStore est utilisé pour sauvegarder des « noms » et « adresses e-mail » des contacts, divisés en (et enregistrées comme) les enfants des racines « amis » et « parents »}

// 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", "[email protected]"); 
     contacts.AppendValues(treeiter, "Bee", "[email protected]"); 

     // second root 
     treeiter = contacts.AppendValues("RELATIVES"); 

     // 3 children of second root 
     contacts.AppendValues(treeiter, "Mommy", "[email protected]"); 
     contacts.AppendValues(treeiter, "Daddy", "[email protected]"); 
     contacts.AppendValues(treeiter, "tom", "[email protected]"); 

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

[J'utilise mono 2.6.4/monodevelop 2.4/gtk-sharp 2.12 sous Windows Vista.]

+0

Pouvez-vous poster votre code? –

+0

Ses 144 L.O.C ... cette boîte de commentaire ne l'admet pas. – explorer

+0

Modifier votre question pour l'inclure –

Répondre

1

Il semble que lorsque vous filtrez des lignes dans un modèle d'arborescence, une ligne n'est visible que si TOUS ses parents sont visibles. Puisque votre fonction de filtre cache les nœuds parents, elle n'affiche pas les nœuds enfants même si le texte correspond. J'ai modifié votre code pour illustrer ce problème:

Maintenant, un des nœuds parents commence par 'test'. Si vous tapez 'test', vous verrez que le filtrage fonctionne correctement.

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", "[email protected]"); 

     contacts.AppendValues(treeiter, "testBee", "[email protected]"); 







    // second root 

    treeiter= contacts.AppendValues("RELATIVES"); 



     // 3 children of second root 

     contacts.AppendValues (treeiter,"Mommy","[email protected]"); 

     contacts.AppendValues (treeiter,"Daddy", "[email protected]"); 

     contacts.AppendValues (treeiter,"tom", "[email protected]"); 









    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; 

} 

}

serait d'avoir la fonction de filtre renvoie toujours pour les noeuds « conteneurs » (amis et parents), sur la base d'une valeur La solution la plus simple avec votre structure actuelle dans une colonne cachée dans la modèle. Cela ne ressemblera pas exactement à ce que vous voulez, mais cela fonctionnera.

Le GTK+ Treeview Tutorial, bien que non mis à jour depuis un certain temps, reste une ressource très utile pour tous vos besoins TreeView. Le code et les exemples sont en C, mais la plupart s'applique toujours à GTK #.

+0

Merci pour le conseil. Je suppose que je dois en apprendre beaucoup sur le modèle de conception Gtk # TreeView/TreeModel et d'autres fonctionnalités de la bibliothèque avant de pouvoir commencer ce niveau de personnalisation et de contrôle fin sur la liaison de données dans Gtk #. – explorer

+0

Merci beaucoup ... Je suis dessus. – explorer

1

Afin d'atteindre la fonctionnalité correcte de votre code, je vous suggère de le modifier de manière suivante:

1.Add nouveau champ private filterBool = false; à votre classe

2.MODIFIER votre méthode FilterTree à cet état :

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

méthode 3.Ajouter manquant

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

Avec cette modification, tous les nœuds sont vérifiés pour détecter d'éventuels nœuds enfants, ce qui pourrait remplir les conditions de filtrage. Si l'un d'eux est détecté, le noeud n'est pas ignoré.