8

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

它在 Win32/Win64 上运行良好,但我现在不明白为什么它在 OS X(VirtualBox/OS X 10.7.x)上不显示 Savedialog 过滤器。

我怎样才能让它在 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;
4

2 回答 2

3

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

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

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

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

于 2012-10-22T10:35:21.320 回答
1

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

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;
于 2013-06-18T23:29:38.620 回答