Gtk3アプリ TreeViewとデータ各種処理２

####TreeViewデータ処理

[前回のTreeViewデータ処理](https://qiita.com/iota_11/items/33cc292d1be7278ed5d2)の続きです。

#####先頭に一件だけデータを追加する

```cs
 Gtk.TreeIter iterFirst;
 //先頭のIterを取得する
 musicListStore.GetIterFirst(out iterFirst);
 //先頭の前のIterを取得する
 Gtk.TreeIter iter = musicListStore.InsertBefore(iterFirst);
 Song Song1 = new Song ("test test", "testtest");
 //Liststoreにセットする
 musicListStore.SetValue(iter, 0, Song1);
```

```cs
  static public void _addFirstRow<T>(this Gtk.ListStore listStore,T obj,int columnName = 0)
    {

        if (listStore.IterNChildren() == 0)
        {
            listStore.AppendValues(obj);
            return;
        }
        
        Gtk.TreeIter iterFirst;
        //先頭のIterを取得する
        listStore.GetIterFirst(out iterFirst);
        //先頭の前のIterを取得する
        Gtk.TreeIter iter = listStore.InsertBefore(iterFirst);
        //Liststoreにセットする
        listStore.SetValue(iter, columnName, obj);
    }
```


#####最後の行に一件だけデータを追加する

```cs
 Gtk.TreeIter iter = musicListStore.Append();
 Song Song1 = new Song ("Daft Punk", "Technologic");
 musicListStore.SetValue(iter, 0, Song1);
```

```cs
    static public void _addRow<T>(this Gtk.ListStore listStore, T obj, int columnNum = 0)
    {
        Gtk.TreeIter iter = listStore.Append();
        listStore.SetValue(iter, columnNum, obj);
    }
```

#####TreeViewの選択した行の後にデーターを一件追加する

```cs
TreeIter iter;
 ITreeModel model;
 if (treeView1.Selection.GetSelected(out model,out iter))
 {   
     Gtk.TreeIter iterAfter = musicListStore.InsertAfter(iter);
     Song Song1 = new Song ("after after", "after after");
     musicListStore.SetValue(iterAfter, 0, Song1);
 }
```

#####TreeViewの選択した行を削除する

```cs
TreeIter iter;
ITreeModel model;
if (treeView1.Selection.GetSelected(out model,out iter))
{
        musicListStore.Remove(ref iter);
}
```

```cs
static public void _deleteSelectedRow<T>(this Gtk.TreeView treeView, Gtk.ListStore listStore)
  {
     TreeIter iter;
     ITreeModel model;
     if (treeView.Selection.GetSelected(out model,out iter))
     {
         listStore.Remove(ref iter);
     }
}
```

#####TreeViewの選択した行を取得する

```cs
private void on_treeViewSection1_changed(object sender , EventArgs e){
	
	TreeIter iter;
	ITreeModel model;
	if (treeView1.Selection.GetSelected(out model,out iter))
	{
		testTable modelData = (testTable)testTableListStore.GetValue(iter, 0);
	}		
}
```

```cs
static public object _getSelectedRow<T>(this Gtk.TreeView treeView,Gtk.ListStore listStore)
{
    TreeIter iter;
    ITreeModel model;
    if (treeView.Selection.GetSelected(out model,out iter))
    {
        T modelData = (T)listStore.GetValue(iter, 0);
        return modelData;
    }
    return null;
}
```

#####ListStoreのRowChangedの処理

```cs
 listStore1.RowChanged += delegate(object o, RowChangedArgs args)
    {
        ListStore testStore = ((ListStore)o);
        TreeIter iter;
        if (testStore.GetIter(out iter, args.Path))
        {
            testModel testModel1 = (testModel)testStore.GetValue(iter, 0);
            Console.WriteLine("testModel1" + testModel1  );          
        }
    };
```

```cs

testTableListStore.RowChanged += delegate(object o, RowChangedArgs args)
{
    ListStore testStore = ((ListStore)o);
    testTable testTable1 = (testTable)testStore._getListStoreRowChanged<testTable>(args);
};

 static public object _getListStoreRowChanged<T>(this Gtk.ListStore listStore, RowChangedArgs args)
    {
        TreeIter iter;
        if (listStore.GetIter(out iter, args.Path))
        {
            T model = (T)listStore.GetValue(iter, 0);
            return model;
        }
        return null;
    }
```

#####Clearを使わずにRowを削除する

ListStore.Clear()はクラッシュすることがあり、代わりの手段

```cs
for (int i = 0; i < musicListStore.IterNChildren(); i++) {
	TreeIter iter;
	if (musicListStore.IterNthChild(out iter, i))
	{
  	  musicListStore.Remove(ref iter);
	}
}

if (musicListStore.IterNChildren() > 0)
{
	TreeIter iter;
	if (musicListStore.IterNthChild(out iter, 0))
	{
 	   musicListStore.Remove(ref iter);
	}
}
```
拡張クラス

```cs
 static public void _ClearCustom(this Gtk.ListStore listStore)
    {
        for (int i = 0; i < listStore.IterNChildren(); i++) {
            TreeIter iter;
            if (listStore.IterNthChild(out iter, i))
            {
                listStore.Remove(ref iter);
            }
        }
        if (listStore.IterNChildren() > 0)
        {
            TreeIter iter;
            if (listStore.IterNthChild(out iter, 0))
            {
                listStore.Remove(ref iter);
            }
        }
    }
```

#####サンプル

```cs
using System;
using System.Collections.Generic;
using Gtk;
using UI = Gtk.Builder.ObjectAttribute;

namespace treeViewTest
{
    public class Song
    {
        public Song (string artist, string title)
        {
            this.Artist = artist;
            this.Title = title;
        } 
        public string Artist;
        public string Title;
    }
    partial class MainWindow
    {

        [UI] private Gtk.TreeView treeView1 = null;
	
        [UI] private Gtk.Button insertAfterBtn = null;
        [UI] private Gtk.Button insertBeforeBtn = null;
	
        [UI] private Gtk.Button appendBtn = null;
	
        [UI] private Gtk.TreeSelection selection1 = null;
        private Gtk.ListStore musicListStore;

        private void on_insertAfterBtn_clicked(object sender , EventArgs e)
        {
            TreeIter iter;
            ITreeModel model;
            if (treeView1.Selection.GetSelected(out model,out iter))
            {   
                Gtk.TreeIter iterAfter = musicListStore.InsertAfter(iter);
                Song Song1 = new Song ("after after", "after after");
                musicListStore.SetValue(iterAfter, 0, Song1);
            }
        }

        private void on_appendBtn_clicked(object sender , EventArgs e){
                
            Gtk.TreeIter iter = musicListStore.Append();
            Song Song1 = new Song ("Daft Punk", "Technologic");
            musicListStore.SetValue(iter, 0, Song1);
        }

		private void on_insertBeforeBtn_clicked(object sender , EventArgs e)
        {

            Gtk.TreeIter iterFirst;
            //先頭のIterを取得する
            musicListStore.GetIterFirst(out iterFirst);
            //先頭の前のIterを取得する
            Gtk.TreeIter iter = musicListStore.InsertBefore(iterFirst);
            Song Song1 = new Song ("test test", "testtest");
            //Liststoreにセットする
            musicListStore.SetValue(iter, 0, Song1);
			
		}

        void _mkTreeView()
        {
            List<Song> songs = new List<Song>();

            songs.Add (new Song ("Dancing DJs vs. Roxette", "Fading Like a Flower"));
            songs.Add (new Song ("Xaiver", "Give me the night"));
            songs.Add (new Song ("Daft Punk", "Technologic"));

            Gtk.TreeViewColumn artistColumn = new Gtk.TreeViewColumn ();
            artistColumn.Title = "Artist";
            Gtk.CellRendererText artistNameCell = new Gtk.CellRendererText ();
            artistColumn.PackStart (artistNameCell, true);

            Gtk.TreeViewColumn songColumn = new Gtk.TreeViewColumn ();
            songColumn.Title = "Song Title";
            Gtk.CellRendererText songTitleCell = new Gtk.CellRendererText ();
            songColumn.PackStart (songTitleCell, true);

            treeView1.AppendColumn (artistColumn);
            treeView1.AppendColumn (songColumn);

            musicListStore = new Gtk.ListStore (typeof (Song));
            
            foreach (Song song in songs) {
                musicListStore.AppendValues (song);
            }

            artistColumn.SetCellDataFunc (artistNameCell, new Gtk.TreeCellDataFunc (RenderArtistName));
            songColumn.SetCellDataFunc (songTitleCell, new Gtk.TreeCellDataFunc (RenderSongTitle));

            treeView1.Model = musicListStore;

        }        
        private void RenderArtistName (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter)
        {
            Song song = (Song) model.GetValue (iter, 0);

            if (song.Artist.StartsWith ("X") == true) {
                (cell as Gtk.CellRendererText).Foreground = "red";
            } else {
                (cell as Gtk.CellRendererText).Foreground = "darkgreen";
            }

            (cell as Gtk.CellRendererText).Text = song.Artist;
        } 
        private void RenderSongTitle (Gtk.TreeViewColumn column, Gtk.CellRenderer cell, Gtk.ITreeModel model, Gtk.TreeIter iter)
        {
            Song song = (Song) model.GetValue (iter, 0);
            (cell as Gtk.CellRendererText).Text = song.Title;
        } 
    }
}

```

####考察
データを追加更新していく際に、データ全体（配列複数）を全部入れ直しを何度もやっていると、メモリリークやポインタエラーで落ちることがある。
データは一件ずつ先頭や最後に入れて更新していくほうがよい。
データをがちゃがちゃやっていると、ListStore.Clear()を実行する時にアプリが落ちることがある。

#####ListStore.Clear()は頻繁に使うとクラッシュする

バグのようなので代わりの手段で削除する

#####Clear時にはtreeView1.ModelにはNullをいれたほうがよい

Gtk-CRITICAL **: gtk_list_store_iter_next: assertion こののようなエラーがでます。
古いiterがModelの中に残ってていることが起こるエラーのようです。

[Gtk3アプリ GtkButton処理関連](https://qiita.com/iota_11/items/e7bdcdc854b618dd6368)に続く