M Y D E L P H I 7 . R U Самоучитель программирования  
 
  • Главная
  •  

     

    Использование диалогов для загрузки и сохранения графических файлов

    Для удобства открытия картинок существует пара компонентов-диалогов: TOpenPictureDialog и TSavePictureDialog.

    Список форматов открываемых файлов определяется свойством Filter. Можно, как в случае со стандартными диалогами TOpenDiaiog или TSaveDialog, сформировать их вручную с помощью редактора свойства Filter. Можно поступить проще, воспользовавшись готовыми средствами. Для удобства формирования строк графических фильтров существуют три специальные функции:

    •  function GraphicFilter(GraphicClass: TGraphicClass): string;

    Формирует строку с полным текстом графического фильтра, позволяющего открывать все файлы, форматы которых являются потомками параметра GraphicClass. Если в качестве параметра этой функции будет передан класс TGraphic, то в строке будут перечислены все форматы:

    'Аll (*.jpg;*.jpeg;*.bmp;*.ico;*.emf;*.wmf} I *.jpg;*.jpeg;*.bmp;*.ico; *.emf;*.wmfIJPEG Image File (*.jpg) I *.jpgI JPEG Image File (*.jpeg) I *.jpeg|Bitmaps (*.bmp) I *.bmplIcons (*.ico) I*.ico|Enhanced Metafiles (*.emf) |*.emf[Metafiles (*.wmf) I *.wmf'

    Формат JPEG появляется в перечне, если в приложении используется модуль с тем же названием — JPEG. В приводимом ниже примере возникла необходимость совместить фильтры только для классов TBitmap и TJPEGimage, которые не являются предками друг друга. В этом случае получившиеся строки нужно соединить, использовав символ конкатенации "|":

    S := GraphicFilter(TBitmap)+'|'+

    GraphicFilter(TJpeglmage) 

    •  function GraphicExtension(GraphicClass: TGraphicClass): string;

    Возвращает расширение файла, формат которого соответствует графическому классу GraphicClass. Так, если передать в качестве параметра класс TBitmap, то функция вернет строку 'BMP';

    •  function GraphicFileMask(GraphicClass: TGraphicClass): string;

    Эта функция возвращает перечень расширений файлов с форматами — потомками GraphicClass, перечисленных через точку с запятой.

    Для диалогов предусмотрено несколько событий, которые программист может обработать самостоятельно. Первые три — достаточно тривиальные: OnShow, oncanciose и enclose. Нужно предостеречь программиста: по чьему-то недосмотру последние два вызываются только в случае нормального завершения диалога (нажатием кнопки Open или Save), а если завершить диалог нажатием кнопки Cancel или "крестика" на заголовке диалога, то управления они не получат.

    Другие три события связаны с изменениями, которые осуществляет пользователь во время выбора нужного файла. Они происходят в момент изменения формата открываемого файла (событие onTypeChange), изменения текущей папки (OnFolderChange) и текущего файла (OnSelectionChange).

    Но разработчики диалогов не предусмотрели одну очень нужную возможность. Дело в том, что у разных графических форматов возможны различные опции и варианты. Если вы имеете опыт работы с графическими пакетами вроде Adobe Photoshop или Corel, то знаете, что, в зависимости от выбранного формата сохранения данных, диалог изменяет свой внешний вид — к нему добавляются элементы управления, соответствующие параметрам формата.

    Поступим так и мы, предусмотрев настройку при сохранении файлов формата JPEG. Для этого будет использовано событие OnTypeChange компонента TSavePictureDialog. Для события нужно проверить значение свойства Filterindex. Если оно больше 1 (т. е. выбраны файлы формата JPEG), нужно увеличить высоту окна диалога и разместить на нем дополнительные компоненты: флажок, соответствующий свойству ProgressiveEncoding, и редактор свойства compressionQuaiity (рис. 10.2). Если тип файла снова поменялся и стал равным 1, нужно эти компоненты убрать.

    Рис. 10.2. Внешний вид модифицированного компонента TSavePictureDiaiog

    Поможет нам в этом внимательное изучение исходных кодов диалогов, находящихся в модуле EXTDLGS.PAS. Программисты Borland пошли по пути модернизации внешнего вида стандартных диалогов, добавив к ним справа панель для отображения внешнего вида открываемых (записываемых) картинок. Можно пойти дальше и добавить таким же образом и свои элементы управления.

    Приводимый ниже пример ModifDlg — усовершенствованная программа просмотра и сохранения файлов растровой графики, к которым относятся файлы форматов JPEG и BMP. Чтобы исключить метафайлы и значки (*.wmf, *.emf, *.ico), соответствующим образом настраиваются фильтры в диалогах открытия и сохранения.

    Для изменения размеров диалогового окна нужно отыскать среди входящих в его состав компонентов панель picturePanel (так назвали ее разработчики Borland) и увеличить ее высоту. Следует также поменять и размеры родительских окон. Поскольку они не являются компонентами Delphi (стандартные диалоги являются составными частями Windows) для этой цели используются функции API GetWindowRect И SetWindowPos.

    Обратите также внимание, что при загрузке используется событие OnProgress класса TGraphic. В его обработчике информация об объеме проделанной работы отображается на компоненте progressBar1. Для маленьких картинок обработчик вызывается только в начале и в конце операции, пользователь ничего не заметит. Зато при загрузке большого изображения он будет спокоен, видя, что процесс загрузки идет и машина не зависла.

    Листинг 10.1. Исходный текст главного модуля программы ModifDlg 

    unit mainUnit; 

    interface

    uses

    Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,

     Dialogs,

    ExtDlgs, StdCtrls, ComCtrls, ExtCtrls, Buttons; 

    type

    TForml = class(TForm)

    SavePictureDialogl: TSavePictureDialog; 

    OpenPictureDialogl: TOpenPictureDialog;

     ScrollBoxl: TScrollBox; Imagel: TImage; 

    ProgressBari: TProgressBar;

     OpenBitBtn: TBitBtn;

     SaveBitBtn: TBitBtn;

    procedure SavePictureDialoglTypeChange(Sender: TObject); 

    procedure ImagelProgress(Sender: TObject; Stage: TProgressStage;

     PercentDone: Byte; 

    RedrawNow: Boolean; 

    const R: TRect;

     const Msg: String);

    procedure SavePictureDialoglClose(Sender: TObject); 

    procedure FormCreate(Sender: TObject);

    procedure SavePictureDialoglShow(Sender: TObject);

     procedure OpenBitBtnClick(Sender: TObject);

     procedure SaveBitBtnClick(Sender: TObject); 

    private 

    public 

    end;

    var

    Forml: TForml;

    implementation

    {$R *.DFM} 

    uses jpeg;

    const DeltaH : Integer = 80; 

    var Quality : TJpegQualityRange; 

    ProgressiveEnc : Boolean;

    procedure TForml.OpenBitBtnClick(Sender: TObject);

    begin

    if OpenPictureDialogl.Execute

    then Imagel.Picture.LoadFromFile

    (OpenPictureDialogl.FileName); 

    end;

    procedure TForml.SaveBitBtnClick(Sender: TObject);

    var ji : TJpeglmage;

    begin

    if SavePictureDialogl.Execute then

    begin

    ji := TJpeglmage.Create;

    ji.CompressionQuality := Quality;

    ji.ProgressiveEncoding := ProgressiveEnc;

    j i.Assign(Imagel.Picture.Bitmap);

    ji.SaveToFile(SavePictureDialogl.FileName);

    ji.Free;

    end;

     end;

    procedure TForml.SavePictureDialoglTypeChange(Sender: TObject);

     var ParentHandle:THandle;wRect:TRect;

    PicPanel,PaintPanel:TPanel;JEdit : TEdit; 

    Expanded : boolean;

    begin

    With Sender as TSavePictureDialog do

     begin

    PicPanel := (FindComponent('PicturePanel') as TPanel);

    if not Assigned(PicPanel) then Exit;

    ParentHandle:=GetParent(Handle);

    PaintPanel:=(FindComponent('PaintPanel') as TPanel); 

    PaintPanel.Align := alNone;

     Expanded := FindComponent('JLabel') <> nil;

     if Filterlndex >1 then begin if not Expanded then

    begin

    GetWindowRect(ParentHandle,WRect);

    SetWindowPos(ParentHandle,0,0,0,

    WRect.Right-WRect.Left,

    WRect.Bottom-WRect.Top+DeltaH,

    SWP_NOMOVE+SWP_NOZORDER);

    GetWindowRect(Handle,WRect);

    SetWindowPos(handle,0,0,0,WRect.Right-

    WRect.Left,

    WRect.Bottom-WRect.Top+DeltaH,

    SWP_NOMOVE+SWP_NOZORDER);

    Expanded:=True;

    PicPanel.Height := PicPanel.Height+DeltaH;

    if FindComponent('JLabel')=nil

     then with TLabel.Create(Sender as TSavePictureDialog) do

     begin

    Parent := PicPanel;

    Name := 'JLabel';

    Caption := 'Quality';

    Left := 5;

    Height := 25;

    Top := PaintPanel.Top+PaintPanel.Height+5; end;

    if FindComponent('JEdit')=nil then 

    begin

    JEdit := TEdit.Create(Sender as TSavePictureDialog);

     with JEdit do 

    begin

    Parent := PicPanel;

    Name:='JEdit';

    Text := '75';

    Left:-50;Width := 50;

    Height := 25;

    Top := PaintPanel.Top+PaintPanel.Height+5; 

    end;

     end;

    if FindComponent('JUpDown')=nil then 

    with TUpDown.Create(Sender as TSavePictureDialog) do

     begin

    Parent := PicPanel;

    Name:='JUpDown';

    Associate := JEdit;

    Increment := 5;

    Min := 1; Max := 100;

    Position := 75; end;

    if FindComponent('JCheck')=nil then

    with TCheckBox.Create(Sender as TSavePictureDialog) do

     begin

    Name: = 'JCheck';

    Caption:='Progressive Encoding'; Parent:=PicPanel;

    Left:=5;Width := PicPanel.Width - 10; Height:=25;

    Top := PaintPanel.Top+PaintPanel.Height+35; 

    end;

     end; 

    end 

    else

    SavePictureDialoglClose(Sender);

     end; 

    end;

    procedure TForml.ImagelProgress(Sender: TObject; Stage: TProgressStage;

     PercentDone: Byte; RedrawNow: Boolean; const R: TRect; 

    const Msg: String); 

    begin

    case Stage of psStarting: 

    begin

    Progressbarl.Position := 0;

     Progressbarl.Max := 100;

     end;

     psEnding: begin

    Progressbarl.Position := 0; 

    end;

    psRunning: begin

    Progressbarl.Position := PercentDone;

    end; 

    end;

     end;

    procedure TForml.SavePictureDialoglClose(Sender: TObject);

     var PicPanel : TPanel; ParentHandle : THandle; WRect : TRect;

     begin

    With Sender as TSavePictureDialog do

     begin

    PicPanel := (FindComponent('PicturePanel') as TPanel);

     if not Assigned(PicPanel) then Exit; ParentHandle:=GetParent(Handle);

     if ParentHandle=0 then Exit;

     if FindComponent('JLabel')onil then 

    begin

    FindComponent('JLabel').Free; 

    FindComponent('JEdit').Free;

    ProgressiveEnc := (FindComponent('JCheck1) as TCheckBox).Checked; FindComponent('JCheck').Free;

    Quality := (FindComponent('JUpDown') as TUpDown).Position; FindComponent('JUpDown').Free;

    PicPanel.Height:=PicPanel.Height-DeltaH; 

    GetWindowRect(Handle,WRect);

    SetWindowPos(Handle,0,0,0,WRect.Right-WRect.Left, WRect.Bottom-WRect.Top-DeltaH,

    SWP_NOMOVE+SWP_NOZORDER); GetWindowRect(ParentHandle,WRect);

    SetWindowPos(ParentHandle,0,0,0,

    WRect.Right-WRect.Left, WRect.Bottom-WRect.Top-DeltaH,

    SWP_NOMOVE+SWP_NOZORDER); Filterlndex := 1;

     end; 

    end; 

    end;

    procedure TForml.FormCreate(Sender: TObject);

    var s: string;

    begin

    s :=GraphicFilter(TBitmap)+'|'+

    GraphicFilter(TJpeglmage);

    OpenPictureDialogl.Filter := s;

    SavePictureDialogl.Filter := s; 

    end;

    procedure TForml.SavePictureDialoglShow(Sender: TObject); 

    begin

    with Sender as TSavePictureDialog do

     begin

    if FindComponent('JLabel')Onil then

     begin

    Filterindex := 2;

    SavePictureDialoglTypeChange(Sender) ;

     end;

     end; 

    end;

    end.

    Приведенный пример может послужить толчком, во-первых, к углубленному изучению формата JPEG, а во-вторых, — к модификации стандартных диалогов. На его базе можно создать диалоги открытия аудиозаписей, документов и других специализированных видов файлов.