How to switch the "current" TOpenDialog directory to the OnTypeChange handler? (Is it even possible?)

Depending on the selected filter, I would like OpenDialog to “look” in different directions. Sort of:

procedure TForm1.FileOpen1OpenDialogTypeChange(Sender: TObject);
// This does not work as intended...
var
  Dialog: TOpenDialog;
  FilterIndex: Integer;
  FilterExt: string;
  Path: string;
begin { TForm1.actFileOpenOpenDialogTypeChange }
  Dialog := Sender as TOpenDialog;
  FilterIndex := Dialog.FilterIndex;
  FilterExt := ExtFromFilter(Dialog.Filter, FilterIndex);
  GetIniPathForExtension(FilterExt, Path);
  if DirectoryExists(Path) and
     (Path <> IncludeTrailingPathDelimiter(Dialog.InitialDir)) then
  begin
    // those two statements don't have the desired effect
    // but illustrate what is meant to happen:
    Dialog.FileName := Path + '*' + FilterExt;
    Dialog.InitialDir := Path;
  end;
end;  { TForm1.actFileOpenOpenDialogTypeChange }

I cannot find a way to give the most interactive update a new directory. I tried calling OpenDialog.Execute, but this launches another OpenDialog without closing the current ...

+3
source share
4 answers

While the following is not entirely elegant, tested with 2K, XP, Vista and 7 seems to work. The idea is to use the dialogue behavior, when a valid directory is entered in the file name field, if the "Open" button is pressed, the dialogue switches to this folder.

" Vista", " " . , , UseLatestCommonDialogs false. , OnTypeChange , FilterIndex InitialDir.

type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure OpenDialog1TypeChange(Sender: TObject);
    procedure OpenDialog1FolderChange(Sender: TObject);
  private
    FDlgCleanUp: Boolean;
    FDlgFocusCtrl: HWnd;
    FSaveDlgFName: array [0..255] of Char;
  public
  end;

[...]

uses
  CommDlg, Dlgs;

procedure TForm1.Button1Click(Sender: TObject);
begin
  if OpenDialog1.Execute then
    ShowMessage(OpenDialog1.FileName);
end;


type
  TFileExt = (feText = 1, feRichText, feDocument);

const
  FileExts: array [TFileExt] of string = ('txt', 'rtf', 'doc');
  FileExtDesc: array [TFileExt] of string =
      ('text (*.txt)', 'rich text (*.rtf)', 'document (*.doc)');

procedure TForm1.FormCreate(Sender: TObject);
var
  fe: TFileExt;
begin
  OpenDialog1.Options := OpenDialog1.Options - [ofOldStyleDialog];
  NewStyleControls := True;
  UseLatestCommonDialogs := False;

  OpenDialog1.Filter := '';
  for fe := Low(FileExts) to High(FileExts) do
    OpenDialog1.Filter := OpenDialog1.Filter +
        FileExtDesc[fe] + '|*.' + FileExts[fe] + '|';
end;

function GetIniPathForExtension(const Ext: string): string;
begin
  // Get corresponding path from an ini file....
  Result := ExtractFilePath(Application.ExeName) + Ext;
end;

procedure TForm1.OpenDialog1TypeChange(Sender: TObject);
var
  Dialog: TOpenDialog;
  Dlg: HWnd;
  Path: string;
begin
  Dialog := Sender as TOpenDialog;
  Dlg := GetParent(Dialog.Handle);
  Path := GetIniPathForExtension(FileExts[TFileExt(Dialog.FilterIndex)]);
  ForceDirectories(Path);

  // remember what in file name, have to put it back later
  GetDlgItemText(Dlg, cmb13, @FSaveDlgFName, 256);
  SendMessage(GetDlgItem(Dlg, cmb13), WM_SETREDRAW, 0, 0); // reduce flicker
  FDlgFocusCtrl := GetFocus;

  // set file name to new folder
  SendMessage(Dlg, CDM_SETCONTROLTEXT, cmb13, Longint(PChar(Path)));

  // weird OS: windows - the below is only necessary for XP. 2K, Vista and 7
  // clicks fine without it, XP does not!
  windows.SetFocus(GetDlgItem(Dlg, IDOK));

  // do not cleanup here, with Vista and 7 folder change seems to happen
  // asynchronously - it might occur later than setting the file name and that
  // clears/reverts the edit box.
  FDlgCleanUp := True;

  // click 'Open' to change to folder
  SendMessage(GetDlgItem(Dlg, IDOK), BM_CLICK, IDOK, 0);
end;

procedure TForm1.OpenDialog1FolderChange(Sender: TObject);
var
  Dlg: HWnd;
begin
  // set the file name and focus back
  if FDlgCleanup then begin   // do not intervene if we didn't cause the change
    Dlg := GetParent((Sender as TOpenDialog).Handle);
    SendMessage(GetDlgItem(Dlg, cmb13), WM_SETREDRAW, 1, 0);
    SetDlgItemText(Dlg, cmb13, @FSaveDlgFName);
    windows.SetFocus(FDlgFocusCtrl);
  end;
  FDlgCleanup := False;
end;
0

, . :

, . , . , . , , , .

: , .

+4

One possibility:

var
  ShowAfterClose: boolean = false;
  MemFilterIndex: integer;

procedure TForm1.Import1Click(Sender: TObject);
begin
//...
  with OpenDialogImport do
  repeat
    if Execute then
    begin
      ReadImportedFile(FileName);                     //Do action
      exit;
    end else begin
      if not ShowAfterClose then                     //Check ShowAfterClose
        exit;
      ShowAfterClose := false;                       //Set ShowAfterClose false
      FilterIndex := MemFilterIndex;                 //Copy MemFilterIndex
    end;
  until false;
//...
end;

procedure TForm1.OpenDialogImportTypeChange(Sender: TObject);
begin
 PostMessage(TOpenDialog(Sender).handle,
   WM_KEYDOWN, VK_ESCAPE , 0);                        //Cancel dialog
 TOpenDialog(Sender).InitialDir := 'C:\';             //Set new directory
 MemFilterIndex := TOpenDialog(Sender).FilterIndex;   //Remember filter index
 ShowAfterClose := True;                              //ShowAfterClose = True
end;
0
source

I agree with everyone else to date ... it's a VERY BAD user interface design to make a difference without asking the user and / or the user's wishes.

0
source

Source: https://habr.com/ru/post/1757526/


All Articles