使用NodeView+NodeStore来显示分层数据

本文关键字:分层 数据 显示 NodeView+NodeStore 使用 | 更新日期: 2023-09-27 18:27:49

我想要一个NodeView来显示一些分层数据,比如这样的:

Father Mother
====== ======
Jon    Ann
 +Sons
 +--Jon  20
 +--Dave 10
 +Daughters
 +--Ann  
Ron    Mary
Paul   Eve
 +Sons
 +--Bob  4

如果"儿子"answers"女儿"是空的,就不应该显示。我已经创建了三个业务类:Parents、Son和Daughter,并且我正在创建TreeNode子类来显示它们。我用Monosdevelop设计器设计了一个Window,并用代码重新创建了nodeView。nodeview根本不显示任何内容,我想知道为什么。这是代码,在一个文件中,这样任何人都可以测试它:

using System;
using Gtk;
using System.Collections.Generic;
using System.Linq;
namespace Family.Model
{
    public class Son {
        public string Name {get;set;}
        public string Age {get;set;}
        public Son(string n,string a) {
            Name=n;Age=a;
        }
    }
    public class Parents 
    {
        public string Father {get;set;}
        public string Mother {get;set;}
        public List<string> Daughters {get;set;}
        public Dictionary<string,Son> Sons {get;set;}
        public Parents() {
            Daughters=new List<string>();
            Sons=new Dictionary<string, Son>();         
        }
    }
}
namespace Family.View
{
    using Family.Model;
    [TreeNode (ListOnly=false)]
    public class ParentsNode:TreeNode
    {
        private Parents parents;
        public ParentsNode (Parents p):base()
        {
            this.parents=p;
            DaughtersRoot rootd=new DaughtersRoot();
            SonsRoot roots=new SonsRoot();
            if (p.Sons.Count>0) {
                this.AddChild (roots);
                p.Sons.Values.ToList ().ForEach (x=>roots.AddChild(new SonNode(x)));
            }
            if (p.Daughters.Count>0) {
                this.AddChild (rootd);
                p.Daughters.ForEach (x=>rootd.AddChild(new DaughterNode(x)));
            }
            OnChanged ();
        }
        [Gtk.TreeNodeValue(Column=0) ]
        public string Father {
            get { return parents.Father;} 
            set { parents.Father=value;OnChanged ();}
        }
        [Gtk.TreeNodeValue (Column=1)]
        public string Mother {
            get { return parents.Mother; }
            set { parents.Mother=value;OnChanged ();}
        }
    }
    [TreeNode(ListOnly=false)]
    public class DaughtersRoot:TreeNode
    {
        [Gtk.TreeNodeValue(Column=0) ]
        public string Label {
            get {return "Daughters"; }
        }
    }
    [TreeNode(ListOnly=false)]
    public class SonsRoot:TreeNode
    {
        [Gtk.TreeNodeValue(Column=0) ]
        public string Label {
            get {return "Sons"; }
        }
    }
    [TreeNode(ListOnly=false)]
    public class DaughterNode:TreeNode {
        private string mName;       
        public DaughterNode(string s):base() {
            this.Name=s;
        }
        [Gtk.TreeNodeValue(Column=0) ]
        public string Name {
            get {return mName;}
            set {mName=value;OnChanged ();}
        }
    }
    [TreeNode(ListOnly=false)]
    public class SonNode:TreeNode {
        private Son son;
        public SonNode(Son s):base() {
            this.son=s;
            OnChanged ();
        }
        [Gtk.TreeNodeValue(Column=0)]
        public string Name {
            get { return this.son.Name; }
            set {son.Name=value;OnChanged ();}
        }
        [Gtk.TreeNodeValue(Column=1)]
        public string Age {
            get { return this.son.Age; }
            set {son.Age=value;OnChanged ();}
        }
    }
    public class MainWindow: Gtk.Window
    {   
        private global::Gtk.ScrolledWindow GtkScrolledWindow;
        private global::Gtk.NodeView treeFamily;
        private NodeStore storeParents=new NodeStore(typeof(ParentsNode));
        protected virtual void Build ()
        {
            global::Stetic.Gui.Initialize (this);
            // Widget MainWindow
            this.Name = "MainWindow";
            this.Title = global::Mono.Unix.Catalog.GetString ("MainWindow");
            this.WindowPosition = ((global::Gtk.WindowPosition)(4));
            this.GtkScrolledWindow = new global::Gtk.ScrolledWindow ();
            this.GtkScrolledWindow.Name = "GtkScrolledWindow";
            this.GtkScrolledWindow.ShadowType = ((global::Gtk.ShadowType)(1));
            this.treeFamily = new global::Gtk.NodeView ();
            this.treeFamily.CanFocus = true;
            this.treeFamily.Name = "treeFamily";
            this.GtkScrolledWindow.Add (this.treeFamily);
            this.Add (this.GtkScrolledWindow);
            if ((this.Child != null)) {
                this.Child.ShowAll ();
            }
            this.DefaultWidth = 400;
            this.DefaultHeight = 300;
            this.Show ();
            this.DeleteEvent += new global::Gtk.DeleteEventHandler (this.OnDeleteEvent);
        }   
        public MainWindow (): base (Gtk.WindowType.Toplevel) {
            Build ();
            Parents p=new Parents();
            p.Father="Bob";
            p.Mother="Mary";
            storeParents.AddNode (new ParentsNode (p));
            p=new Parents();
            p.Father="Ron";
            p.Mother="Ann";
            p.Sons.Add ("David",new Son("David","20"));
            p.Sons.Add ("Matt",new Son("Matt","10"));
            p.Daughters.Add ("Elaine");
            p.Daughters.Add ("Kate");
            storeParents.AddNode (new ParentsNode(p));
            this.treeFamily=new NodeView(storeParents);
            Gtk.TreeViewColumn fatherColumn = new Gtk.TreeViewColumn 
                                            ("Father",new CellRendererText(),"text",0);
            Gtk.TreeViewColumn motherColumn = new Gtk.TreeViewColumn 
                                            ("Mother",new CellRendererText(),"text",1);
            treeFamily.AppendColumn (fatherColumn);
            treeFamily.AppendColumn (motherColumn);
            treeFamily.ShowAll ();
        }
        protected void OnDeleteEvent (object sender, DeleteEventArgs a) {
            Application.Quit ();
            a.RetVal = true;
        }
    }
    class MainClass
    {
        public static void Main (string[] args) {
            Application.Init ();
            MainWindow win = new MainWindow ();
            win.Show ();
            Application.Run ();
        }
    }
}

使用NodeView+NodeStore来显示分层数据

Gtk模型绑定的工作方式与其他工具包截然不同。话虽如此,以下是您需要了解的入门知识:

GTK中有几种类型的"控件"或小部件可以显示矩阵/列表数据:

  • NodeView(最简单)
  • TreeView

现在,AFAIC,NodeView只存在于GTK#中,也就是.Net绑定中。TreeView在所有其他绑定中都可用,并且是GTK+核心的一部分。不同的是,NodeView在某种程度上更容易使用,但更有限。

如果您只需要显示列表数据,也就是说,不需要分层数据(尽管您似乎需要),那么您将希望使用NodeView

如果您需要显示分层数据,那么您将使用TreeView。

无论您使用哪种方式,您都必须在该小部件中设置您需要显示的内容,例如您的列。GTK中的NodeView/TreeView单元格与其他基本工具包的区别在于,例如,NodeView列可以在其单元格内显示其他小部件,而不仅仅是文本,因此您可以在一列中有一个显示进度条或复选框的单元格。在这些单元格中使用的小部件称为CellRenderers,有CellRendererText、CellRenderToggle等。

现在,这些控件通过"存储"与数据"绑定",例如:

  • NodeStore
  • ListStore
  • TreeStore

您将再次使用哪一个取决于您的需求和将要使用的小部件类型,因此,如果您只需要显示简单数据,请使用NodeStore,如果您需要显示分层数据,则使用TreeStore。这些数据存储的一个强大之处在于,您不仅可以在其中存储NodeView/TreeView小部件上显示的数据,还可以存储任何其他不一定需要显示的数据。您甚至可以存储对象,例如,您可以有一个包含4列的存储,其中3列显示在小部件上,第四列保存完整对象的实例。

在这个链接中,有我提到的每个案例的样本,你可以试试。我认为你应该使用"树"模型来完成你想要的,而不是"节点"。

GTK是一个强大的工具包,但有时很难理解它是如何工作的。我希望这个介绍对你有用。