Search code examples
lazarusfreepascal

Setting `InitialDir` property of `TSelectDirectoryDialog` mutiple times


I'm trying to use the InitialDir property of TSelectDirectoryDialog:

procedure selectfolder;
begin
SelectDirectoryDialog1.InitialDir := strPath;
If SelectDirectoryDialog1.Execute then begin
   Edit1.Text := SelectDirectoryDialog1.FileName; 
   end;
end;

The first time (with strPath=X) it works fine, the second time I'm using this procedure (with strPath=Y) it doesn't use the new path (Y), but the one I selected previously.

Do I have to call a method, something like SelectDirectoryDialog1."reinitiate" before I set the InitialDir property a second time? Another idea would be to use a different property then InitialDir, but I don't know which one would do the job. Unfortunately the doc page for TSelectDirectoryDialog is currently down, so I don't have a description for the available methods/properties for TSelectDirectoryDialog and the ones I tested to solve my problem.

I got it to work if I create the TSelectDirectoryDialog class instance manually and don't use the one from the Component Palette to create it "on the form". Then I just destroy the instance and create a new one.

procedure TForm1.Button4Click(Sender: TObject);
var SelectDirectoryDialogManual : TSelectDirectoryDialog;
begin

SelectDirectoryDialogManual := TSelectDirectoryDialog.Create(nil);
SelectDirectoryDialogManual.InitialDir := 'C:\Windows';
if SelectDirectoryDialogManual.Execute then ShowMessage(SelectDirectoryDialogManual.FileName);
SelectDirectoryDialogManual.Free;
end; 

But how do I do that when I created SelectDirectoryDialog1 using the component Component Palette?


Solution

  • By saving and restoring the value of InitialDir before each invocation of Execute, or doing what @Sertac says in a comment, which works but is less "self-documenting" imo, ymmv.

    The code below works fine for me. edInitialDir is a TEdit which saves the most recent directory selected using SelectDirectoryDialog1, which is then used for the next invocation.

    procedure TForm1.Button1Click(Sender: TObject);
    begin
      SelectDirectoryDialog1.InitialDir := edInitialDir.Text;
    
      if SelectDirectoryDialog1.Execute then
        Caption := 'executed'
      else
        Caption := 'not executed';
    
      edInitialDir.Text := SelectDirectoryDialog1.FileName;
    end;
    

    Note: All properties of SelectDirectoryDialog1 are the defaults for an instance freshly added from the Component Palette.

    Regarding your comment, TSelectDirectoryDialog.Execute calls TWin32WSSelectDirectoryDialog.CreateHandle (see Dialogs.Pas, line 1219). The initial part of this is as follows:

    class function TWin32WSSelectDirectoryDialog.CreateHandle(const ACommonDialog: TCommonDialog): THandle;
    var
      Options : TOpenOptions;
      InitialDir : string;
      Buffer : PChar;
      bi : TBrowseInfo;
      iidl : PItemIDList;
      biw : TBROWSEINFOW;
      Bufferw : PWideChar absolute Buffer;
      InitialDirW: widestring;
      Title: widestring;
      DirName: string;
    begin
      DirName := '';
      InitialDir := TSelectDirectoryDialog(ACommonDialog).FileName;
      Options := TSelectDirectoryDialog(ACommonDialog).Options;
    
      if length(InitialDir)=0 then
        InitialDir := TSelectDirectoryDialog(ACommonDialog).InitialDir;
      if length(InitialDir)>0 then begin
        // remove the \ at the end.                                                                      
        if Copy(InitialDir,length(InitialDir),1)=PathDelim then
          InitialDir := copy(InitialDir,1, length(InitialDir)-1);
        // if it is a rootdirectory, then the InitialDir must have a \ at the end.
        if Copy(InitialDir,length(InitialDir),1)=DriveDelim then
          InitialDir := InitialDir + PathDelim;
      end;
    

    From this you can see that it initially attempts to derive the value of InitialDir from the FileName property and only if that results in an empty string does it attempt to use the stored value of the InitialDir property. This is why the dialog uses the previously-selected directory the next time Execute is invoked, which is exactly what you should be expecting, even if you do not like it. The only way to re-use the initial value of IntialDir from second and subsequent invocations is to restore it before each one.