Опубликован: 25.03.2010 | Уровень: для всех | Доступ: платный
Лекция 15:

Стандартные элементы управления

Спроектируем более совершенную версию программы для той же задачи построения дерева каталогов. Чтобы все было красиво, нужно извлечь иконки для соответствующих узлов из архива библиотеки VS2005ImageLibrary.zip, поставляемой в составе Visual Studio 2005.


Можно взять упомянутые иконки и из каталога Source данной работы.

Для включения значков в ресурс проекта, чтобы при компиляции они были внедрены в исполнимую сборку exe, нужно сделать следующее:

  • В панели Solution Explorer на корневом узле проекта вызвать контекстное меню и командой Add/New Folder добавить в проект каталог Resource (или с любым другим именем)
  • В панели Solution Explorer на добавленной папке вызвать контекстное меню и командой Add/Add Existing Item добавить в нее следующие файлы иконок
    1. 35FLOPPY.ICO
    2. CDDRIVE.ICO
    3. CLSDFOLD.ICO
    4. DRIVENET.ICO
    5. OPENFOLD.ICO
  • В панели Solution Explorer выделить добавленные иконки и через панель Properties установить для них свойство Build Action в значение Embedded Resource (внедренный ресурс). Теперь иконки будут храниться в exe -файле, который можно перемещать без них куда угодно

Можно таким же образом внедрить в сборку иконку самой формы приложения (например, " 1.ICO " в каталоге Source )

Окончательный код усовершенствованной программы просмотра дерева каталогов будет таким

using System;
using System.Drawing;
using System.Windows.Forms;
// Пространство имен для работы с каталогами
using System.IO;
    
namespace Test
{
    // Пользовательский класс построения дерева каталогов
    // как расширение библиотечного класса TreeView
    class DirectoryTreeView : TreeView
    {
        public DirectoryTreeView()  // Конструктор
        {
            // Создаем список иконок из внедренного ресурса
            ImageList imageList = new ImageList();
            // Порядок соблюдать - от него зависят индексы списка
            imageList.Images.Add(new Icon(GetType(), 
                "Resource.CLSDFOLD.ICO"));  //0 - свернут
            imageList.Images.Add(new Icon(GetType(), 
                "Resource.OPENFOLD.ICO"));  //1 - развернут
            imageList.Images.Add(new Icon(GetType(), 
                "Resource.35FLOPPY.ICO"));  //2 - гибкий диск
            imageList.Images.Add(new Icon(GetType(), 
                "Resource.CDDRIVE.ICO"));   //3 - жесткий диск
            imageList.Images.Add(new Icon(GetType(), 
                "Resource.DRIVENET.ICO"));  //4 - папки
    
            // Используем наследуемые от TreeView свойства
            // Присоединяем список к свойству ImageList элемента TreeView
            this.ImageList = imageList;
            // В дереве в каждый момент времени может быть выделен только один узел
            this.ImageIndex = 0;        // Когда узел просто отображен (Collapsed)
            this.SelectedImageIndex = 1;// Когда узел выделен (Open)
    
            // Сканируем логические диски компьютера
            DriveInfo[] drives = DriveInfo.GetDrives(); // Статический метод
    
            // Строим дерево просмотра логических дисков и каталогов
            TreeNode selectedNode = null;
            foreach (DriveInfo drive in drives)
            {
            // Создаем очередной корневой узел для диска
            TreeNode nodeDrive = new TreeNode(drive.RootDirectory.Name);
            if (drive.RootDirectory.Name == @"C:\")
                    selectedNode = nodeDrive;
    
            // Назначаем узлу пиктограмму в зависимости от типа диска
            // Одинаковые изображения для свернутого и развернутого состояний
            if (drive.DriveType == DriveType.Removable)
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 2;
            else if (drive.DriveType == DriveType.CDRom)
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 3;
            else
                    nodeDrive.ImageIndex = nodeDrive.SelectedImageIndex = 4;
    
            // Добавляем узел диска в унаследованный TreeView
            this.Nodes.Add(nodeDrive);
            // Добавляем к корневому узлу подкаталоги ближайшего слоя
            // с помощью нашей теперь уже нерекурсивной функции
            AddDirectories(nodeDrive);
            }
    
            if (selectedNode != null)
                this.SelectedNode = selectedNode;
        }
    
        // Нерекурсивная функция добавления узлов подкаталогов
        void AddDirectories(TreeNode node)
        {
        node.Nodes.Clear(); // Очищаем коллекцию узлов на случай повторного
                            // раскрытия уже ранее раскрытого и сформированного узла
    
         // Формируем полный путь для текущего каталога (узла)
         DirectoryInfo dirInfo = new DirectoryInfo(node.FullPath);
         // Объявляем ссылку на массив подкаталогов
         DirectoryInfo[] arrayDirInfo;
    
         // Если есть подкаталоги - безопасный код
         try
         {
         arrayDirInfo = dirInfo.GetDirectories();
         }
         catch
         {
         // Подкаталогов нет - выходим
         return;
         }
    
         // Добавляем к текущему узлу дочерний узел для каждого каталога
         foreach (DirectoryInfo dir in arrayDirInfo)
                node.Nodes.Add(new TreeNode(dir.Name));
        }
    
        // Переопределяем обработчик базового класса TreeView,
        // который срабатывает перед раскрытием пользователем
        // текущего узла, формируя ближайший слой дочерних узлов налету
        protected override void OnBeforeExpand(TreeViewCancelEventArgs args)
        {
            base.OnBeforeExpand(args);
    
            this.BeginUpdate(); // Замораживаем перерисовку дерева
    
            // Быстренько создаем ближайший слой подузлов для каждого
            // подузла раскрываемого узла, чтобы отображались
            // значки + на узлах слоя после раскрытия текущего
            foreach (TreeNode node in args.Node.Nodes)
                AddDirectories(node);
    
            this.EndUpdate();   // Освобождаем перерисовку дерева
        }
    }
    
    // Класс приложения
    class MyClass : Form
    {
        public MyClass()    // Конструктор
        {
            this.Text = "Улучшенное дерево каталогов";
            this.FormBorderStyle = FormBorderStyle.FixedSingle;
            // Замыкаем размеры
            this.MaximizeBox = false;
            this.StartPosition = FormStartPosition.CenterScreen;
            this.Width += this.Width / 3;   // Чуток расширили форму
            // Внедряем в сборку ресурс иконки формы
            this.Icon = new Icon(GetType(), "Resource.1.ICO");
    
            // Создаем экземпляр пользовательского класса дерева
            DirectoryTreeView myTree = new DirectoryTreeView();
            // Привязываем к форме
            myTree.Parent = this;
            // Разварачиваем на всю форму
            myTree.Dock = DockStyle.Fill;
        }
    }
    
    // Запуск
    class Program
    {
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.Run(new MyClass());
        }
    }
}
Листинг 15.8 . Усовершенствованная версия программы просмотра дерева каталогов

В старой программе с помощью рекурсивной функции, вызов которой был помещен в конструктор формы, мы вначале сканировали все дерево каталогов компьютера и тратили на это значительное время. Это существенно задерживало появление окна приложения при его запуске. В усовершенствованной программе в дереве просмотра для каждого раскрытого узла хранятся только два ближайших слоя дочерних узлов. При раскрытии пользователем очередного узла вначале срабатывает обработчик, которому передается коллекция дочерних узлов раскрываемого узла. В обработчике для каждого узла готовой раскрыться коллекции на лету создается новый слой дочерних узлов, готовых для раскрытия.

В новой программе мы всю работу разделили на этапы. Вначале создается два слоя - слой устройств и ближайший слой подчиненных им каталогов. При раскрытии узла устройства перед отображением уже вычисленного дочернего слоя вычисляется следующий в глубину слой для каждого дочернего узла, готовый для отображения при далнейшем раскрытии. Таким образом, при очередном шаге в глубину дерева вычисляется только один новый дочерний слой. Для пользователя эта задержка не очень заметна.

Вот внешний вид результата выполнения улучшенной версии программы чтения дерева каталогов


Максим Филатов
Максим Филатов

Прошел курс. Получил код Dreamspark. Ввожу код на сайте, пишет:

Срок действия этого кода проверки уже истек. Проверьте, правильно ли введен код. У вас осталось две попытки. Вы также можете выбрать другой способ проверки или предоставить соответствующие документы, подтверждающие ваш академический статус.

 

Как активировать код?

Денис Пашков
Денис Пашков
Россия
Татьяна Ковалюк
Татьяна Ковалюк
Украина, Киев, Киевский политехнический институт, 1974