Запрос каталога “почти по взрослому”

Иногда хочется запросить у пользователя не файл, а именно каталог. И сделать это хочется красиво, без использования getfiled или сторонних приложений, чистым лиспом. Попробуем?

Вообще говоря, решение существует уже давно. Один из вариантов показал Владимир Азарко здесь. На всякий случай (caduser уже столько раз падал, что не помешает и страховая копия) приведу здесь ключевой код:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
(vl-load-com)

(defun directory-dia (message / sh folder folderobject result)
  ;; By Tony Tanzillo
  ;; Modified by Tim Willey
  ;; 16 Will let you type in the path
  ;; 64 Will let you create a new folder
  ;; Use
  ;; (Directory-Dia "Create Sheet Index \nSelect directory to grab Drawings \nBy Tim Willey 09/13/07")

  (vl-load-com)
  (setq sh
   (vla-getinterfaceobject
     (vlax-get-acad-object)
     "Shell.Application"
     ) ;_ end of vla-getInterfaceObject
  ) ;_ end of setq
  (setq folder
   (vlax-invoke-method
     sh
     'browseforfolder
     (vla-get-hwnd (vlax-get-acad-object))
     message
     0
;;; This is the bit number to change.
;;; (+ 16 64)
     ) ;_ end of vlax-invoke-method
  ) ;_ end of setq
  (vlax-release-object sh)
  (if folder
    (progn
      (setq folderobject
       (vlax-get-property folder 'self)
      ) ;_ end of setq
      (setq result
       (vlax-get-property folderobject 'path)
      ) ;_ end of setq
      (vlax-release-object folder)
      (vlax-release-object folderobject)
      (strcat (vl-string-right-trim "\" result) "\")
      ) ;_ end of progn
    ) ;_ end of if
  ) ;_ end of defun

Поискав в MSDN, можно обнаружить, что у метода BrowseForFolder несколько параметров:

1
oFolder = Shell.BrowseForFolder(Hwnd, sTitle, iOptions [, vRootFolder])
Hwnd Required. The handle to the parent window of the dialog box. This value can be zero.
sTitle Required. A String value that represents the title displayed inside the Browse dialog box.
iOptions Required. An Integer value that contains the options for the method. This can be zero or a combination of the values listed under the ulFlags member of the BROWSEINFO structure.
vRootFolder Optional. The root folder to use in the dialog box. The user cannot browse higher in the tree than this folder. If this value is not specified, the root folder used in the dialog box is the desktop. This value can be a string that specifies the path of the folder or one of the ShellSpecialFolderConstants values. Note that the constant names found in ShellSpecialFolderConstants are available in Microsoft Visual Basic, but not in Visual Basic Scripting Edition (VBScript) or Microsoft JScript. In those cases, the numeric values must be used in their place.

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


Символьное представление Оригинальный текст Попытка перевода Значение [16] Значение[10]
BIF_RETURNONLYFSDIRS Only return file system directories. If the user selects folders that are not part
of the file system, the OK button is grayed.
Возвращает только системные каталоги. Попытка выбора несистемного каталога блокирует
кнопку ОК
0x0001 1
BIF_DONTGOBELOWDOMAIN Do not include network folders below the domain level in the dialog box's tree view
control.
Исключает сетевые папки ниже уровня домена при представлении в виде дерева 0x0002 2
BIF_STATUSTEXT Include a status area in the dialog box. The callback function can set the status
text by sending messages to the dialog box. This flag is not supported when BIF_NEWDIALOGSTYLE
is specified.
Включает показ статусной строки в окне. теоретически можно установить новые значения
статусной строки через специальную callback-функцию (сам не пробовал, не до того
было). Значение блокируется, если установлен флаг BIF_NEWDIALOGSTYLE
0x0004 4
BIF_RETURNFSANCESTORS Only return file system ancestors. An ancestor is a subfolder that is beneath the
root folder in the namespace hierarchy. If the user selects an ancestor of the root
folder that is not part of the file system, the OK button is grayed.
Как-то с переводом у меня не задалось 0x0008 8
BIF_EDITBOX Include an edit control in the browse dialog box that allows the user to type the
name of an item.
Включает текстовое поле, позволяющее вручную ввести путь к каталогу. 0x0010 16
BIF_VALIDATE If the user types an invalid name into the edit box, the browse dialog box will
call the application's BrowseCallbackProc with the BFFM_VALIDATEFAILED message.
This flag is ignored if BIF_EDITBOX is not specified.
Если пользователь вводит в текстовое поле некорректный путь, диалоговое окно будет
вызывать специальную функцию BrowseCallbackProc с сообщением BFFM_VALIDATEFAILED.
Флаг игнорируется, если BIF_EDITBOX не установлен
0x0020 32
BIF_NEWDIALOGSTYLE Use the new user interface. Setting this flag provides the user with a larger dialog
box that can be resized. The dialog box has several new capabilities, including:
drag-and-drop capability within the dialog box, reordering, shortcut menus, new
folders, delete, and other shortcut menu commands. To use this flag, you must call
OleInitialize or CoInitialize before calling SHBrowseForFolder.
Использует новый пользовательский интерфейс. Установка этого флага позволяет использовать
диалоговое окно большего размера, да еще и с изменяемыми границами. Также предоставляется
несколько новых возможностей: drag-n-drop, изменение порядка следования каталогов,
контекстные меню, создание новых каталогов, удаление каталогов, и т.п. Использование
этого флага в lisp'е затруднено, т.к. требуется дополнительно вызывать специальные
функции OleInitialize и CoInitialize
0x0040 64
BIF_USENEWUI Является комбинацией флагов BIF_NEWDIALOGSTYLE и BIF_EDITBOX 0x0050 80
BIF_BROWSEINCLUDEURLS The browse dialog box can display URLs. The BIF_USENEWUI and BIF_BROWSEINCLUDEFILES flags must also be set. If these three flags are not set, the browser dialog box will reject URLs. Even when these flags are set, the browse dialog box will only display URLs if the folder that contains the selected item supports them. When the folder's IShellFolder::GetAttributesOf method is called to request the selected item's attributes, the folder must set the SFGAO_FOLDER attribute flag. Otherwise, the browse dialog box will not display the URL. Допускается показ и выбор URL. Требует обязательной установки флагов BIF_USENEWUI и BIF_BROWSEINCLUDEFILES. 0x0080 128
BIF_UAHINT When combined with BIF_NEWDIALOGSTYLE, adds a usage hint to the dialog box in place of the edit box. BIF_EDITBOX overrides this flag. 0x0100 256
BIF_NONEWFOLDERBUTTON Do not include the New Folder button in the browse dialog box. Исключает кнопку [Создать новую папку] из диалога 0x0200 512
BIF_NOTRANSLATETARGETS When the selected item is a shortcut, return the PIDL of the shortcut itself rather than its target. (насколько я понял) Если выбирается ярлык, то возвращается именно он, а не тот каталог, на который он указывает. Если будет время, проверю и отпишусь. 0x0400 1024
BIF_BROWSEFORCOMPUTER Only return computers. If the user selects anything other than a computer, the OK button is grayed. Ну, и по названию уже все понятно :) 0x1000 4096
BIF_BROWSEFORPRINTER Only allow the selection of printers. If the user selects anything other than a printer, the OK button is grayed.
In Microsoft Windows XP, the best practice is to use an XP-style dialog, setting the root of the dialog to the Printers and Faxes folder (CSIDL_PRINTERS).
Позволяет выбирать только принтеры. 0x2000 8192
BIF_BROWSEINCLUDEFILES The browse dialog box will display files as well as folders. Показывает файлы как каталоги. Удобно не всегда 0x4000 16384

В общем-то, комбинируя разные флаги простым сложением, можно поиграться с видом окна.

Остается только один, последний параметр. Необязательный - vRootFolder. Указывает родительский каталог, с которого пользователь сможет выбирать подкаталоги. Вроде бы и удобно, да вот проблема - подняться "выше" этого каталога невозможно.

Понятно, что диалоги, разработанные с использованием C++ или .NET, будут намного более интересны и многофункциональны. Но зато это решение практически не зависит от версии и разрядности как AutoCAD, так и Windows.



Комментарии

Есть 2 коммент. к “Запрос каталога “почти по взрослому””
  1. Кулик Алексей aka kpblc пишет:

    Что называется, "стоило написать" :) Тут же всплыли темы http://www.caduser.ru/forum/index.php?PAGE_NAME=read&FID=23&TID=34695&PAGEN_1=2 и http://cadtips.cadalyst.com/programmers-tools/select-multiple-files . Куда катится этот мир! :)

  2. Кулик Алексей aka kpblc пишет:

    В заголовке окна, кстати, можно указывать до 3 строк текста, разделенного символом "\n"

Поделитесь своим мнением


Я не робот.