![]() |
|
|
#1
|
|||
|
|||
|
Возможно ли, и если да то как, превратить стандартный OpenDialog или SaveDialog в Select-диалог, который должен только выбирать место, куда будут сохранены ранее выбранные файлы (то есть такое окно, в котором я могу выбрать путь, куда экспортировать файлы и чтобы больше ничего нельзя было менять, то есть строки с названием файла вообще не должно быть).
|
|
#2
|
|||
|
|||
|
Есть специальная функция Win32 API, показвающая диалог выбора папки. Называется SHBrowseForFolder. Возвращает идентификатор, который можно преобразовать в путь с помощью функции SHGetPathFromIDList.
Вот например, готовая функция, отображающая диалог выбора пути и возвращающая строку с терминальным нулем, в которой записывается путь к выбранной папке. Код:
function TFaceForm.ShowChooseDirDialog: PChar;
const
TitleName = 'Укажите папку назначения'; // это подсказка, которая будет выведена в диалоге
var
lpItemID: PItemIDList;
BrowseInfo: TBrowseInfo;
DisplayName: array[0..MAX_PATH] of Char;
TempPath: array[0..MAX_PATH] of Char;
begin
Result := nil;
FillChar(BrowseInfo, sizeof(TBrowseInfo), #0);
BrowseInfo.hwndOwner := FaceForm.Handle;
BrowseInfo.pszDisplayName := @DisplayName;
BrowseInfo.lpszTitle := @TitleName[1];
BrowseInfo.ulFlags := BIF_RETURNONLYFSDIRS;
lpItemID := SHBrowseForFolder(BrowseInfo);
if lpItemID <> nil then
begin
SHGetPathFromIDList(lpItemID, TempPath);
Result := TempPath;
GlobalFreePtr(lpItemID);
end;
end;Не подойдет? |
|
#3
|
||||
|
||||
|
Можно использовать стандартую функцию SelectDirectory из модуля FileCtrl , которая делает то же самое. Не приходиться писать то, что уже написано
![]() |
|
#4
|
|||
|
|||
|
Видимо у нас разные версии delphi (у меня 7), потому как не могу найти ни SHBrowseForFolder ни SelectDirectory.
|
|
#5
|
||||
|
||||
|
У меня тоже 7 версия.
Добавить необходимые модули не забыл ? Для использования функции SelectDirectory нужен модуль FileCtrl Для SHBrowseForFolder - ShlObj |
|
#6
|
|||
|
|||
|
Это те которые лежат в ...\Borland\Delphi7\Source\Vcl\ ?
или в ...\Borland\Delphi7\Lib\Debug\ ? |
|
#7
|
||||
|
||||
|
В начале кода можно увидеть такую строку(или что-то похожее):
Код:
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; Если надо использовать функции из модуля, не указанного в этом списке, просто добавь его туда через запятую, например чтобы стало так: Код:
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, FileCtrl; |
|
#8
|
|||
|
|||
|
Теперь понял. Я просто перепутал слово "модуль" со словом "компонент"
|
|
#9
|
|||
|
|||
|
Проверил оба варианта. По удобству для пользователя более приемлемым показался графический интерфейс, основанный на модуле ShlObj.pas (минимум лишней информации на экране, текст на кнопках на русском языке). Из недостатков — отсутствует кнопка создания новой директории. Если как-то добавить в окно диалога эту кнопку, то оно стало бы идеальным.
|
|
#10
|
||||
|
||||
|
Есть два варианта процедуры SelectDirectory, в зависимости какой используешь, будут разные графические интерфейсы, да и код у них разный, можешь посмотреть исходник FileCtrl. Но вот кнопку создания новой папки туда не добавить. Поэтому процедуру вызова диалога надо писать самому, добавив необходимый флаг:
Код:
function ShowChooseDirDialog: String;
const
TitleName = 'Укажите папку назначения'; // это подсказка
var
lpItemID: PItemIDList;
BrowseInfo: TBrowseInfo;
DisplayName: array[0..MAX_PATH] of Char;
TempPath: array[0..MAX_PATH] of Char;
begin
Result := '';
FillChar(BrowseInfo, sizeof(TBrowseInfo), 0);
//Здесь нужно использовать именно Application.Handle
BrowseInfo.hwndOwner := Application.Handle;
BrowseInfo.pszDisplayName := @DisplayName;
BrowseInfo.lpszTitle := @TitleName[1];
// NEWDIALOGSTYLE - будет добавлена кнопка "Создать папку"
BrowseInfo.ulFlags := BIF_RETURNONLYFSDIRS or BIF_NEWDIALOGSTYLE;
lpItemID := SHBrowseForFolder(BrowseInfo);
if lpItemID <> nil then
begin
SHGetPathFromIDList(lpItemID, TempPath);
Result := String(TempPath);
GlobalFreePtr(lpItemID);
end;
end; |
|
#11
|
|||
|
|||
|
Rokuell, диалог стал таким как надо!
Но есть проблема: после того как я выполняю хотя бы один раз ShowChooseDirDialog приложение неправильно закрывается (то есть программа визуально закрывается, но в процессах виндов остается висеть EXE прграммы). Думаю это связано со строкой: BrowseInfo.hwndOwner := Application.Handle; |
|
#12
|
||||
|
||||
|
Я думаю это связано с глюками в твоей программе, а не в функции:
Во-первых: Поле hwndOwner определяет окно-владельца данного диалога, и никак на закрытие программы оно не влияет. Во-вторых: Более корректно делать владельцем диалога всё приложение, а не одну форму ( можешь сравнить это, вызови диалог, сверни все окна, а потом попытайся развенуть твою прогу, если владельцем будет приложение, на экране появится окно программы, с вызванным диалогом, если же владельцем будет окно, появится только диалог, а окно программы останеться скрытым ). В-третьих: можешь создать новый проект и добавть туда только эту функцию, и убедишься, что всё работает нормально. В-четвёртых: Даже в исходниках Delphi ты можешь посмотреть, что владельцем делается именно всё приложение ( файл FileCtrl.pas строка 1998 ) |
|
#13
|
|||
|
|||
|
Сделал чистый проект с этой функцией, но та же проблема (после хотя бы одного запуска функции выбора пути, выход по кнопке "Exit" из главной формы уже не работает, точнее exe-файл программы остается в процессах виндов). Вот исходники тестового проекта:
test.rar |
|
#14
|
||||
|
||||
|
Странно, у меня всё нормально работает. Попробуй проверить на другой винде (кстати, у тебя какая версия?).
Или изменить строки: Код:
procedure TForm2.Button2Click(Sender: TObject); begin Form1.Show; //Form2.Hide; Form2.Close; end; |
|
#15
|
|||
|
|||
|
Win XP Pro SP3, Delphi7. Изменил строки - тот же глюк. Другой винды не стоит.
Возможно проблема действительно в моем компе. Но все равно спасибо за коды и участие в теме. |