Создаем простейший файловый менеджер в Delphi

В первых двух строках кода создаются списки маленьких и больших иконок. Свойства Largelmages и Smalllmages имеют тип TimageList, НО сразу ПОСЛе создания компонента они равны nil. Поэтому они создаются, присваивая результат вызова TimageList. create (self). Когда они проинициализированы, необходимая память будет выделена.

 

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

 

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

 

В дальнейшем мы запрашиваем у системы список больших иконок. Для этого используется функция SHGetFileinfo, которая возвращает информацию о файле, папке или диске. Первый параметр — путь к файлу. Второй — атрибуты. Третий — указатель на tshfileinfo. Четвертый— размер tshfileinfo. Последний пара­метр — это флаги, указывающие на тип информации, запрашиваемой у системы.

 

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

 

В качестве флагов указывается shgfi_sysiconindex и shgfi_largeicon. shgfi_jsysiconindex означает, что нужно вернуть указатель на системный список иконок (imageList). Второй флаг говорит, что нужны большие иконки.

 

При втором вызове этой функции (чуть ниже в коде) мы запрашиваем маленькие иконки (shgfi__smallicon). Функция возвращает указатель на соответствующий системе SysImageList, КОТОрЫЙ МЫ впоследствии присваиваем ListViewl.Largelmages.Handle. После этого присваивания ListViewl.Largelmages содержит все системные иконки раз­мера 32x32. Почему? Потому что свойство Handle— это указатель на выделенную для картинок память. Этот указатель мы изменили на тот, который получили из системы, и теперь наш список картинок указывает на системный.

Системный список иконок (imageList) содержит все иконки, установленные в системе и ассоциированные с разными типами файлов. Эти иконки вы можете видеть в проводнике (Windows Explorer) у файлов doc, txt, ini, zip и др.

На следующем этапе разработки программы создадим обработчик события onshow. В нем вызовем процедуру AddFile, которая считывает все файлы из теку­щей папки:

AddFile('С:/*.*',faAnyFile);

Процедуру AddFile нужно объявить в разделе private нашей формы Forml сле­дующим образом:

 

Объявите эту процедуру так же, а потом нажмите комбинацию клавиш <Ctrl>+<Shift>+<C>, и Delphi создаст заготовку для будущей процедуры. В эту за­готовку напишите содержимое листинга:

 

Процедура получилась достаточно большая и надо подробно'ее рассмотреть. Делать это будем по частям программного кода, чтобы было легче воспринимать объяснения.

 

После имени процедуры идет объявление локальных переменных. Это все по­нятно, и мы не раз уже такое делали. Но после объявления переменных вместо на­чала процедуры begin стоит объявление другой локальной функции:

 

Конечно же, эту функцию можно написать как полноценную, но в данном слу­чае мы закрепляем на практике локальные процедуры. Этот код будет нужен толь­ко внутри функции AddFile и больше нигде, а значит, нет смысла выделять отдель­ную функцию.

 

Если одна процедура или функция (внутренняя) объявлена внутри другой (внешней), то внутренняя процедура может быть вызвана только из внешней. Весь остальной код программы не будет знать о существовании где-то внутренней про­цедуры.

 

ПРИМЕЧАНИЕ. В примере сложилась ситуация, когда используется внутренняя про­цедура. Это сделано искусственно, потому что вы можете встретить такую конструк­цию в других программах. Однако многие программисты стараются не использовать такой прием, потому что трудно найти случай, когда внутренняя процедура действи­тельно необходима. По этой причине обходятся без нее.

После объявления и описания внутренней процедуры идет начало внешней про­цедуры. Вот тут начинается самое интересное. В самом начале вызываются два ме­тода компонента

 

Первый метод BeginUpdate говорит о том, что начинается обновление элемен­тов списка. После этого вызова никакие изменения, вносимые в элементы, не будут отражаться на экране, пока не будет вызван Endupdate.

 

Когда вы хотите произвести незначительное изменение, то не надо вызывать эти методы, но когда предполагается, что элементы списка будут изменяться очень сильно, то лучше все изменения заключить между вызовами BeginUpdate и Endupdate. Это связано с тем, что когда вы вносите хоть какое-то изменение, оно сразу отображается на экране. Логично? А что если вам нужно удалить все элемен­ты и потом в цикле добавить в список 1000 новых элементов. В этом случае после удаления и каждого добавления нового элемента будет происходить прорисовка компонента. Вот тут и возникает вопрос: "Зачем после каждого добавления рисо­вать?".

 

В этом случае намного эффективнее будет добавить все элементы, а только потом их прорисовать, причем все сразу. Вот именно для этого и существуют свое­образные операторные скобки BeginUpdate И Endupdate:

 

После вызова BeginUpdate производится очистка текущего списка элементов С ПОМОЩЬЮ вызова ListViewl. Items .Clear.

 

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

 

FindFirst — открывает поиск. В качестве первого параметра выступает маска поиска. Если вы укажете конкретный файл, то система найдет его. Второй пара­метр— атрибуты включаемых в поиск файлов. Здесь мы используем faAnyFile, чтобы искать любые файлы. Последний параметр — это структура, в которой нам вернется информация о поиске, а именно: имя найденного файла, размер, время создания и т. д.

 

После вызова FindFirst мы проверяем корректность найденного файла. Если все в норме, то запускается цикл Repeat - until. Этот цикл выполняет операторы, располо­женные между repeat и until, пока условие, расположенное после слова until, явля­ется верным (имеет значение true). Как только условие нарушается, цикл прерывается.

ПРИМЕЧАНИЕ. Цикл until похож на while, но с одним отличием. Если в while условие заведомо неверно, то операторы внутри цикла не выполнятся. В repeat - until выполнятся, потому что сначала происходит выполнение операто­ров, а лишь затем проверка until.

Напоминаю, что функция поиска может возвращать в качестве найденного име­ни в структуре SearchRec (параметр Name) точку или две точки. Если встречаются такие имена, то их просто отбрасывают.

Далее идет вызов функции SlashSep:

FileName := SlashSep(Editl.Text, SearchRec.Name);

Эта функция и FileTimeToDateTimestr будут написаны позже и объявлены в разделе var после объявления объекта:

 

Здесь функция SlashSep объявлена не внутри объекта, значит, она никому не принадлежит.

 

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

В этом примере объявлена самостоятельная процедура Examp и метод объекта Forml— Examp2. Из метода Ехатр2 мы вызываем самостоятельную процедуру ехатр. Этот код правильный, потому что процедура сначала реализуется, а потом уже используется.

А теперь посмотрите на неправильный код, который показан в листинге: 

 

В этом примере происходит попытка вызвать процедуру, которая реализована после вызова, поэтому компилятор выдаст ошибку. Чтобы этого избежать, само­стоятельные процедуры можно описывать в разделе var, как это показано в лис­тинге:

 

А теперь давайте посмотрим, как же выглядит функция siashsep:

 

Функцию siashsep уже один раз использовали, но вспомним, что здесь проис­ходит. Эта функция получает два параметра — путь к файлу и имя файла, которые она должна соединить в одну строку, чтобы получился полный путь к файлу. Но сначала мы должны проверить, заканчивается ли путь (первый полученный па­раметр — Path) знаком V. Переменная Path — это строка типа string, а значит, мы можем к ней обращаться как к массиву символов. Чтобы получить доступ к перво­му символу, мы должны написать Path.


Нам нужно проверить последний сим­вол, поэтому В квадратных скобках используется Length (Path). Функция Length возвращает длину переданной ей строковой переменной, а это значит, что в квад­ратных скобках мы указываем длину строки, т. е. последний символ.

Если бы нужен был предпоследний символ, то мы бы написали Path [Length (Path) -1]. В этом случае из длины строки вычитается единица и в ре­зультате получается индекс предпоследнего символа.

 

Если последний символ не равен \\ добавляем сначала его, а потом имя файла. Если этот символ в строке имеет место, то нужно только добавить имя файла и за­писать в переменную Result, чтобы функция вернула полный путь к файлу.

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

 

Сейчас нас больше интересует работа с компонентом Listview. Следующий код добавляет в список новый элемент: Listviewi.items.Add. Это делается внутри кон­струкции with, значит, все последующие действия между begin и end будут выпол­няться с новым элементом. А именно — изменяется заголовок нового элемента:

 

Создаем простейший файловый менеджер в Delphi

У каждого элемента есть свойство Subitems, которое хранит дополнительную информацию. Когда компонент находится в режиме отображения иконок, то до­полнительная информация не видна. Но если выбрать в свойстве viewstyle значе­ние vsReport, то компонент будет выглядеть в виде таблицы, где каждый столбец отображает дополнительную информацию, как это показано на рис. 11.38.

 

Чтобы добавить дополнительные колонки к новому элементу, надо выполнить оператор:

Subitems.Add('значение');.

Чтобы колонки отображались, нужно в свойстве columns указать имена колонок. Если имена колонок не указаны, то ничего отображаться не будет. И не забывайте, что при описании колонок первая — это заголовок элементов, остальные — это дополнительные параметры в порядке их добавления с помощью subitems.Add.

 

И последнее, ЧТО надо еще рассмотреть,— ЭТО функция FileTimeToDateTimeStr, которая переводит время/дату из системного формата в строку. Ее код можно уви­деть в листинге:

В самом начале мы приводим дату файла в универсальное глобальное время (по Гринвичу). Для ЭТОГО используется функция FileTimeToLocalFileTime, у КОТОрОЙ два параметра:

  • переменная типа TFileTime, которую нужно перевести;
  • переменная, в которую будет записан результат.

Вторым этапом мы переводим универсальное глобальное время в системное время вашего компьютера. Для этого нужна функция FileTimeToSystemTime, у которой также два параметра:

  • универсальное глобальное время;
  • переменная результата.

Теперь у нас дата хранится в переменной sysFTime и имеет тип TSystemTime. Переменная SysFTime имеет тип структуры и следующие свойства:

  • wYear — год;
  • wMonth — месяц;
  • wDay — день;
  • wHour — часы;
  • wMinute — минуты;
  • wsecond — секунды;
  • wMilli seconds — миллисекунды.

Все это числа, и нам надо превратить их в строку, но так, чтобы строка даты вы­глядела в соответствии с локальными настройками системы. Если мы пишем про­грамму, которая будет выполняться в однотипной системе (например, в русской версии Windows с российским представлением даты и времени), то вы можете вос­пользоваться функцией IntToStr, чтобы превратить все поля в строки и отформа­тировать их по своему усмотрению.

 

Однако сейчас поступим более универсально. Сначала данные превратим в формат DateTime. Для этого есть функции EncodeDate и EncodeTime. Эти функции создают пе­ременные типа TDate и TTime на основе переданных им числовых значений.

 

Получив эти переменные, мы объединяем их в более общий формат DateTime простым сложением и переводим в строку с помощью функции DateTimeToStr. Эта функция переводит дату в строку в соответствии с локальными настройками ре­гиона в ОС Windows. Вы же можете воспользоваться и функцией FormatDate, ко­торая может создать строку даты в любом виде.

dle

Помоги проекту! Расскажи друзьям об этом сайте: