:: MVP ::
|
|
:: RSS ::
|
|
|
Навигацию по файловой системе можно организовать разными способами. Наиболее
распространенные - с использованием ListView и/или TreeView, иногда для навигации
по дискам используется ComboBox (самый распространенный пример: Explorer). Сейчас
мы рассмотрим еще один вариант, с использованием MainMenu.
Прежде, чем мы приступим, скажу пару слов про этот метод. Работа с таким меню
очень напоминает работу с TreeView (расположение элементов меню по своей структуре
ничем не отличается от расположения узлов TreeView). Для более комфортной навигации,
каждому элементу меню можно присвоить иконку, ассоциированную с файлом или каталогом,
но который он указывает. В отличие от TreeView, в меню не нужно каждый раз щелкать
мышкой, чтобы просмотреть список дочерних элементов. Коротко о неприятном. Если мы
раскрываем узел с большим количеством дочерних элементов, то нам предстоит долгое
ожидание, пока все элементы будут прорисованы, прежде чем они отобразятся на экране.
В это время пользователь может подумать, что программа зависла (такая вот неприятная
мелочь).
Тем не менее, раз взялись, будем делать. Процедура, строящая дерево каталогов,
будет работать рекурсивно.
(* Рекурсивная процедура, строящая дерево каталогов *)
procedure UpdateMenu( Path: string; Parent: TMenuItem );
var
sr: TSearchRec;
ShInfo: TSHFileInfo;
MenuItem, MenuItemZero: TMenuItem;
begin
if FindFirst( Path + '*.*', faAnyFile, sr ) = 0 then
repeat
// Запрашиваем индекс иконки в системном списке
if Form1.GetIcon.Checked then
SHGetFileInfo( PChar( Path + sr.Name ), 0, ShInfo, SizeOf( ShInfo ),
SHGFI_TYPENAME or SHGFI_SYSICONINDEX );
if ( sr.Name <> '.' ) and ( sr.Name <> '..' ) then
begin
if ( sr.Attr and faDirectory ) = faDirectory then
begin
MenuItem := TMenuItem.Create( Form1 );
MenuItem.Caption := sr.Name;
Parent.Add( MenuItem );
// Если нужно, рисуем иконку
if Form1.GetIcon.Checked then
MenuItem.ImageIndex := ShInfo.iIcon;
UpdateMenu( Path + sr.Name + '\', MenuItem );
// Проверяем, пустой каталог или нет
if MenuItem.Count = 0 then
begin
MenuItemZero := TMenuItem.Create( Form1 );
MenuItemZero.Caption := 'Пусто';
MenuItem.Add( MenuItemZero );
end;
end
else
begin
MenuItem := TMenuItem.Create( Form1 );
MenuItem.Caption := sr.Name;
MenuItem.Hint := Path + sr.Name;
MenuItem.OnClick := Form1.MnuClick;
Parent.Add( MenuItem );
// Если нужно, рисуем иконку
if Form1.GetIcon.Checked then
MenuItem.ImageIndex := ShInfo.iIcon;
end;
end;
Application.ProcessMessages;
if Form1.Tag = 0 then
begin
Form1.StatusBar1.Panels.Items[0].Text := 'Поиск прерван';
Break;
end;
until FindNext( sr ) <> 0;
end;
(* Прерываем поиск *)
procedure TForm1.EndSearchClick(Sender: TObject);
begin
Tag := 0;
BeginSearch.Enabled := true;
end;
|
Подробно рассматривать эту процедуру не стану (надеюсь, вы знакомы с рекурсией),
но несколько моментов объясню. Функция SHGetFileInfo возвращает информацию о файле
(директории, диске), о ней я расскажу подробнее чуть ниже. Наше меню позволяет
запускать найденные файлы программой, связанной с ними по расширению. Для того
чтобы связать пункт меню и файл, на который он указывает, путь к файлу можно
занести в свойство Hint пункта меню. Процедуру, открывающую файл, присвоим событию
OnClick пункта меню (эта процедура описана ниже). В конце цикла идет проверка
поля Tag на равенство нулю. В нашем случае Tag показывает, идет в данный момент
поиск (Tag <> 0, например он равен 1), или нет (Tag = 0). Перед началом поиска
устанавливаем значение поля Tag в 1, и теперь, чтобы его прервать, это поле
достаточно обнулить.
(* Процедура запуска файлов из меню *)
procedure TForm1.MnuClick(Sender: TObject);
begin
ShellExecute( Handle, 'open', PChar( ( Sender as TMenuItem ).Hint ),
nil, nil, SW_SHOWNORMAL );
end;
|
Теперь, когда все готово к поиску, посмотрим, как происходит его вызов.
(* Запуск поиска файлов *)
procedure TForm1.BeginSearchClick(Sender: TObject);
var
SysImageList: UINT;
SFI: TSHFileInfo;
begin
if DirectoryExists( PathEdit.Text ) then
begin
// Очищаем меню
MainMenu1.Images.Free;
// Если пользователь хочет видеть иконки ...
if GetIcon.Checked then
begin
// Создаем список иконок
MainMenu1.Images := TImageList.Create( Self );
case RadioGroup1.ItemIndex of
0: // Запрашиваем маленькие иконки
SysImageList := SHGetFileInfo( '', 0, SFI, SizeOf( TSHFileInfo ),
SHGFI_SYSICONINDEX or SHGFI_SMALLICON );
1: // Запрашиваем большие иконки
SysImageList := SHGetFileInfo( '', 0, SFI, SizeOf( TSHFileInfo ),
SHGFI_SYSICONINDEX or SHGFI_LARGEICON );
end;
// Назначаем системный список иконок нашему меню
if SysImageList <> 0 then
begin
MainMenu1.Images.Handle := SysImageList;
MainMenu1.Images.ShareImages := true;
end;
end;
Tag := 1;
BeginSearch.Enabled := false;
StatusBar1.Panels.Items[0].Text := 'Очистка главного меню ...';
MnuRoot.Clear;
MnuRoot.Caption := IncludeTrailingPathDelimiter( PathEdit.Text );
StatusBar1.Panels.Items[0].Text := 'Ждите, работаю ...';
UpdateMenu( IncludeTrailingPathDelimiter( PathEdit.Text ), MnuRoot );
StatusBar1.Panels.Items[0].Text := 'Работа закончена';
BeginSearch.Enabled := true;
Tag := 0;
end;
end;
|
Здесь нас, прежде всего, интересует первая половина кода (со второй все и так
понятно). Если пользователь хочет видеть иконки файлов в меню, мы должны запросить
их у системы. Для этого воспользуемся функцией SHGetFileInfo. Рассмотрим аргументы
этой функции. Первый - путь к файлу (если файл указан, мы получим информацию по
этому файлу, если этот параметр пустой, мы получим "глобальные" данные). Второй -
атрибуты. Третий - указатель на структуру TSHFILEINFO (именно в нее будет занесена
информация). Четвертый - размер структуры TSHFILEINFO. Пятый - флаги, говорящие
системе о том, какую информацию мы у нее запрашиваем.
В процедуре BeginSearchClick, в зависимости от того, что хочет пользователь, мы
запрашиваем системный список маленьких (SHGFI_SMALLICON) или больших
(SHGFI_LARGEICON) иконок. В процедуре UpdateMenu мы запрашиваем номер иконки
(SHGFI_TYPENAME) для файла или каталога, указанного в первом параметре.
Имейте в виду, получение иконок заметно снижает скорость поиска.
На сегодня все. Успехов в программировании.
.: Пример к данной статье :.
|
При использовании материала - ссылка на сайт обязательна
|
|