Informasi di halaman ini mengasumsikan pembaca memiliki pengetahuan dasar konsep IMGUI (Immediate Mode GUI). Untuk informasi tentang IMGUI dan menyesuaikan jendela Editor, merujuk ke Memperpanjang Editor dan .
TreeView adalah kontrol IMGUI yang digunakan untuk menampilkan data hirarkis yang dapat Anda kembangkan dan runtuh. Gunakan TreeView untuk membuat tampilan daftar yang sangat dapat disesuaikan dan meja multi-kolumn untuk jendela Editor, yang dapat Anda gunakan bersama kontrol dan komponen IMGUI lainnya.
Lihat dokumentasi API Scripting Unity pada TreeView untuk informasi tentang fungsi API TreeView yang tersedia.
Perhatikan bahwa TreeView bukan model data pohon. Anda dapat membangun TreeView menggunakan struktur data pohon yang Anda sukai. Ini bisa menjadi model pohon C #, atau struktur pohon berbasis Unity seperti hierarki Transform.
rendering TreeView ditangani dengan menentukan daftar item yang diperluas yang disebut baris. Setiap baris mewakili satu TreeViewItem
. Setiap TreeViewItem
mengandung informasi induk dan anak-anak, yang digunakan oleh TreeView untuk menangani navigasi (kunci dan input mouse).
TreeView memiliki satu akar TreeViewItem
yang tersembunyi dan tidak muncul di Editor. Artikel ini adalah akar dari semua barang lainnya.
Kelas yang paling penting selain dari TreeView sendiri adalah TreeViewItem dan TreeViewState.
TreeViewState (TreeViewState) mengandung informasi state yang berubah ketika berinteraksi dengan bidang TreeView di Editor, seperti state seleksi, state diperluas, state navigasi, dan state scroll. TreeViewState
adalah satu-satunya keadaan yaitu serializable. PohonView sendiri tidak serializable - itu direkonstruksi dari data yang mewakili ketika dibangun atau dimuat kembali. Tambahkan TreeViewState
sebagai bidang di kelas EditorWindow
-derived Anda untuk memastikan bahwa negara yang berubah pengguna tidak hilang ketika mengisi ulang scriptsSepotong kode yang memungkinkan Anda untuk membuat Komponen Anda sendiri, memicu peristiwa permainan, memodifikasi sifat komponen dari waktu ke waktu dan menanggapi input pengguna dengan cara apa pun yang Anda sukai. More info
Lihat di Glossary atau memasukkan mode Play (lihat dokumentasi pada memperluas Editor untuk informasi tentang cara melakukan ini). Sebagai contoh kelas yang mengandung bidang TreeViewState
, lihat Contoh 1: TreeView sederhana, di bawah ini.
TreeViewItem (TreeViewItem) berisi data tentang item TreeView individu, dan digunakan untuk membangun representasi struktur pohon dalam Editor. Setiap TreeViewItem
harus dibangun dengan ID bilangan bulat yang unik (sebagai barang di TreeView). ID digunakan untuk menemukan item di pohon untuk state seleksi, state diperluas, dan navigasi. Jika pohon mewakili benda Unity, gunakan GetInstanceID untuk setiap objek sebagai ID untuk TreeViewItem
. ID yang digunakan pada TreeViewState
untuk bertahan keadaan yang berubah pengguna (seperti item yang diperluas) ketika memuat ulang skrip atau memasukkan mode Play di Editor.
Semua TreeViewItems
memiliki properti depth
, yang menunjukkan indentasi visual. Lihat contoh Memastikan TreeView di bawah ini untuk informasi lebih lanjut.
BuildRoot (BuildRoot) adalah metode abstrak tunggal dari kelas TreeView
yang harus diimplementasikan untuk membuat TreeView. Gunakan metode ini untuk menangani membuat item akar pohon. Ini disebut setiap kali Reload disebut di pohon. Untuk pohon sederhana yang menggunakan set data kecil, buat seluruh pohon TreeViewItems
di bawah item akar di BuildRoot
. Untuk pohon yang sangat besar, tidak optimal untuk membuat seluruh pohon pada setiap reload. Dalam situasi ini, membuat akar dan kemudian menimpa metode BuildRows
untuk hanya membuat item untuk baris saat ini. Sebagai contoh dari BuildRoot
dalam penggunaan, lihat Contoh 1: TreeView sederhana di bawah ini.
BuildRows (BuildRows) adalah metode virtual di mana pelaksanaan default menangani membangun daftar baris berdasarkan pohon penuh yang dibuat di BuildRoot
. Jika hanya akar dibuat dalam BuildRoot
, metode ini harus ditimidasi untuk menangani baris yang diperluas. Lihat Memastikan TreeView, di bawah ini, untuk informasi lebih lanjut.
Diagram ini meringkas urutan dan pengulangan metode acara BuildRoot
dan BuildRows
selama masa pakai TreeView. Perhatikan bahwa metode BuildRoot
disebut sekali setiap kali Reload
disebut. BuildRows
disebut lebih sering karena disebut sekali pada Reload
(kanan setelah BuildRoot
) dan setiap kali TreeViewItem
diperluas atau runtuh.
TreeView diinisialisasi ketika metode Reload
disebut dari objek TreeView.
Ada dua cara untuk mengatur TreeView:
Create the full tree - Buat TreeViewItem
s untuk semua item dalam data model pohon. Ini adalah default dan membutuhkan kode lebih sedikit untuk mengatur. Pohon penuh dibangun ketika BuildRoot disebut dari objek TreeView.
Create only the expanded items - Pendekatan ini mengharuskan Anda untuk menimpa BuildRows
untuk mengontrol baris yang ditunjukkan, dan BuildRoot
hanya digunakan untuk membuat akar TreeViewItem
. Pendekatan ini meningkatkan yang terbaik dengan set data besar atau data yang sering berubah.
Gunakan pendekatan pertama untuk set data kecil, atau untuk data yang tidak berubah sering. Gunakan pendekatan kedua untuk set data besar, atau data yang berubah sering, karena lebih cepat untuk hanya membuat item yang diperluas daripada pohon penuh.
Ada tiga cara Anda dapat mengatur TreeViewItems:
Buat TreeViewItem
s dengan anak-anak, orang tua, dan kedalaman diinisialisasi dari awal.
Buat TreeViewItem
s dengan orang tua dan anak-anak kemudian gunakan SetupDepthsFromParentsAndChildren untuk mengatur kedalaman.
Buat TreeViewItem
s hanya dengan informasi mendalam dan kemudian gunakan SetupDepthsFromParentsAndChildren untuk mengatur referensi induk dan anak-anak.
Untuk melihat Proyek dan kode sumber untuk contoh yang ditunjukkan di bawah ini, unduh.
Untuk membuat TreeView, buat kelas yang memperpanjang kelas TreeView
dan menerapkan metode abstrak BuildRoot
. Contoh berikut membuat TreeView sederhana.
class SimpleTreeView : TreeView
{
public SimpleTreeView(TreeViewState treeViewState)
: base(treeViewState)
{
Reload();
}
protected override TreeViewItem BuildRoot ()
{
// BuildRoot is called every time Reload is called to ensure that TreeViewItems
// are created from data. Here we create a fixed set of items. In a real world example,
// a data model should be passed into the TreeView and the items created from the model.
// This section illustrates that IDs should be unique. The root item is required to
// have a depth of -1, and the rest of the items increment from that.
var root = new TreeViewItem {id = 0, depth = -1, displayName = "Root"};
var allItems = new List<TreeViewItem>
{
new TreeViewItem {id = 1, depth = 0, displayName = "Animals"},
new TreeViewItem {id = 2, depth = 1, displayName = "Mammals"},
new TreeViewItem {id = 3, depth = 2, displayName = "Tiger"},
new TreeViewItem {id = 4, depth = 2, displayName = "Elephant"},
new TreeViewItem {id = 5, depth = 2, displayName = "Okapi"},
new TreeViewItem {id = 6, depth = 2, displayName = "Armadillo"},
new TreeViewItem {id = 7, depth = 1, displayName = "Reptiles"},
new TreeViewItem {id = 8, depth = 2, displayName = "Crocodile"},
new TreeViewItem {id = 9, depth = 2, displayName = "Lizard"},
};
// Utility method that initializes the TreeViewItem.children and .parent for all items.
SetupParentsAndChildrenFromDepths (root, allItems);
// Return root of the tree
return root;
}
}
Dalam contoh ini, informasi kedalaman digunakan untuk membangun TreeView. Akhirnya, panggilan ke SetupDepthsFromParentsAndChildren
menetapkan data induk dan anak-anak dari TreeViewItem
s.
Catatan bahwa ada dua cara untuk mengatur TreeViewItem
: Mengatur orang tua dan anak-anak langsung, atau gunakan metode AddChild
, seperti yang ditunjukkan dalam contoh berikut:
protected override TreeViewItem BuildRoot()
{
var root = new TreeViewItem { id = 0, depth = -1, displayName = "Root" };
var animals = new TreeViewItem { id = 1, displayName = "Animals" };
var mammals = new TreeViewItem { id = 2, displayName = "Mammals" };
var tiger = new TreeViewItem { id = 3, displayName = "Tiger" };
var elephant = new TreeViewItem { id = 4, displayName = "Elephant" };
var okapi = new TreeViewItem { id = 5, displayName = "Okapi" };
var armadillo = new TreeViewItem { id = 6, displayName = "Armadillo" };
var reptiles = new TreeViewItem { id = 7, displayName = "Reptiles" };
var croco = new TreeViewItem { id = 8, displayName = "Crocodile" };
var lizard = new TreeViewItem { id = 9, displayName = "Lizard" };
root.AddChild(animals);
animals.AddChild(mammals);
animals.AddChild(reptiles);
mammals.AddChild(tiger);
mammals.AddChild(elephant);
mammals.AddChild(okapi);
mammals.AddChild(armadillo);
reptiles.AddChild(croco);
reptiles.AddChild(lizard);
SetupDepthsFromParentsAndChildren(root);
return root;
}
BuildRoot
untuk kelas SimpleTreeView
di atasContoh berikut menunjukkan EditorWindow
yang mengandung SimpleTreeView
. TreeViews dibangun dengan instance TreeViewState
. Pengelola TreeView harus menentukan bagaimana keadaan pandangan ini harus ditangani: apakah keadaannya harus bertahan sampai sesi Unity berikutnya, atau apakah itu hanya harus melestarikan keadaannya setelah skrip diisi ulang (baik ketika memasuki mode Play atau skrip rekompiling). Dalam contoh ini, TreeViewState
di serialisasi dalam EditorWindow
, memastikan TreeView melestarikan keadaannya ketika Editor ditutup dan dibuka kembali.
using System.Collections.Generic;
using UnityEngine;
using UnityEditor.IMGUI.Controls;
class SimpleTreeViewWindow : EditorWindow
{
// SerializeField is used to ensure the view state is written to the window
// layout file. This means that the state survives restarting Unity as long as the window
// is not closed. If the attribute is omitted then the state is still serialized/deserialized.
[SerializeField] TreeViewState m_TreeViewState;
//The TreeView is not serializable, so it should be reconstructed from the tree data.
SimpleTreeView m_SimpleTreeView;
void OnEnable ()
{
// Check whether there is already a serialized view state (state
// that survived assembly reloading)
if (m_TreeViewState == null)
m_TreeViewState = new TreeViewState ();
m_SimpleTreeView = new SimpleTreeView(m_TreeViewState);
}
void OnGUI ()
{
m_SimpleTreeView.OnGUI(new Rect(0, 0, position.width, position.height));
}
// Add menu named "My Window" to the Window menu
[MenuItem ("TreeView Examples/Simple Tree Window")]
static void ShowWindow ()
{
// Get existing open window or if none, make a new one:
var window = GetWindow<SimpleTreeViewWindow> ();
window.titleContent = new GUIContent ("My Window");
window.Show ();
}
}
Contoh ini menggambarkan TreeView multi-kolom yang menggunakan kelas MultiColumnHeader.
MultiColumnHeader
mendukung fungsi berikut: item renaming, multi-selection, item pemesanan dan konten baris kustom menggunakan kontrol IMGUI normal (seperti slider dan bidang objek), penyortiran kolom, dan penyaringan dan pencarian baris.
Contoh ini menciptakan model data menggunakan kelas TreeElement
dan TreeModel
. PohonView mengambil data dari "TreeModel". Dalam contoh ini, kelas TreeElement
dan TreeModel
telah dibangun untuk menunjukkan fitur kelas TreeView. Kelas-kelas ini telah dimasukkan dalam Proyek Contoh TreeView (). Contoh ini juga menunjukkan bagaimana struktur model pohon serialisasi ke Login Sitemap dan disimpan dalam Aset.
[Serializable]
//The TreeElement data class is extended to hold extra data, which you can show and edit in the front-end TreeView.
internal class MyTreeElement : TreeElement
{
public float floatValue1, floatValue2, floatValue3;
public Material material;
public string text = "";
public bool enabled = true;
public MyTreeElement (string name, int depth, int id) : base (name, depth, id)
{
floatValue1 = Random.value;
floatValue2 = Random.value;
floatValue3 = Random.value;
}
}
Kelas ScriptableObject berikut memastikan bahwa data tetap dalam Aset ketika pohon serial.
[CreateAssetMenu (fileName = "TreeDataAsset", menuName = "Tree Asset", order = 1)]
public class MyTreeAsset : ScriptableObject
{
[SerializeField] List<MyTreeElement> m_TreeElements = new List<MyTreeElement> ();
internal List<MyTreeElement> treeElements
{
get { return m_TreeElements; }
set { m_TreeElements = value; }
}
}
Contoh berikut menunjukkan cuplikan kelas MultiColumnTreeView
, yang menggambarkan bagaimana kolom multi GUI dicapai. Temukan kode sumber penuh di Proyek Contoh TreeView ().
public MultiColumnTreeView (TreeViewState state,
MultiColumnHeader multicolumnHeader,
TreeModel<MyTreeElement> model)
: base (state, multicolumnHeader, model)
{
// Custom setup
rowHeight = 20;
columnIndexForTreeFoldouts = 2;
showAlternatingRowBackgrounds = true;
showBorder = true;
customFoldoutYOffset = (kRowHeights - EditorGUIUtility.singleLineHeight) * 0.5f;
extraSpaceBeforeIconAndLabel = kToggleWidth;
multicolumnHeader.sortingChanged += OnSortingChanged;
Reload();
}
Perubahan kustom dalam sampel kode di atas membuat penyesuaian berikut:
rowHeight = 20
: Mengubah ketinggian default (yang didasarkan pada titik 16 EditorGUIUtility.singleLineHeight) ke 20, untuk menambahkan lebih banyak ruang untuk kontrol GUI.
columnIndexForTreeFoldouts = 2
: Dalam contoh, panah lipat ditampilkan di kolom ketiga karena nilai ini ditetapkan ke 2 (lihat gambar di atas). Jika nilai ini tidak berubah, lipatan diberikan di kolom pertama, karena “columnIndexForTreeFoldouts” adalah 0 secara default.
showAlternatingRowBackgrounds = true
: Mengubah warna latar belakang baris, sehingga setiap baris berbeda.
showBorder = true
: Mengirimkan TreeView dengan margin di sekitarnya, sehingga batas tipis ditunjukkan untuk menentukannya dari sisa konten
customFoldoutYOffset = (kRowHeights - EditorGUIUtility.singleLineHeight) * 0.5f
: Pusat lipatan vertikal di baris - lihat Kustomisasi GUI di bawah ini.
extraSpaceBeforeIconAndLabel = 20
: Membuat ruang sebelum label pohon sehingga tombol toggle ditunjukkan.
multicolumnHeader.sortingChanged += OnSortingChanged
: Menetapkan metode untuk acara untuk mendeteksi ketika mengurutkan perubahan dalam komponen header (ketika kolom header diklik), sehingga baris dari perubahan TreeView untuk mencerminkan keadaan penyortiran.
Jika penanganan RowGUI default digunakan, TreeView terlihat seperti contoh SimpleTreeView
di atas, hanya dengan lipatan dan label. Ketika menggunakan beberapa nilai data untuk setiap item, Anda harus menimpa metode RowGUI untuk memvisualisasikan nilai-nilai ini.
protected override void RowGUI (RowGUIArgs args)
Sampel kode berikut adalah struktur argumen dari struct RowGUIArgs
.
protected struct RowGUIArgs
{
public TreeViewItem item;
public string label;
public Rect rowRect;
public int row;
public bool selected;
public bool focused;
public bool isRenaming;
public int GetNumVisibleColumns ()
public int GetColumn (int visibleColumnIndex)
public Rect GetCellRect (int visibleColumnIndex)
}
Anda dapat memperpanjang TreeViewItem
dan menambahkan data pengguna tambahan (yang membuat kelas yang berasal dari TreeViewItem
). Anda kemudian dapat menggunakan data pengguna ini di callback RowGUI. Contoh ini disediakan di bawah ini. Lihat override void RowGUI
- contoh ini melemparkan item input ke TreeViewItem<MyTreeElement>
.
Ada tiga metode yang terkait dengan penanganan kolom: GetNumVisibleColumns, GetColumn, dan GetCellRect. Anda hanya dapat memanggil ini ketika TreeView dibangun dengan MultiColumnHeader, jika tidak terkecuali dibuang.
protected override void RowGUI (RowGUIArgs args)
{
var item = (TreeViewItem<MyTreeElement>) args.item;
for (int i = 0; i < args.GetNumVisibleColumns (); ++i)
{
CellGUI(args.GetCellRect(i), item, (MyColumns)args.GetColumn(i), ref args);
}
}
void CellGUI (Rect cellRect, TreeViewItem<MyTreeElement> item, MyColumns column, ref RowGUIArgs args)
{
// Center the cell rect vertically using EditorGUIUtility.singleLineHeight.
// This makes it easier to place controls and icons in the cells.
CenterRectUsingSingleLineHeight(ref cellRect);
switch (column)
{
case MyColumns.Icon1:
// Draw custom texture
GUI.DrawTexture(cellRect, s_TestIcons[GetIcon1Index(item)], ScaleMode.ScaleToFit);
break;
case MyColumns.Icon2:
//Draw custom texture
GUI.DrawTexture(cellRect, s_TestIcons[GetIcon2Index(item)], ScaleMode.ScaleToFit);
break;
case MyColumns.Name:
// Make a toggle button to the left of the label text
Rect toggleRect = cellRect;
toggleRect.x += GetContentIndent(item);
toggleRect.width = kToggleWidth;
if (toggleRect.xMax < cellRect.xMax)
item.data.enabled = EditorGUI.Toggle(toggleRect, item.data.enabled);
// Default icon and label
args.rowRect = cellRect;
base.RowGUI(args);
break;
case MyColumns.Value1:
// Show a Slider control for value 1
item.data.floatValue1 = EditorGUI.Slider(cellRect, GUIContent.none, item.data.floatValue1, 0f, 1f);
break;
case MyColumns.Value2:
// Show an ObjectField for materials
item.data.material = (Material)EditorGUI.ObjectField(cellRect, GUIContent.none, item.data.material,
typeof(Material), false);
break;
case MyColumns.Value3:
// Show a TextField for the data text string
item.data.text = GUI.TextField(cellRect, item.data.text);
break;
}
}
Q: In my TreeView subclass, I have the functions BuildRoot and RowGUI. Is RowGUI
called for every TreeViewItem
that got added in the build function, or only for items that are visible on screen in the scroll view?
A: RowGUI
hanya disebut untuk item yang terlihat pada layar. Misalnya, jika Anda memiliki 10.000 item, hanya 20 item yang terlihat di layar memiliki RowGUI
mereka yang disebut.
Q: Can I get the indices of the rows that are visible on the screen?
Sitemap Gunakan metode GetFirstAndLastVisibleRows.
Q: Can I get the list of rows that are built in BuildRows?
Sitemap Gunakan metode GetRows.
Q: Is it mandatory for any of the overridden functions to call base.Method
?
A: Hanya jika metode memiliki perilaku default yang ingin Anda perpanjangkan.
Q: I just want to make list of items (not a tree). Do I have to create the root?
A: Ya, Anda harus selalu memiliki akar. Anda dapat membuat item akar dan mengatur root.children = rows
untuk setup cepat.
Q: I’ve added a Toggle to my row - why doesn’t the selection jump to that row when I click on it?
A: Secara default, baris hanya dipilih jika mouse turun tidak dikonsumsi oleh isi baris. Di sini, Toggle Anda mengkonsumsi acara. Untuk memperbaiki ini, gunakan metode SelectionClick sebelum tombol Toggle Anda disebut.
Q: Are there methods I can use before or after all RowGUI
methods are called?
Sitemap Lihat dokumentasi API pada BeforeRowsGUI dan AfterRowsGUI.
Q: Is there a simple way to return key focus to the TreeView from API? If I select a FloatField in my row, the row selection becomes gray. How do I make it blue again?
A: Warna biru menunjukkan baris yang saat ini memiliki fokus utama. Karena FloatField memiliki fokus, TreeView kehilangan fokus, sehingga ini adalah perilaku yang dimaksudkan. Set GUIUtility.keyboardControl = treeViewControlID
bila diperlukan.
Q: How do I convert from id
to a TreeViewItem
?
A: Gunakan FindItem atau FindRows.
Q: How do I receive a callback when a user changes their selection in the TreeView?
A: Override metode SelectionChanged (pont berguna lainnya: Sitemap Artikel, dan Login Artikel).