Skip to Content

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

Для удобства открытия картинок существует пара компонентов-диалогов: 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, которые не являются предками друг друга. В этом случае получившиеся строки нужно соединить, использовав символ конкатенации "|":

  1. S := GraphicFilter(TBitmap)+'|'+
  2.  
  3. 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

  1. unit mainUnit;
  2.  
  3. interface
  4.  
  5. uses
  6.  
  7. Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
  8.  
  9. Dialogs,
  10.  
  11. ExtDlgs, StdCtrls, ComCtrls, ExtCtrls, Buttons;
  12.  
  13. type
  14.  
  15. TForml = class(TForm)
  16.  
  17. SavePictureDialogl: TSavePictureDialog;
  18.  
  19. OpenPictureDialogl: TOpenPictureDialog;
  20.  
  21. ScrollBoxl: TScrollBox; Imagel: TImage;
  22.  
  23. ProgressBari: TProgressBar;
  24.  
  25. OpenBitBtn: TBitBtn;
  26.  
  27. SaveBitBtn: TBitBtn;
  28.  
  29. procedure SavePictureDialoglTypeChange(Sender: TObject);
  30.  
  31. procedure ImagelProgress(Sender: TObject; Stage: TProgressStage;
  32.  
  33. PercentDone: Byte;
  34.  
  35. RedrawNow: Boolean;
  36.  
  37. const R: TRect;
  38.  
  39. const Msg: String);
  40.  
  41. procedure SavePictureDialoglClose(Sender: TObject);
  42.  
  43. procedure FormCreate(Sender: TObject);
  44.  
  45. procedure SavePictureDialoglShow(Sender: TObject);
  46.  
  47. procedure OpenBitBtnClick(Sender: TObject);
  48.  
  49. procedure SaveBitBtnClick(Sender: TObject);
  50.  
  51. private
  52.  
  53. public
  54.  
  55. end;
  56.  
  57. var
  58.  
  59. Forml: TForml;
  60.  
  61. implementation
  62.  
  63. {$R *.DFM}
  64.  
  65. uses jpeg;
  66.  
  67. const DeltaH : Integer = 80;
  68.  
  69. var Quality : TJpegQualityRange;
  70.  
  71. ProgressiveEnc : Boolean;
  72.  
  73. procedure TForml.OpenBitBtnClick(Sender: TObject);
  74.  
  75. begin
  76.  
  77. if OpenPictureDialogl.Execute
  78.  
  79. then Imagel.Picture.LoadFromFile
  80.  
  81. (OpenPictureDialogl.FileName);
  82.  
  83. end;
  84.  
  85. procedure TForml.SaveBitBtnClick(Sender: TObject);
  86.  
  87. var ji : TJpeglmage;
  88.  
  89. begin
  90.  
  91. if SavePictureDialogl.Execute then
  92.  
  93. begin
  94.  
  95. ji := TJpeglmage.Create;
  96.  
  97. ji.CompressionQuality := Quality;
  98.  
  99. ji.ProgressiveEncoding := ProgressiveEnc;
  100.  
  101. j i.Assign(Imagel.Picture.Bitmap);
  102.  
  103. ji.SaveToFile(SavePictureDialogl.FileName);
  104.  
  105. ji.Free;
  106.  
  107. end;
  108.  
  109. end;
  110.  
  111. procedure TForml.SavePictureDialoglTypeChange(Sender: TObject);
  112.  
  113. var ParentHandle:THandle;wRect:TRect;
  114.  
  115. PicPanel,PaintPanel:TPanel;JEdit : TEdit;
  116.  
  117. Expanded : boolean;
  118.  
  119. begin
  120.  
  121. With Sender as TSavePictureDialog do
  122.  
  123. begin
  124.  
  125. PicPanel := (FindComponent('PicturePanel') as TPanel);
  126.  
  127. if not Assigned(PicPanel) then Exit;
  128.  
  129. ParentHandle:=GetParent(Handle);
  130.  
  131. PaintPanel:=(FindComponent('PaintPanel') as TPanel);
  132.  
  133. PaintPanel.Align := alNone;
  134.  
  135. Expanded := FindComponent('JLabel') <> nil;
  136.  
  137. if Filterlndex >1 then begin if not Expanded then
  138.  
  139. begin
  140.  
  141. GetWindowRect(ParentHandle,WRect);
  142.  
  143. SetWindowPos(ParentHandle,0,0,0,
  144.  
  145. WRect.Right-WRect.Left,
  146.  
  147. WRect.Bottom-WRect.Top+DeltaH,
  148.  
  149. SWP_NOMOVE+SWP_NOZORDER);
  150.  
  151. GetWindowRect(Handle,WRect);
  152.  
  153. SetWindowPos(handle,0,0,0,WRect.Right-
  154.  
  155. WRect.Left,
  156.  
  157. WRect.Bottom-WRect.Top+DeltaH,
  158.  
  159. SWP_NOMOVE+SWP_NOZORDER);
  160.  
  161. Expanded:=True;
  162.  
  163. PicPanel.Height := PicPanel.Height+DeltaH;
  164.  
  165. if FindComponent('JLabel')=nil
  166.  
  167. then with TLabel.Create(Sender as TSavePictureDialog) do
  168.  
  169. begin
  170.  
  171. Parent := PicPanel;
  172.  
  173. Name := 'JLabel';
  174.  
  175. Caption := 'Quality';
  176.  
  177. Left := 5;
  178.  
  179. Height := 25;
  180.  
  181. Top := PaintPanel.Top+PaintPanel.Height+5; end;
  182.  
  183. if FindComponent('JEdit')=nil then
  184.  
  185. begin
  186.  
  187. JEdit := TEdit.Create(Sender as TSavePictureDialog);
  188.  
  189. with JEdit do
  190.  
  191. begin
  192.  
  193. Parent := PicPanel;
  194.  
  195. Name:='JEdit';
  196.  
  197. Text := '75';
  198.  
  199. Left:-50;Width := 50;
  200.  
  201. Height := 25;
  202.  
  203. Top := PaintPanel.Top+PaintPanel.Height+5;
  204.  
  205. end;
  206.  
  207. end;
  208.  
  209. if FindComponent('JUpDown')=nil then
  210.  
  211. with TUpDown.Create(Sender as TSavePictureDialog) do
  212.  
  213. begin
  214.  
  215. Parent := PicPanel;
  216.  
  217. Name:='JUpDown';
  218.  
  219. Associate := JEdit;
  220.  
  221. Increment := 5;
  222.  
  223. Min := 1; Max := 100;
  224.  
  225. Position := 75; end;
  226.  
  227. if FindComponent('JCheck')=nil then
  228.  
  229. with TCheckBox.Create(Sender as TSavePictureDialog) do
  230.  
  231. begin
  232.  
  233. Name: = 'JCheck';
  234.  
  235. Caption:='Progressive Encoding'; Parent:=PicPanel;
  236.  
  237. Left:=5;Width := PicPanel.Width - 10; Height:=25;
  238.  
  239. Top := PaintPanel.Top+PaintPanel.Height+35;
  240.  
  241. end;
  242.  
  243. end;
  244.  
  245. end
  246.  
  247. else
  248.  
  249. SavePictureDialoglClose(Sender);
  250.  
  251. end;
  252.  
  253. end;
  254.  
  255. procedure TForml.ImagelProgress(Sender: TObject; Stage: TProgressStage;
  256.  
  257. PercentDone: Byte; RedrawNow: Boolean; const R: TRect;
  258.  
  259. const Msg: String);
  260.  
  261. begin
  262.  
  263. case Stage of psStarting:
  264.  
  265. begin
  266.  
  267. Progressbarl.Position := 0;
  268.  
  269. Progressbarl.Max := 100;
  270.  
  271. end;
  272.  
  273. psEnding: begin
  274.  
  275. Progressbarl.Position := 0;
  276.  
  277. end;
  278.  
  279. psRunning: begin
  280.  
  281. Progressbarl.Position := PercentDone;
  282.  
  283. end;
  284.  
  285. end;
  286.  
  287. end;
  288.  
  289. procedure TForml.SavePictureDialoglClose(Sender: TObject);
  290.  
  291. var PicPanel : TPanel; ParentHandle : THandle; WRect : TRect;
  292.  
  293. begin
  294.  
  295. With Sender as TSavePictureDialog do
  296.  
  297. begin
  298.  
  299. PicPanel := (FindComponent('PicturePanel') as TPanel);
  300.  
  301. if not Assigned(PicPanel) then Exit; ParentHandle:=GetParent(Handle);
  302.  
  303. if ParentHandle=0 then Exit;
  304.  
  305. if FindComponent('JLabel')onil then
  306.  
  307. begin
  308.  
  309. FindComponent('JLabel').Free;
  310.  
  311. FindComponent('JEdit').Free;
  312.  
  313. ProgressiveEnc := (FindComponent('JCheck1') as TCheckBox).Checked; FindComponent('JCheck').Free;
  314.  
  315. Quality := (FindComponent('JUpDown') as TUpDown).Position; FindComponent('JUpDown').Free;
  316.  
  317. PicPanel.Height:=PicPanel.Height-DeltaH;
  318.  
  319. GetWindowRect(Handle,WRect);
  320.  
  321. SetWindowPos(Handle,0,0,0,WRect.Right-WRect.Left, WRect.Bottom-WRect.Top-DeltaH,
  322.  
  323. SWP_NOMOVE+SWP_NOZORDER); GetWindowRect(ParentHandle,WRect);
  324.  
  325. SetWindowPos(ParentHandle,0,0,0,
  326.  
  327. WRect.Right-WRect.Left, WRect.Bottom-WRect.Top-DeltaH,
  328.  
  329. SWP_NOMOVE+SWP_NOZORDER); Filterlndex := 1;
  330.  
  331. end;
  332.  
  333. end;
  334.  
  335. end;
  336.  
  337. procedure TForml.FormCreate(Sender: TObject);
  338.  
  339. var s: string;
  340.  
  341. begin
  342.  
  343. s :=GraphicFilter(TBitmap)+'|'+
  344.  
  345. GraphicFilter(TJpeglmage);
  346.  
  347. OpenPictureDialogl.Filter := s;
  348.  
  349. SavePictureDialogl.Filter := s;
  350.  
  351. end;
  352.  
  353. procedure TForml.SavePictureDialoglShow(Sender: TObject);
  354.  
  355. begin
  356.  
  357. with Sender as TSavePictureDialog do
  358.  
  359. begin
  360.  
  361. if FindComponent('JLabel')Onil then
  362.  
  363. begin
  364.  
  365. FilterIndex := 2;
  366.  
  367. SavePictureDialoglTypeChange(Sender) ;
  368.  
  369. end;
  370.  
  371. end;
  372.  
  373. end;
  374.  
  375. end.

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



Delphi Для профессионалов &1   |    Delphi Для профессионалов &2   |    Delphi Для профессионалов &3   |    Иллюстрированный самоучитель &1   |    Иллюстрированный самоучитель &2