Программирование на Lazarus

Диалоги

Показывать лекцию целиком

Цель лекции

Изучение стандартных диалогов и компонента-контейнера изображений TImage.

Диалоги

В любой большой программе есть диалоги.

Диалоги - это стандартные системные окна, предназначенные для получения информации от пользователя. В Lazarus диалоги - невизуальные (невидимые пользователю) компоненты, работа которых приводит к выводу на экран стандартных диалоговых окон операционной системы.

Информация, которую требуется получить от пользователя, может быть самой разной: какой файл открыть, какой файл создать, куда сохранить, какой выбрать шрифт, цвет, картинку… Можно, конечно, создавать все эти диалоги вручную, но гораздо удобней пользоваться стандартными диалогами - это проще, и эти диалоги используют язык установленной операционной системы. Тем более что от каждого диалога нам с вами потребуется всего пару-тройку свойств, и один метод - легче некуда! Все диалоги находятся на вкладке Dialogs Палитры компонентов.

TOpenDialog и TSaveDialog

Диалоги TOpenDialog и TSaveDialog предназначены, как нетрудно догадаться из их названия, для открытия и сохранения файлов:

(рис 15.1) Компоненты TOpenDialog и TSaveDialog

Изучать работу диалогов мы с вами будем сразу на конкретных примерах. Чтобы не делать лишней работы, воспользуемся проектом MyNotebook из прошлой лекции, который вы должны были сохранить в папку 14-01. Если вы помните, в том проекте для хранения текста мы использовали файл MyText.txt, что не очень удобно - а вдруг пользователю захочется работать со многими файлами, а не только с одним? Вот как раз для этого нам и понадобятся два этих диалога.

Итак, откройте Lazarus. Если у вас открылся новый проект (или предыдущий), закройте его командой Файл -> Закрыть. Далее, командой Файл -> Открыть найдем и откроем проект MyNotebook (для этого нужно указать файл MyNotebook.lpi или MyNotebook.lpr). Обратите внимание: только что мы воспользовались стандартным диалогом открытия файла!

Когда проект с редактором текста откроется, установите в любое место формы по одному компоненту TOpenDialog и TSaveDialog. Эти компоненты будут невидимы для пользователя, поэтому их можно установить в любое место формы, например, прямо поверх Memo1. Выделите компонент TOpenDialog, разберемся с его свойствами. Как видите, их не очень много, да и нужны нам будут не все.

DefaultExt - расширение имени файла по умолчанию. В зависимости от того, с каким типом файлов нам придется работать, такое у них будет и расширение. Если мы работаем с текстом, то лучше именам файлов давать расширение txt. Это необязательно, но так системе проще будет понять, с каким типом файлов ей придется работать. Так, если вы в Проводнике щелкните дважды по нашему прежнему файлу MyText.txt, то откроется стандартный Блокнот Windows, в котором будет загружен текст из этого файла.
FileName - имя файла. Можно сразу же указать имя файла, с адресом и расширением, но обычно это свойство оставляют пустым. После того, как диалог сработает, и пользователь выберет файл для открытия, то в этом свойстве будет и адрес, и имя этого файла. А они нам будут нужны в методе
Memo1.LoadFromFile()
        
Filter - фильтр типов файлов. Здесь можно задать фильтрацию файлов по их типам, используя маску файлов. В маске знак "*" означает любое количество любых символов. Например, в фильтре можно указать маски *.txt, что означает "любой файл с расширением txt", и(или) *.*, что означает "любой файл с любым расширением или без расширения".
InitialDir - папка (директория, каталог), используемая по умолчанию. Здесь указывается адрес папки, с которой диалог начнет свою работу. Заполнять это свойство имеет смысл лишь тогда, когда нужные файлы у вас будут храниться в каком-то одном, конкретном месте. В нашем случае мы не знаем, где пользователю захочется сохранять свои файлы, поэтому заполнять это свойство не нужно.
Name - имя компонента. С этим свойством вы уже знакомы, но тут нужно сделать одно замечание. Помните, в прошлой лекции я говорил, что если компонент один, то его можно не переименовывать? С кнопками этот совет хорош - к кнопкам в коде нам не приходится обращаться по имени. А вот к диалогам придется обращаться неоднократно. Судите сами, что проще будет набрать на клавиатуре:
OpenDialog1.FileName или OD.FileName?
        
Вот то-то. Поэтому совет: переименовывайте диалоги, оставляя лишь заглавные буквы имени. Если вам доведется в одной форме использовать два одинаковых диалога (а мне пока такого делать не доводилось), то можно их назвать OD1 и OD2.
Title - заголовок окна диалога. По умолчанию, он уже содержит нужный текст: "Открыть существующий файл". Если же вам захочется установить какое то свое, нестандартное название, например "Открыть мой текстовый файл", можете вписать его здесь.

Со свойствами разобрались, остался метод. Метод этот - Execute.

Execute вызывает стандартное диалоговое окно, и дает пользователю сделать выбор. Если пользователь сделал свой выбор, то Execute вернет True. Если пользователь отказался делать выбор и закрыл окно, не указав файла, метод вернет False.

Настроим наш TOpenDialog:

  • DefaultExt = .txt
  • Name = OD
  • Теперь займемся фильтром. Выделите свойство Filter и щелкните по кнопке "" справа от него. Откроется редактор фильтров, который мы заполним следующим образом:

    (рис 15.2) Фильтры для TOpenDialog

    Когда вы нажмете "ОК", Lazarus в свойстве Filter сгенерирует следующий фильтр:

    Текстовые файлы|*.txt|Все файлы|*.*
        

    Эту строку можно было бы написать и вручную, но воспользоваться Редактором фильтров все же удобней.

    Теперь, когда мы настроили наш диалог открытия файлов OD, займемся кодом. Если вы помните, то загрузка текста из файла у нас происходила при нажатии кнопки "Читать", то есть, bRead. Щелкните дважды по этой кнопке, и вы попадете на код её события OnClick. Приведу текст этого события:

    procedure TfMain.bReadClick(Sender: TObject);
    begin
      if FileExists('MyText.txt') then
        Memo1.Lines.LoadFromFile('MyText.txt')
      else ShowMessage('Файл MyText.txt не существует');
    end;
        

    Помните, мы вначале проверяли, существует ли этот файл, и затем, в зависимости от результата, предпринимали либо одно, либо другое действие. Так вот, с диалогами этого делать не нужно! Если пользователь выбрал файл, то нет смысла проверять - существует ли он. Конечно, существует, иначе пользователь не смог бы его выбрать. Чувствуете разницу? Новый код события будет таков:

    procedure TfMain.bReadClick(Sender: TObject);
    begin
      if OD.Execute then Memo1.Lines.LoadFromFile(OD.FileName);
    end;
        

    А теперь разница видна? Мы проверяем - если диалог сработал, то мы вызываем метод LoadFromFile, передавая ему в качестве параметра выбранный пользователем файл. Не забывайте, что в свойстве FileName диалога содержится имя выбранного файла вместе с его адресом и расширением. Если же диалог не сработал, то и делать ничего не нужно.

    Теперь займемся диалогом сохранения файла TSaveDialog. А тут нам все уже известно - все свойства и метод Execute у него в точности такие, как и у TOpenDialog, разве что текст в свойстве Title другой. Именно поэтому я и дал эти диалоги парой.

    Измените имя компонента на SD. Свойства DefaultExt и Filter настройте так же, как в OD. Все остальное остается без изменений. Теперь нам нужно вписать код сохранения файла. Делается это в событии OnClick кнопки "Сохранить". Новый код события такой:

    procedure TfMain.bSaveClick(Sender: TObject);
    begin
      if SD.Execute then Memo1.Lines.SaveToFile(SD.FileName);
    end;
        

    Код простой, и должен уже быть вам понятен без всяких комментариев. Сохраните проект и запустите его на выполнение. Посмотрите, как работает сохранение и загрузка файлов. Здесь есть один недостаток, если вы заметили: при сохранении уже открытого файла программа все равно запрашивает, куда сохранять текст. Этот недостаток мы исправим в ближайшей лабораторной работе.

    TColorDialog

    TColorDialog - диалог выбора цвета. Он очень прост. Все, что нам от него нужно, это свойство Color и метод Execute. Если диалог состоялся, то сложное свойство Color будет содержать выбранный пользователем цвет. Этот цвет можно присвоить свойству Color какого-то другого компонента. Например, свойство Color компонента TMemo отображает цвет фона данного компонента. Я, правда, говорил, что не стоит использовать в проекте попугайские расцветки, но наша программа учебная, к тому же мы будем устанавливать только те расцветки, которые выберет пользователь. А потому, установите на форму еще одну кнопку TButton, свойство Name которой переименуйте в bColor, а в свойстве Caption напишите Цвет. Не забудьте снять в свойстве Anchors закрепление к верхнему краю, и установить закрепление к нижнему, как мы делали это с остальными кнопками.

    Далее, нам потребуется установить на форму компонент TColorDialog:

    (рис 15.3) Компонент TColorDialog

    Этот компонент, как и все остальные компоненты, невизуальный, поэтому устанавливайте его, куда хотите. Свойство Name диалога переименуйте в CD. Обработчик OnClick для кнопки bColor очень простой:

    procedure TfMain.bColorClick(Sender: TObject);
    begin
      if CD.Execute then Memo1.Color:= CD.Color;
    end;
        

    Если диалог состоялся, фону редактора присваиваем тот цвет, который выбрал пользователь. Сохраните проект, запустите его и попробуйте менять цвета.

    TFontDialog

    TFontDialog - диалог выбора шрифта. В этом диалоге пользователь может выбрать как сам шрифт, так и его размеры, начертание, эффекты и цвет. Не путайте цвет фона и цвет шрифта! Белый или желтый текст, например, прекрасно читается на синем или черном фоне. Нам потребуется установить на форму один такой компонент:

    (рис 15.4) Компонент TFontDialog

    Свойство Name компонента переименуйте в FD. В коде нам потребуется его сложное свойство Font, которое будет содержать тот шрифт, что выбрал пользователь, и которое мы сможем присвоить свойству Font другого компонента.

    Также нам потребуется кнопка с именем bFont и текстом Шрифт в свойстве Caption. Не забывайте про привязки кнопок к нижней границе формы. Обработчик OnClick для кнопки такой:

    procedure TfMain.bFontClick(Sender: TObject);
    begin
      if FD.Execute then Memo1.Font:= FD.Font;
    end;
        

    TCalendarDialog

    TCalendarDialog - диалог выбора даты. В диалоге пользователь может выбрать дату, которую затем можно будет вставить прямо в текст.

    (рис 15.5) Компонент TCalendarDialog

    Как и обычный календарь, этот диалог имеет свойство Date, которое содержит выбранную пользователем дату в формате TDateTime. Свойство Name диалога предлагаю переименовать в DD (Date Dialog), поскольку CD на форме уже есть, это диалог выбора цвета. Нам потребуется кнопка bDate с надписью Дата в Caption. Код обработчика кнопки следующий:

    procedure TfMain.bDateClick(Sender: TObject);
    begin
      if DD.Execute then Memo1.Lines.Add(DateToStr(DD.Date));
    end;
        

    Не нужно объяснять, что тут мы вставляем в конец текста дату, предварительно преобразовав ее из TDateTime в String?

    TCalculatorDialog

    TCalculatorDialog - диалог-калькулятор. Очень полезен, особенно в бухгалтерских программах. Позволяет пользователю вывести калькулятор, сделать необходимые расчеты, и результат вставить в текст:

    (рис 15.6) Компонент TCalculatorDialog

    У компонента есть свойство Value, которое имеет тип Double, то есть, выводит результат в виде вещественного числа. Переименуйте диалог в CalcD (так как CD уже есть). Для реализации диалога нам также потребуется кнопка bCalc с надписью Считать в Caption. Код кнопки:

    procedure TfMain.bCalcClick(Sender: TObject);
    begin
      if CalcD.Execute then Memo1.Lines.Add(FloatToStr(CalcD.Value));
    end;
        

    Обратите внимание, диалог считается состоявшимся, если пользователь по окончании расчетов нажал на кнопку с "галочкой":

    (рис 15.7) Кнопка завершения диалога TCalculatorDialog

    Только в этом случае событие Execute вернет True, и код выполнится, вставив результат вычислений в текст. Если же пользователь закроет диалог кнопкой с крестиком, клавишами <Alt+F4> или как-то иначе, то диалог не будет выполнен, и результат потеряется.

    В результате всех наших действий, наш редактор должен выглядеть и работать примерно так:

    (рис 15.8) Окончательный вид редактора

    На этом данный проект можете закрыть, он нам больше не понадобится.

    Компонент TImage и диалоги TOpenPictureDialog, TSavePictureDialog

    Последний раздел лекции посвятим работе с графикой, у Lazarus есть и такая возможность. Чтобы не портить наши предыдущие достижения, откроем Lazarus с новым проектом. Как обычно, главную форму назовем fMain, сохраним проект в папку 15-01 под именем MyImageBrowser, а модуль главной формы назовем Main. Сделаем следующие настройки свойств у главной формы:

    Caption = Просмотр изображений
    Height = 450
    Position = poDesktopCenter
    Width = 700
        

    На вкладке Additional Палитры компонентов найдите компонент TImage:

    (рис 15.9) Компонент TImage

    Установите его на форму. Компонент TImage является контейнером для показа изображений - графических файлов. Сам компонент по умолчанию имеет такой же цвет, как форма, а его границы обозначены пунктирной линией. TImage позволяет загружать графические файлы как на этапе проектирования, так и в процессе работы программы. В первом случае изображение считывается, и в дальнейшем становится частью проекта, его ресурсом. Во втором случае изображение не становится частью проекта, оно занимает память с момента его открытия пользователем, и до закрытия программы, либо пока пользователь не загрузит другое изображение. Мы опробуем оба варианта, но для начала настроим положение и размеры компонента. Имя оставим по умолчанию - Image1. Обратим внимание на свойства компонента в Инспекторе объектов.

    AutoSize - автоматический размер. Если равно True, компонент TImage будет подгонять свой размер под реальный размер изображения.
    Center - при значении True выводит изображение по центру компонента.
    Picture - основное свойство, имеет специальный тип TPicture и содержит само изображение. С помощью этого свойства можно загрузить изображение из файла в компонент и во время проектирования, и во время выполнения программы. Можно также сохранить изображение в файл, хотя это имеет смысл только для графических редакторов, позволяющих создавать и изменять изображения.
    Proportional - при значении True изображение будет изменять размеры, сохраняя пропорции изображения - отношение высоты к ширине. Если значение False, то при изменении размеров изображение может быть искажено: чрезмерно вытянуто в длину или в ширину.
    Stretch - при значении True размер изображения будет подстраиваться под размер TImage. Обычно либо картинку подгоняют под размер контейнера, либо контейнер под размер картинки. В первом случае True будет у свойства AutoSize, во втором - у Stretch.
    Transparent - прозрачность. Действует только на битовые матрицы, на файлы с форматом bmp. Применяется, когда нужно спрятать фоновый цвет рисунка. Допустим, в редакторе Paint вы на белом фоне нарисовали синий круг. Сохранили в bmp-файл, который затем загрузили в TImage. Так вот, если Transparent = False, то вы получите картинку, как есть - синий круг в белом прямоугольном фоне. Если же Transparent = True, то фоновый цвет будет заменяться на цвет компонента под TImage, то есть, станет прозрачным. Фоновым считается цвет самого нижнего левого пиксела - если он белый, то этот цвет отображаться не будет.

    Нужными нам методами обладает сложное свойство Picture, которое само является объектом. Подобно массивам строк, свойство Picture имеет такие методы, как LoadFromFile и SaveToFile, хотя последний метод применяется в основном, в графических редакторах.

    Установим следующие свойства компонента Image1:

    Left, Top = 5
    Height = 385
    Width = 690
    AutoSize = False
    Center = True
    Proportional = True
    Stretch = True
        

    Остальные свойства изменять не будем. Попробуем загрузить картинку. Выделите свойство Picture и щелкните по кнопке "" справа от него. Откроется диалог загрузки изображений. Нажав кнопку "Загрузить", вы откроете стандартный диалог "Открыть файл изображений". Здесь вы можете выбрать желаемый файл, просматривая в правой части диалога миниатюрное изображение файла. Выбрав нужный файл, нажмите кнопку "Открыть". Выбранный файл отобразится в Диалоге загрузки изображений, после чего нажмите кнопку "ОК". Выбранное изображение попадет в TImage, причем будет отображено по центру контейнера, сохранит пропорции и подгонит свой размер под размеры контейнера.

    Однако нам не нужен фон для формы, нам нужна программа для просмотра различных изображений, а такая программа загружает картинки по требованию пользователя. Поэтому удалим изображение. Для этого снова выделите Picture и откройте Диалог загрузки изображений. Там нажмите на кнопку "Очистить", после чего нажмите на "ОК". Диалог закроется, контейнер Image1 снова будет пуст.

    Теперь нам нужен диалог открытия графических файлов - TOpenPictureDialog, который находится на вкладке Dialogs Палитры компонентов:

    (рис 15.10) Компонент TOpenPictureDialog

    Подобно другим диалогам, TOpenPictureDialog является невизуальным, его можно установить на любое место, например, прямо посреди Image1. Свойств у него также немного, причем все нужные свойства уже заполнены. Откройте, например, Редактор фильтров в свойстве Filter, и посмотрите на то обилие графических форматов, с которыми вы можете работать! Однако имя диалога слишком длинное, так что переименуем его свойство Name на OPD.

    Также внизу нам понадобится кнопка TButton, которой мы дадим имя bOpen, а в свойстве Caption напишем Загрузить изображение. Чтобы надпись поместилась на кнопке, установите её свойство Width равным 160, или просто растяните кнопку с помощью мыши или кнопкой со стрелкой вправо, удерживая нажатой кнопку <Shift>.

    Давайте воспользуемся примером предыдущего приложения, и подкорректируем свойство Anchors у контейнера и кнопки: Image1 "привяжите" ко всем сторонам формы, чтобы он мог менять размер вместе с формой, а кнопку "отвяжите" от верхней границы и "привяжите" к нижней.

    Сгенерируйте событие OnClick для кнопки, его код:

    procedure TfMain.bOpenClick(Sender: TObject);
    begin
      if OPD.Execute then Image1.Picture.LoadFromFile(OPD.FileName);
    end;
        

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

    (рис 15.11) Программа MyImageBrowser с загруженным изображением и уменьшенным размером

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

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

    Вернуться к учебному плану