por Marcos Elias
{essa é uma dica de programação para Win32/Win64 usando o Lazarus / FreePascal, não interessa a usuários comuns}
As versões atuais do Lazarus / FreePascal ainda não foram atualizadas com as chamadas da API do Windows que exibe as janelas novas de Abrir e Salvar (new OpenDialog and SaveDialog), usadas no Windows Vista e 7. Em algum momento isso deverá ocorrer, mas enquanto não atualizam…
Dá para chamá-las diretamente, sem se prender à LCL e/ou ao compilador. Eu não testei no Delphi, mas há algo parecido para as versões antigas, que também usavam os programas com janelas “velhas”. Fica meio feio usar um programa atualmente e as janelas comuns não corresponderem ao encontrado no restante do sistema. E não é exclusividade de Windows. Quem usa Linux sabe o desgosto visual que é lidar com as telas de Abrir e Salvar do GTK1 sobre GTK2 :P Além do visual tem a questão da praticidade. No Windows Vista+ há um campo “Pesquisar” nas telas Abrir e Salvar que serve como filtro de arquivos na pasta atual, isso ajuda demais.
Veja como são as janelas antigas:
E as novas:
Algo parecido ocorreu com a mudança do Windows 98 pro 2000/Me/XP, onde apareceu aquela barra “Locais” na esquerda, que também ajuda muito perto da janela simples do Windows 95/98. Eis a antigona:
Eu achei uma unit para isso no DotFusion:
{ VistaOpenSaveDialog: A new Open/Save dialog that uses Windows API to display Vista compatiable Open or Save Dialog. Tested in Windows 2000/XP/Vista/Vista x64. Compiled with Lazarus 0.9.29 beta (21448) / FreePascal 2.2.4 It should compile successfully with all newer and maybe some the versions. Created by Iskren Slavov (http://www.dotfusion.net/). No right reserved. Feel free to use for any of your applications regardless of the license. ########################################## Example usage: VistaOpenSaveDialg(Handle, '', '', '', 'Open file...', fileName, OFN_FILEMUSTEXIST, VDT_OPENDIALOG); Some usable flags under Windows Vista: OFN_READONLY, OFN_HIDEREADONLY, OFN_OVERWRITEPROMPT, OFN_FILEMUSTEXIST, OFN_PATHMUSTEXIST, OFN_FORCESHOWHIDDEN, OFN_DONTADDTORECENT } unit VistaOpenSaveDlg; {$mode objfpc}{$H+} interface uses Windows, Messages, CommDlg, SysUtils; type TVistaDlgType = (VDT_OPENDIALOG, VDT_SAVEDIALOG); function ReplaceStr(const S, Srch, Replace: string): string; function VistaOpenSaveDialog(Parent: HWND; const Filters, DefaultExtension, InitialDir, Title: string; var FileName: string; DlgFlags: DWORD; DlgType: TVistaDlgType): Boolean; implementation function ReplaceStr(const S, Srch, Replace: string): string; var i: Integer; Source: string; begin Source := S; Result := ''; repeat i := Pos(UpperCase(Srch), UpperCase(Source)); if i > 0 then begin Result := Result + Copy(Source, 1, i - 1) + Replace; Source := Copy(Source, i + Length(Srch), MaxInt); end else Result := Result + Source; until i <= 0; end; function VistaOpenSaveDialog(Parent: HWND; const Filters, DefaultExtension, InitialDir, Title: String; var FileName: String; DlgFlags: DWORD; DlgType: TVistaDlgType): Boolean; var fnStruct: TOpenFileName; szFile: array[0..MAX_PATH] of Char; begin Result := False; FillChar(fnStruct, SizeOf(TOpenFileName), 0); with fnStruct do begin hwndOwner := Parent; lStructSize := SizeOf(TOpenFileName); lpstrFile := szFile; StrPCopy(lpstrFile, FileName); nMaxFile := SizeOf(szFile); lpstrFilter := PChar(ReplaceStr(Filters, '|', #0) + #0#0); if (Title <> '') then lpstrTitle := PChar(Title); if (InitialDir <> '') then lpstrInitialDir := PChar(InitialDir); if DefaultExtension <> '' then lpstrDefExt := PChar(DefaultExtension); Flags := Flags or DlgFlags; end; case DlgType of VDT_OPENDIALOG: if GetOpenFileName(@fnStruct) then begin Result := True; FileName := StrPas(szFile); end; VDT_SAVEDIALOG: if GetSaveFileName(@fnStruct) then begin Result := True; FileName := StrPas(szFile); end; end; end; end. |
Basta salvá-na num arquivo VistaOpenSaveDlg.pas na pasta do projeto, e incluir VistaOpenSaveDlg na uses. Para chamar as janelas você deverá criar uma variável para receber o retorno (o nome do arquivo), por exemplo:
Vista e Seven OpenDialog (abrir):
var
arquivo: String;
begin
VistaOpenSaveDialog(Handle, 'Text|*.txt|All|*.*', '.txt', '', 'Open file', arquivo, OFN_FILEMUSTEXIST, VDT_OPENDIALOG);
//Faça alguma coisa com a variável arquivo...
end;
Vista e Seven SaveDialog (salvar):
var
arquivo: String;
begin
VistaOpenSaveDialog(Handle, 'Text|*.txt|All|*.*', '.txt', '', 'Save file', arquivo, OFN_OVERWRITEPROMPT, VDT_SAVEDIALOG);
//Faça alguma coisa com a variável arquivo...
end;
As flags podem ser as citadas no comentário no começo da unit.
E no Linux, Mac OS X, Windows CE, Windows Mobile, etc?
Por fim, há um pequeno grande problema se suas aplicações forem multiplataforma: esse código é exclusivo para Windows. Por isso para usar em aplicações multiplataforma você deve usar um ifdef… Uma condicional para o compilador.
Um exemplo pronto, que estou usando no Mep LA (projeto que provavelmente substituirá o Mep Texto):
Na uses:
{$IFDEF WINDOWS}, Windows, VistaOpenSaveDlg{$ENDIF}
Para abrir e salvar, coloque um componente normal OpenDialog e SaveDialog. E chame-os assim:
Abrir:
var
arquivo: String;
...
{$IFDEF WINDOWS}
VistaOpenSaveDialog(Self.Handle, 'Text files|*.txt|All|*', '.txt', GetUserDir, 'Open file', arquivo, OFN_FILEMUSTEXIST, VDT_OPENDIALOG);
{$ELSE}
if not OpenDialog1.Execute then Exit;
arquivo := OpenDialog1.Filename;
{$ENDIF}
Salvar:
var
ArqNovo: String;
...
ArqNovo := '';
{$IFDEF WINDOWS}
VistaOpenSaveDialog(Self.Handle, 'Text files|*.txt|All|*', '.txt', GetUserDir, 'Save file', ArqNovo, OFN_OVERWRITEPROMPT + OFN_PATHMUSTEXIST, VDT_SAVEDIALOG);
if ArqNovo = '' then
Exit;
{$ELSE}
if not SaveDialog1.Execute then Exit;
ArqNovo := SaveDialog1.Filename;
{$ENDIF}
Os exemplos devem ser adaptados ao seu gosto e caso, mas é basicamente isso. Bom que funciona sem precisar esperar o compilador do FreePascal implementar as novas chamadas. Assim que elas forem inclusas no compilador nativamente, você poderá voltar a usar os componentes OpenDialog e SaveDialog do Lazarus em todos os projetos.