FireMonkey / Rad Studio XE2:如何在OS X上显示SaveDialog过滤器?

时间:2012-10-19 15:39:17

标签: macos delphi delphi-xe2 firemonkey

我创建了一个(Delphi XE2)Firemonkey示例程序,其中包含一个TButton和一个带有两个不同过滤器的TSavedialog。 (TSaveDialog组件支持Win32 / Win64和OS X平台。)

它在Win32 / Win64上工作正常,但我现在不知道为什么它不显示OS X上的Savedialog过滤器(VirtualBox / OS X 10.7.x)。

如何让它在OS X上运行?

procedure TForm1.Button_SaveClick(Sender: TObject);
begin
  SaveDialog.Filter:='Format_1 (*.fmt1)|*.fmt1|Format_2 (*.fmt2)|*.fmt2';

  If Savedialog.Execute Then ShowMessage(SaveDialog.FileName+#13+'Selected filterindex: '+Inttostr(SaveDialog.FilterIndex));
end;

2 个答案:

答案 0 :(得分:3)

“保存”对话框不是在Delphi中构建的,而是调用本机MAC OSX对话框(NSSavePanel)。这没有用户可选择的过滤器。

当您执行保存对话框时,Delphi将过滤器作为数组传递给NSSavePanel.SetAllowedFileTypes,它确定OSX对话框允许用户指定的扩展名 - 但是没有可选列表。

要允许用户从列表中进行选择,您需要创建自己的文件类型选择对话框,然后选择该选项并将其作为默认文件类型和唯一的过滤项目传递给savedialog。

创建一个全新的fileSave对话框的替代方法并不容易,因为Firemonkey树组件似乎坚持扩展其所有节点,因此执行硬盘驱动器上所有文件的完整遍历。在任何情况下,MAC用户都会熟悉标准对话框。

答案 1 :(得分:1)

我在MAC OSX中遇到了与TOpendialog相同的问题:过滤器不起作用,但在Windows中它们可以。现在我解决了这个问题,也许你可以使用代码来解决问题。在MAC OSX下禁用那些未在Windows中显示的文件,您无法选择它们。

uses
  Macapi.Foundation, Macapi.ObjectiveC, Macapi.AppKit;


 {$IFDEF MACOS}

  function AllocFilterStr(const S: string; var Filter: NSArray): Boolean;
  var
    input, pattern: string;
    FileTypes: array of string;
    outcome, aux: TArray<string>;
    i, j: Integer;
    FileTypesNS: array of Pointer;
    NStr: NSString;
    LocObj: ILocalObject;
  begin
    // First, split the string by using '|' as a separator
    Result := false;
    input := S;
    pattern := '\|';

    outcome := TRegEx.Split(input, pattern);
    pattern := '\*\.';
    SetLength(FileTypes, 0);

    for i := 0 to length(outcome) - 1 do
    begin
      if Odd(i) then
        if outcome[i] <> '*.*' then
          if AnsiLeftStr(outcome[i], 2) = '*.' then
          begin
            aux := TRegEx.Split(outcome[i], pattern);
            for j := 0 to length(aux) - 1 do
            begin
              aux[j] := Trim(aux[j]);
              if aux[j] <> '' then
              begin
                if AnsiEndsStr(';', aux[j]) then
                  aux[j] := AnsiLeftStr(aux[j], length(aux[j]) - 1);
                SetLength(FileTypes, length(FileTypes) + 1);
                FileTypes[length(FileTypes) - 1] := aux[j];
              end;
            end;
          end;
    end;

    // create the NSArray from the FileTypes array
    SetLength(FileTypesNS, length(FileTypes));
    for i := 0 to length(FileTypes) - 1 do
    begin
      NStr := NSSTR(FileTypes[i]);
      if Supports(NStr, ILocalObject, LocObj) then
        FileTypesNS[i] := LocObj.GetObjectID;
    end;
    if length(FileTypes) > 0 then begin
      Filter := TNSArray.Wrap(TNSArray.OCClass.arrayWithObjects(@FileTypesNS[0], length(FileTypes)));
      result := true;
    end;
  end;

function CFToDelphiString(const CFStr: CFStringRef): string;
var
  Range: CFRange;
begin
  Range.location := 0;
  Range.length := CFStringGetLength(CFStr);
  SetLength(Result, Range.length);
  if Range.length = 0 then Exit;
  CFStringGetCharacters(CFStr, Range, PWideChar(Result));
end;

function NSToDelphiString(const NSStr: NSString): string; inline;
begin
  Result := CFToDelphiString((NSStr as ILocalObject).GetObjectID);
end;


  {$ENDIF}


procedure TMainform.LoadClick(Sender: TObject);
 {$IFDEF MACOS}
var
  Filter: NSArray;
  LOpenDir: NSOpenPanel;
  {$ENDIF}
begin

  {$IFDEF MSWINDOWS}
  Opendialog1.Filter:= '*.fcb|*.fcb';
  if Opendialog1.execute then
  begin
    case Opendialog1.Filterindex of
      1:  LoadPlaylist(Opendialog1.filename, false, false);
      2:  LoadPlaylist(Opendialog1.filename, false, true);
    end;
  end;
  {$ENDIF}

 {$IFDEF MACOS}
  LOpenDir := TNSOpenPanel.Wrap(TNSOpenPanel.OCClass.openPanel);
  if AllocFilterStr('*.fcb|*.fcb', Filter) then
  if LOpenDir.runModalForTypes(Filter)=1 then
    LoadPlaylist(NSToDelphiString(LOpenDir.filename), false, false);
  {$ENDIF}
end;