How to do it? I'm using *.dir in my filter and this does the job of getting OpenDialog to display only directories, but it seems I still have to select a file to select a directory. Is it possible to use the OpenDialog to select a directory?

Using ExtratFilepath does do the job here. I want to select a directory, not a file than extract the directory.

Thanks. (Delphi 6)

Recommended Answers

All 10 Replies

Figured it out. Seems that whenever I finally break down and ask for help that I also decide to try a different approach or look to other sources and I figure it out. Anyway, it looks like there is a

SelectDirectory(DirPath, DirOptions, 0)

command, and a FileCtrl unit, that I did not know existed. Now I do. I'll have to investigate this FileCtrl until a bit more to see what else it offers.

Here is what I use for the directory selector. The reason I handle exceptions is because sometimes the directory picker will default to the floppy disk or removable drive that is no longer attached and will cause an exception to be thrown.

procedure TMainFm.ButtonExportPathClick(Sender: TObject);
Var
  Dir: String;
begin
  if DirectoryExists(wwDBEditExportPath.Text) then
    Dir := wwDBEditExportPath.Text
  else
  begin
    if not DirectoryExists(DefaultPath('Export')) then
      CreateDir(DefaultPath('Export'));

    Dir := DefaultPath('Export');
  end;

  try
    if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],SELDIRHELP) then
      wwDBEditExportPath.Text := Dir;
  except
    on E: Exception do
    begin
      try
        Dir := emptyStr;
        if SelectDirectory(Dir, [sdAllowCreate, sdPerformCreate, sdPrompt],SELDIRHELP) then
          wwDBEditExportPath.Text := Dir;
      except
        on E: Exception do
        begin
        end;
      end;      
    end;
  end;      
end;

I hope this helps...

I left out the constant:

const
  SELDIRHELP = 1000;
commented: Thanks +1

Thanks. Very helpful.

For all the Delphi books I have and reading I have done, I've never seen any reference to the FileCtrl unit.

FileCtrl contains windows 3.1 stuff so SelectDirectory opens windows 3.1 style dialog. Personally I wouldn't want to use it.
It's possible to use OpenDialog to open only folders:
Set ofNoValidate in opendialog.options to True, set Filter to '*.' (no 's) and filename to '*.'.
Then you can use opendialog to select folders. User can press 'open' once he's inside the correct folder. It's not quite as intuitive as it could be, but it doesn't require you to select a file inside the folder.

opendialog.initialdir:=path;
opendialog.FileName:='*.';
if opendialog.execute=false then exit;
path=extractfilepath(opendialog.filename);

Can't claim I figured this out myself - I found the gist of using opendialog this way on some old borland forum.

Thanks.

I had tried something like that, where the filename, or mask, I forget, was *.dir, but I couldn't manage to retrieve the directory, but you've given me an idea.

Sorry for the late reply.

From: http://delphi.about.com/od/windowsshellapi/l/aa122803a.htm

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, shellapi, shlobj;

type
  TForm1 = class(TForm)
    Edit1: TEdit;
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


function BrowseDialogCallBack
  (Wnd: HWND; uMsg: UINT; lParam, lpData: LPARAM): 
  integer stdcall;
var
  wa, rect : TRect;
  dialogPT : TPoint;
begin
  //center in work area
  if uMsg = BFFM_INITIALIZED then
  begin
    wa := Screen.WorkAreaRect;
    GetWindowRect(Wnd, Rect);
    dialogPT.X := ((wa.Right-wa.Left) div 2) - 
                  ((rect.Right-rect.Left) div 2);
    dialogPT.Y := ((wa.Bottom-wa.Top) div 2) - 
                  ((rect.Bottom-rect.Top) div 2);
    MoveWindow(Wnd,
               dialogPT.X,
               dialogPT.Y,
               Rect.Right - Rect.Left,
               Rect.Bottom - Rect.Top,
               True);
  end;

  Result := 0;
end;

function BrowseDialog(const Title: string; const Flag: integer): string;
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);
  with BrowseInfo do begin
    hwndOwner := Application.Handle;
    pszDisplayName := @DisplayName;
    lpszTitle := PChar(Title);
    ulFlags := Flag;
    lpfn := BrowseDialogCallBack;
  end;
  lpItemID := SHBrowseForFolder(BrowseInfo);
  if lpItemId <> nil then begin
    SHGetPathFromIDList(lpItemID, TempPath);
    Result := TempPath;
    GlobalFreePtr(lpItemID);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  sFolder : string;
begin
  sFolder := BrowseDialog('Select a folder',
                          BIF_RETURNONLYFSDIRS);

  if sFolder <> '' then
    ShowMessage('Selected: ' + #13#10 + sFolder);
end;

end.

It's possible to use OpenDialog to open only folders?

HEY! I have it!

I checked Word does it in options, select default locations, just hide the file type and file name component and use the '*.' trick commented above, so it looks as you should expect!

It is a little tricky: On the dialog OnSohw you need to send some win32 messages to the dialog and voila! it is done... in the code I placed all the links to the places where I found all the info, so you can change it to your needs.

NOTE: I copy-pasted from within my code, it is not a uinit just for this, so the uses is commented. You need to copy it to a unit of you and make sure the Messages is in you uses clause.

//***********************
//** Chose a directory **
//**   uses Messages   **
//***********************

  //General usage here:
  //  http://www.delphipages.com/forum/showthread.php?p=185734

  //Need a class to hold a procedure to be called by Dialog.OnShow:
  type TOpenDir = class(TObject)
  public
    Dialog: TOpenDialog;
    procedure HideControls(Sender: TObject);
  end;
  //This procedure hides de combo box of file types...
  procedure TOpenDir.HideControls(Sender: TObject);
  const
    //CDM_HIDECONTROL and CDM_SETCONTROLTEXT values from:
    //  doc.ddart.net/msdn/header/include/commdlg.h.html
    //  CMD_HIDECONTROL = CMD_FIRST + 5 = (WM_USER + 100) + 5;
    //Usage of CDM_HIDECONTROL and CDM_SETCONTROLTEXT here:
    //  msdn.microsoft.com/en-us/library/ms646853%28VS.85%29.aspx
    //  msdn.microsoft.com/en-us/library/ms646855%28VS.85%29.aspx
    CDM_HIDECONTROL =    WM_USER + 100 + 5;
    CDM_SETCONTROLTEXT = WM_USER + 100 + 4;
    //Component IDs from:
    //  msdn.microsoft.com/en-us/library/ms646960%28VS.85%29.aspx#_win32_Open_and_Save_As_Dialog_Box_Customization
    //Translation into exadecimal in dlgs.h:
    //  www.koders.com/c/fidCD2C946367FEE401460B8A91A3DB62F7D9CE3244.aspx
    //
    //File type filter...
    cmb1: integer  = $470; //Combo box with list of file type filters
    stc2: integer  = $441; //Label of the file type
    //File name const...
    cmb13: integer = $47c; //Combo box with name of the current file
    edt1: integer  = $480; //Edit with the name of the current file
    stc3: integer  = $442; //Label of the file name combo
  var H: THandle;
  begin
    H:= GetParent(Dialog.Handle);
    //Hide file types combo...
    SendMessage(H, CDM_HIDECONTROL, cmb1,  0);
    SendMessage(H, CDM_HIDECONTROL, stc2,  0);
    //Hide file name label, edit and combo...
    SendMessage(H, CDM_HIDECONTROL, cmb13, 0);
    SendMessage(H, CDM_HIDECONTROL, edt1,  0);
    SendMessage(H, CDM_HIDECONTROL, stc3,  0);
    //NOTE: How to change label text (the lentgh is not auto):
    //SendMessage(H, CDM_SETCONTROLTEXT, stc3, DWORD(pChar('Hello!')));
  end;

//Call it when you need the user to chose a folder for you...
function GimmeDir(var Dir: string): boolean;
var
  OpenDialog: TOpenDialog;
  OpenDir: TOpenDir;
begin
  //The standard dialog...
  OpenDialog:= TOpenDialog.Create(nil);
  //Objetc that holds the OnShow code to hide controls
  OpenDir:= TOpenDir.create;
  try
    //Conect both components...
    OpenDir.Dialog:= OpenDialog;
    OpenDialog.OnShow:= OpenDir.HideControls;
    //Configure it so only folders are shown (and file without extension!)...
    OpenDialog.FileName:= '*.';
    OpenDialog.Filter:=   '*.';
    OpenDialog.Title:=    'Chose a folder';
    //No need to check file existis!
    OpenDialog.Options:= OpenDialog.Options + [ofNoValidate];
    //Initial folder...
    OpenDialog.InitialDir:= Dir;
    //Ask user...
    if OpenDialog.Execute then begin
      Dir:= ExtractFilePath(OpenDialog.FileName);
      result:= true;
    end else begin
      result:= false;
    end;
  finally
    //Clean up...
    OpenDir.Free;
    OpenDialog.Free;
  end;
end;

NOTE: May be you would prefer to left file name stuff visible, but change label to "Folder", so user can copy-paste a location into this edit... it is now very easy: Comment 3 lines hiding file name, un comment the one changing label caption and place "Folder" there (not much longer, the label width is not "auto" like in delphi).

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.