====== Strom se soubory ====== Na záložce **Files** zobrazíme jednotlivé disky a jejich adresáře a soubory. \\ Kliknutím na některé soubory zobrazíme odpovídající panel {{diagram_tree.png}} Podadresáře budeme načítat průběžně podle toho, které adresáře si uživatel bude prohlížet. Aby byly vidět značky naznačující, že prvek stromu má v sobě schované další větve, \\ načteme do stromu o úroveň (o patro) prvků více než uživatel dosud navštívil. ==== Třída FileNode ==== Rozšíříme standardní třídu **TreeNode** o proměnnou **path** skladující kompletní cestu k souboru, \\ a proměnou **ready** obsahující příznak, zda byly nacteny i podadresáře daného uzlu. class FileNode : TreeNode { public string path; public bool ready = false; // true ... podadresare jiz nacteny } ==== Jednotlivé disky ===== Metoda **displayDrives** * Vymažeme původní obsah stromu * Statická funkce **GetDrives** ve třídě **DriveInfo** nám poskytne pole informací o jednotlivých discích ( C:, D:, ... ) * V cyklu projedeme pole disků * Pro jednotlivé disky zavoláme metodu **displayDirectory** * první parametr bude podobjekt **Nodes** ve stromu, tím budeme přidávat disky jako větve stromu na nejvyšší úrovni * druhým parametrem bude informace o kořenovém adresáři disku private void displayDrives () { fileTree.Nodes.Clear (); DriveInfo[] roots = DriveInfo.GetDrives (); foreach (DriveInfo r in roots) displayDirectory (fileTree.Nodes, r.RootDirectory); } ==== Zobrazení adresáře souborů ve stromu ==== Metoda **displayDirectory** * má za první parametr objekt typpu "kolekce" uzlů, do které budeme přidávat nový uzel * druhý parametr typu **DirectoryInfo** poskytne informace o adres85i na disku * parametr **level** určuje kolik pater do stromu přidáme * Vytvoříme nový uzel našeho typu **FileNode** * do **node.path** uložíme cestu k adresáři * **node.ready** nastavíme na //false//, podadresáře ještě nejsou načteny * v **node.Text** bude text zobrazovaný v daném uzlu, uložíme tam jen krátké jméno adresáře bez nadřazených adresářů * do **ToolTipText**, textu v malém obdélníčku (pokud se na chilku zastavíme s myší), bude úplná cesta k adresáři * **ForeColor** určuje barvu textu * **target.Add (node);** přidá nový uzel do příslušného místa stromu * metoda **displayDetail**, popsaná dále, doplní pod nový uzel další adresáře a soubory private void displayDirectory (TreeNodeCollection target, DirectoryInfo dir, int levels = 2) { FileNode node = new FileNode (); node.path = dir.FullName; node.ready = false; node.Text = dir.Name; node.ToolTipText = node.path; node.ForeColor = Color.Blue; target.Add (node); displayDetail (node, dir, levels); } ==== Zobrazení souboru ve stromu ==== Metoda **displayFile** obdoně zobrazí informace o jednom souboru. Standardní třida **FileInfo** také může poskytnout informace o délce a datumu souboru private void displayFile (TreeNodeCollection target, FileInfo f) { FileNode node = new FileNode (); node.path = f.FullName; node.ready = true; node.Text = f.Name; node.ToolTipText = node.path; node.ForeColor = Color.Orange; target.Add (node); } ==== Soubory a podadresáře ===== Metoda **displayDetail** * dostane jako parametr již existující uzel stromu **node** * a v tomto uzlu je již zobrazeno jméno adresáře **dir** * poslední parametr určuje kolik pater je ještě potřeba zobrazit * Pokud je **level** větší než jedna, budeme pokračovat * Blok **try** ... **catch** má zachytit výjimky, například nedovolený přístup do adresáře nebo disk bez CD/DVD média * **dir.GetFiles ()** poskytne pole s popisy jednotlivý souborů, zavoláme pro ně metodu **displayFile** * **dir.GetDirectories ()** zjistí seznam podadresářů, funkci **displayDirectory** zavoláme pro počet pater o zmenšený o jedna * Pokud vznikne výjimka * informace o výjimce budou v proměnné **e** typu **Exception** * vytvoříme uzel stromu (jen typu //TreNode// nikoliv //FileNode//) * jako //Text// přidáme zprávu o výjimce **e.ToString ()** * v plovoucím obdélníčku zobrazíme seznam právě prováděných funkcí **e.ToString ()** * text obarvíme na červeno a přídáme do stromu private void displayDetail (FileNode node, DirectoryInfo dir, int levels) { if (levels > 1) try { foreach (FileInfo f in dir.GetFiles ()) displayFile (node.Nodes, f); foreach (DirectoryInfo d in dir.GetDirectories ()) displayDirectory (node.Nodes, d, levels - 1); node.ready = true; } catch (Exception e) { TreeNode t = new TreeNode (); t.Text = e.ToString (); t.ToolTipText = e.StackTrace; t.ForeColor = Color.Red; node.Nodes.Add (t); } } {{diagram_exception.png}} ==== Rozvinutí větve představující adresář ==== Pokud uživatel "rozklikne" v2tev stromu, dřive než uvidí výsledek, tak proběhne **treeView_BeforeExpand** V parametru **e** se skrývá odkaz na otvíranou větev **e.Node**, \ ta by již měla být dobře zobrazena, my se podíváme na dosud skryté pod poduzly **e.Node.Nodes**. Poduzly přetypujeme na //FileNode// FileNode node = n as FileNode; pokud by **n** bylo jen //TreeNode// (např. červená zpráva o chybě), bude **node** rovno **null**. Pro jednotlivé poduzly nám standardní třída //DirectoryInfo//poskytne informace o adresáři na disku **new DirectoryInfo (node.path)**\\ Pokud by při tom vznikla výjimka, přidáme //try ... catch// DirectoryInfo dir = new DirectoryInfo (node.path); Nakonec funkce displayDetail přidá do stromu vnořené adresáře a soubory private void treeView_BeforeExpand (object sender, TreeViewCancelEventArgs e) { foreach (TreeNode n in e.Node.Nodes) { FileNode node = n as FileNode; if (node != null && !node.ready) { try { DirectoryInfo dir = new DirectoryInfo (node.path); displayDetail (node, dir, 2); } catch (Exception ex) { } } } } ==== Výběr souboru ve stromu ==== Při dvojitém kliknutí do stromu pomocí **FileInfo** získáme příponu souboru a pro některé přípony zobrazíme panel private void fileTree_DoubleClick (object sender, EventArgs e) { TreeNode node = fileTree.SelectedNode as TreeNode; if (node != null) { string path = node.FullPath; FileInfo f = new FileInfo (path); string ext = f.Extension; statusLabel.Text = path + ", " + ext; switch (ext) { case ".txt": case ".bat": case ".ini": case ".cs": case ".c": case ".cpp": case ".cc": case ".h": case ".hpp": displayText (path); break; case ".png": case ".bmp": case ".jpg": case ".jpeg": displayImage (path); break; case ".csv": displayTable (path); break; case ".chart": displayChart (path); break; case ".html": displayHtml (path); break; } } } Funkce **displayText** vytvoří nový panel **TextArea** a zavolá dále popsanou funkci **displayObject** public void displayText (string path) { TextArea a = new TextArea (path); displayObject (a); } public void displayImage (string path) { ImageArea a = new ImageArea (path); displayObject (a); } public void displayTable (string path) { TableArea a = new TableArea (path); displayObject (a); } public void displayChart (string path) { ChartArea a = new ChartArea (path); displayObject (a); } public void displayHtml (string path) { HtmlArea a = new HtmlArea (path); displayObject (a); } ==== Zobrazení nového panelu (nebo jiného objektu) ==== Na záložku **Tree** přidáme informace o novém objektu * jako text ve stromu použijeme standardní konverzi **obj.ToString ()**, kterou používá i sčítání řetězců znaků * do standardní položky **node.Tag** typu **object** schováme ukazatel na objekt Pokud je objekt typu **Control** nebo třídy z //Control// odvozené, \\ umístíme objekt nad **pictureBox**. **BringToFront** umístí objekt nad jiné plouvoucí panely, aby byl vidět public void displayObject (object obj) { TreeNode node = new TreeNode (); node.Text = obj.ToString (); node.Tag = obj; tree.Nodes.Add (node); if (obj is Control) { Control c = obj as Control; c.Parent = pictureBox; c.BringToFront (); } } ==== Kliknutí do stromu na záložce Tree ==== * Z uzlu stromu z položky **Tag** vyzvedneme ukazatel na objekt * //PropertyGrid// na pravé straně okna zobrazí jednotlivé vlastnosti objektu * Pokud je náš objekt plovoucím objektem nad původním obrázkem, umístíme objekt nad jiné objekty private void tree_AfterSelect (object sender, TreeViewEventArgs e) { object obj = e.Node.Tag; propGrid.SelectedObject = obj; if (obj is Control) { Control c = obj as Control; c.BringToFront (); } } [[https://gitlab.fjfi.cvut.cz/culikzde/pw/-/tree/master/Diagram|gitlab]] [[http://kmlinux.fjfi.cvut.cz/~culikzde/pw/Diagram2020.zip|zip]]