如何在OnTypeChange处理程序中切换TOpenDialog的“当前”目录? (有可能吗?)

时间:2010-08-01 07:47:40

标签: delphi

根据所选的过滤器,我希望OpenDialog能够在不同的方向上“看”。 类似的东西:

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 }

我找不到任何方法让对话框将自己更新到新目录。 我试过调用OpenDialog.Execute,但是这会启动另一个OpenDialog而不关闭当前的那个......

4 个答案:

答案 0 :(得分:4)

前段时间我完全照顾过那种东西,但也找不到解决办法。现在我很高兴不要因为以下原因而实施它:

想象一下,用户执行打开的对话框。他知道在哪里可以找到所需文件并导航到该文件夹​​。现在他看不到该文件并意识到过滤器设置错误。他更改过滤器并自然希望文件夹保持不变。

尝试并做一些观察:在大多数情况下,用户首先选择文件夹,然后选择文件类型。

答案 1 :(得分:0)

一种可能性:

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;

答案 2 :(得分:0)

到目前为止,我会同意其他所有人的观点......在没有询问用户和/或用户的意愿的情况下改变事物是非常糟糕的用户界面设计。

答案 3 :(得分:0)

虽然以下不完全优雅,经过2K,XP,Vista和7测试,但似乎有效。我们的想法是使用对话框的行为,当在文件名框中输入有效目录时,如果按下“打开”按钮,对话框将切换到该文件夹​​。

它不适用于'Vista风格'对话框,我对Common Item Dialog没有任何认识。因此,在显示对话框之前,UseLatestCommonDialogs必须设置为false。另请注意,最初启动对话框时不会触发OnTypeChange事件,可以在显示对话框之前设置FilterIndexInitialDir

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's 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;