天天看點

TreeView簡單介紹

TreeView : TreeView是一個IMGUI控件,可以讓您為編輯器建立樹視圖、清單視圖和多清單。它可以自定義行内容呈現、拖拽邏輯、選擇邏輯、搜尋、排序和項目重命名.

TreeView類中兩個重要的函數:

BuildRoot():是一個需要被實作的抽象方法。該方法應該建立treeviewitem的完整樹并傳回根目錄。這個方法和BuildRows一起實作TreeView的初始化工作。可以使用兩種不同的方法建立一個TreeView:(1)建立項目的根和完整樹;(2)建立根和行.方法1是預設的,因為TreeView會自動處理建構行,祖先資訊等等;對于非常大的資料集或經常更改的資料,方法2是可取的.每個TreeViewItem都需要用唯一的整數ID構造,對于相同的資料元素,ID需要保持一緻,不管是否是拓展狀态。ID用于在樹中查找項目,用于選擇狀态、擴充狀态和導航。對于一個被合理初始化的TreeView,所有的treeviewitem都需要初始化“父”、“子”和“深度”屬性。根據樹的資料模型(Tree Model)可以有用的設定父和子的屬性或深度屬性,然後使用SetupParentsAndChildrenFromDepths或SetupDepthsFromParentsAndChildren方法在一次調用中設定所有行未初始化的屬性。

BuildRows():重寫該方法可以控制如何生成行。每當調用重載時或者每次擴充或收縮時,就會調用這個方法。建構行的預設實作負責根據完整的樹和項目的擴充狀态來緩存擴充的行。對于非常大的資料集或經常更改的資料,隻需要建立TreeView的行,而不是完整的樹。在這種情況下,重寫該方法以手動建構行,如果遇到收縮的父節點,那麼父節點的後代就可以被忽略,設定項的孩子用CreateChildListforCollapsedParent()方法。當使用這種方法時,建構root應該隻建立根TreeViewItem,也確定重寫GetAncestors()和GetDescendantsThatHaveChildren()和使用模型資料擷取這些資訊,否則建構架構和擴大子樹将會失敗。

SetupDepthsFromParentsAndChildren():使用輸入TreeViewItem的深度為其所有後代TreeViewItem設定正确的深度。

SetupParentsAndChildrenFromDepths():使用已設定的順序和深度值來初始化所有行的父和子屬性.

TreeViewState:TreeViewState為TreeView提供可序列化的狀态資訊。這主要是使用者可以通過與TreeView進行互動來改變的狀态,例如選擇狀态,擴充狀态,導航狀态和滾動狀态.TreeViewState是唯一應該在TreeView中序列化/反序列化的狀态.TreeView本身不是可序列化的,應該從它所代表的樹資料中進行重構.這個類中包含的所有狀态都是由TreeView自身更新的。對這個狀态的通路也可以通過TreeView API完成。

解釋TreeViewExmaple的幾個例子:

(A)SimpleTreeView是一個繼承自TreeView的類,重寫了BuildRoot方法,手動建構了一棵完整的樹。

SimpleTreeViewWindow中聲明了序列化的TreeViewState:

[SerializeField] TreeViewState m_TreeViewState;

聲明了SimpleTreeView和SearchField:

SimpleTreeView m_TreeView;

SearchField m_SearchField;

需要對它們都進行初始化:

if (m_TreeViewState == null)

m_TreeViewState = new TreeViewState ();

m_TreeView = new SimpleTreeView(m_TreeViewState);

m_SearchField = new SearchField ();

與search相關的屬性和變量:

m_SearchField.downOrUpArrowKeyPressed:當焦點搜尋字段檢測到下或上鍵被按下時,就會發出這個事件,并可用于将鍵盤焦點轉移到另一個控件,比如TreeView。

m_SearchField.OnToolbarGUII():這個函數使用工具欄UI樣式顯示搜尋字段,并使用GUILayout類來自動計算它所呈現的矩形的位置和大小。通過一個可選的清單來指定額外的布局屬性.

m_TreeView.searchString:目前的樹視圖的搜尋字元串,存儲在TreeViewState對象中.

m_TreeView.OnGUI():這是TreeView的主要GUI方法,在這裡處理和繪制treeviewitem。

(B)來看一個複雜一點的例子:MultiColumnTreeView

它不直接繼承自TreeView,而是繼承自TreeViewWithTreeModel<MyTreeElement>,而TreeViewWithTreeModel<MyTreeElement>繼承自TreeView,并且樹中的節點資料也更加複雜了,是MyTreeElement類,這個類繼承自TreeElement類。

那麼這個關系就很自然了:

TreeView簡單介紹

然而另一方面:TreeModel是一個實用程式類,它在一系列可序列化的樹元素清單中工作,每個樹元素的順序和深度定義了樹結構。它和MultiColumnTreeView又有什麼關系呢?

在MultiColumnWindow中聲明了兩個狀态:

[SerializeField] TreeViewState m_TreeViewState;

[SerializeField] MultiColumnHeaderState m_MultiColumnHeaderState;

聲明了MultiColumnTreeView和SearchField:

SearchField m_SearchField;

MultiColumnTreeView m_TreeView;

這裡解釋兩個類:MultiColumnHeaderState 和MultiColumnHeader:

MultiColumnHeader:是一個通用的類。可以使用該樹視圖來建立多列樹視圖和清單視圖.它通過拖拽來支援對列寬度的調整,并為使用者的輸入提供有用的回調。注意,使用者可以使用MultiColumnHeader的上下文菜單隐藏列。

MultiColumnHeaderState :由MultiColumnHeader産生的狀态。

對狀态的初始化:

if (m_TreeViewState == null)

m_TreeViewState = new TreeViewState();

bool firstInit = m_MultiColumnHeaderState == null;

var headerState = MultiColumnTreeView.CreateDefaultMultiColumnHeaderState(multiColumnTreeViewRect.width);

if (MultiColumnHeaderState.CanOverwriteSerializedFields(m_MultiColumnHeaderState, headerState))MultiColumnHeaderState.OverwriteSerializedFields(m_MultiColumnHeaderState, headerState);

m_MultiColumnHeaderState = headerState;

MultiColumnHeader的初始化,使樹視圖可調整列寬等:

var multiColumnHeader = new MyMultiColumnHeader(headerState);

if (firstInit)

multiColumnHeader.ResizeToFit ();

将資料加入到樹中,形成樹結構。

var treeModel = new TreeModel<MyTreeElement>(GetData());

m_TreeView = new MultiColumnTreeView(m_TreeViewState, multiColumnHeader, treeModel);

這裡就可以明白地知道TreeModel是用來結合TreeView生成樹視圖結構的。

這裡僅描述了實作TreeView的大概結構,可能還有不少錯誤,具體細節有時間再看吧。