Учебное пособие: Учебно-методическое пособие для студентов физико-математических специальностей вузов Балашов
Название: Учебно-методическое пособие для студентов физико-математических специальностей вузов Балашов Раздел: Остальные рефераты Тип: учебное пособие | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Балашовский институт (филиал) ГОУ ВПО «Саратовский государственный университет им. Н. Г. Чернышевского» О. А. Кузнецов Основы программирования Учебно-методическое пособие для студентов физико-математических специальностей вузов Балашов 2009 УДК 004.43 ББК 32.97 К89 Рецензенты: Доктор физико-математических наук, профессор А. Ф. Тараканов; Кандидат педагогических наук, заместитель директора заведующий кафедрой информационных технологий И. А. Седов; Кандидат физико-математических наук, старший преподаватель кафедры им. Н. Г. Чернышевского» А. А. Бубнов. Рекомендовано к изданию Научно-методическим советом Балашовского Кузнецов, О. А. К89 Основы программирования в среде Delphi : учеб.-методич. пособие для студентов физ.-мат. специальностей вузов / О. А. Кузнецов. — Балашов : Николаев, 2009. — 104 с. ISBN 978-5-94035-378-2 В учебно-методическом пособии излагаются основы работы с языком программирования Delphi . Рассматриваются возможности использования различных компонентов при решении практических задач. Издание может быть рекомендовано студентам, специализирующимся в области информатики, и всем, кто интересуется современными способами и методами программирования в операционной среде Windows . УДК 004.43 ББК 32.97 ISBN 978-5-94035-378-2 © Кузнецов О. А., 2009 Предисловие..................................................................................................... 4 Введение........................................................................................................... 6 Лабораторная работа 1. Интегрированная среда разработки........................................................................................................ 7 Лабораторная работа 2. Перенесение программы из Pascal в Delphi ........................................................................................... 17 Лабораторная работа 3. Компоненты ввода и вывода данных................... 23 Лабораторная работа 4. Компоненты-переключатели................................. 32 Лабораторная работа 5. Компоненты-таблицы............................................ 41 Лабораторная работа 6. Окна сообщений и диалоговые окна.................... 45 Лабораторная работа 7. Графические компоненты..................................... 54 Лабораторная работа 8. Компоненты-меню и элементы интерфейса.................................................................................. 66 Лабораторная работа 9. Отображение мультимедийной информации.................................................................................................... 73 Лабораторная работа 10. Исключительные ситуации................................. 84 Лабораторная работа 11. Классы.................................................................. 88 Лабораторная работа 12. Потоки.................................................................. 95 Заключение................................................................................................... 101 Список рекомендуемой литературы........................................................... 102 В государственных образовательных стандартах многих специальностей физико-математического профиля имеется пункт «Языки программирования высокого уровня». Даже если этот пункт отдельно не присутствует в других дисциплинах, предусмотрено изучение объектно-ориентирован-ного или визуального программирования. При этом отдельно не оговаривается, какой именно язык программирования необходимо изучать, из того достаточно большого и разнообразного набора языков, которые популярны в современном мире. Все языки высокого уровня создавались на базе семантики некоторых алгоритмических языков, например, язык программирования Visual Basic имеет семантику и основные способы записи алгоритмических структур языка программирования Basic , Visual Builder имеет в своей основе язык C ++, а язык Delphi имеет семантику языка Pascal . Выбор изучаемого языка высокого уровня зависит от изученного ранее алгоритмического языка. Поскольку язык программирования Pascal был изначально создан Николаусом Виртом для обучения студентов алгоритмическим языкам, язык программирования Delphi является оптимальным языком для получения основных навыков работы с высокоуровневыми языками. Хотя он может показаться достаточно тяжелым при изучении, по сравнению с языком Visual Basic , который допускает «многие вольности» при написании программы, Delphi имеет более жесткую структуру и семантику, усвоение которой и должно формировать основные представления о программировании на языке высокого уровня. Необходимо отметить, что большинство задач решаются на алгоритмическом языке программирования. Именно на изучении основных алгоритмов и необходимо сосредоточить внимание всем, кто имеет желание изучить программирование. Объектно-ориентированное, в частности, язык Delphi , позволяет упростить написание программ в среде Windows . Однако основой составляющей любой программы всегда является алгоритм. Теперь несколько слов о структуре данной книге и основные рекомендации по ее чтению. Данное учебно-методическое пособие состоит из лабораторных работ, которые условно можно разбить на несколько частей. В первой части (лабораторные работы 1, 2) содержатся некоторые начальные сведения. Первая работа посвящена описанию внешнего вида среды программирования, ее основным элементам и способам создания внешнего интерфейса приложения. Во второй лабораторной работе излагаются основы программирования в Windows , демонстрируется примером перевод программы с языка программирования Pascal в среду Delphi (предполагается, что читатель знаком с основами языка Pascal ). Во второй части (лабораторные работы 3—9) изучается возможность работы с визуальными компонентами, систематизированными по видам выполняемой работы. При этом основной упор делается не на перечисление всех свойств и методов, а на приведение конечных примеров использования данных элементов. Третья часть (лабораторные работы 10—12) содержит дополнительные работы, в которых описывается возможность использования более специфических компонентов. Любую книгу по программированию (и также данную) рекомендуется изучать в два этапа. На первом этапе происходит чтение и осмысление некоторой части или всей лабораторной работы. На втором этапе необходимо самостоятельно создать и запустить приложение. И, наконец, автор настойчиво рекомендует выполнять все задания для самостоятельной работы. Именно решение задач самостоятельно позволяет изучить язык В настоящее время имеется огромное количество разнообразной литературы по данному языку программирования. Она отличается как стилем изложения, так и рассматриваемыми темами. В списке литературы приведен только небольшой их перечень. Любая из этих книг может быть полезна либо для ознакомления, либо на последующих этапах для более глубокого, профессионального изучения. Кроме этого существует и большое количество электронных ресурсов, на которых можно найти и скачать подобную литературу, например www.progbook.net/delphi/. В данном курсе лабораторных работ будет изучаться язык программирования Delphi . Не стóит подробно останавливаться на версии (хотя будем ориентироваться на свободно распространяемое программное обеспечение, а именно на систему Turbo Delphi ), поскольку в момент выхода книги может появиться новая версия языка, имеющая большие возможности и более специфические компоненты. Изучим основы визуального программирования на основе компонент, которые появились еще в первых версиях языка. При переходе в программирование из операционной среды Dos в операционную среду Windows необходимо знать некоторые различия. Например, в среде Dos : 1) программный код состоит из операторов, которые выполняются один за другим; 2) в работающей программе постоянно что-то выполняется; 3) одновременно может выполняться только одна программа; 4) существует прямая связь между программой и компьютером, то есть управление осуществляется непосредственно вашей программой. В операционной среде Windows при написании программы необходимо знать следующее: 1) написанный код должен состоять из процедур обработки событий, которые Windows посылает программе; 2) одновременно может выполняться несколько программ; 3) работающая программа находится в рабочей области памяти Среда Delphi , как и всякая современная среда разработки приложений, позволяет создавать программы, отвечающие этим требованиям. Описанию объектно-ориентированного программирования может быть посвящена не одна такая же книга, поэтому отметим только наиболее принципиальное отличие. Преимущество объектно-ориентированных методов программирования заключается в том, что используются предварительно созданные объекты — элементы управления Windows , которые потом могут быть использованы в качестве предков для новых компонентов. Концепция объектно-ориентированного программирования предполагает использование нового типа данных — классов. Класс — это определенный пользователем тип данных, который обладает внутренними данными и методами в форме процедур и функций и обычно описывает родовые признаки и способы поведения ряда очень похожих объектов. Объект является экземпляром класса. Более подробно классы рассматриваются Лабораторная работа 1 . Интегрированная среда разработки Цель: изучить среду программирования Turbo Delphi . Потребность в эффективных средствах разработки программного обеспечения привели к появлению систем программирования, ориентированных на так называемую «быструю разработку». В основе систем быстрой разработки RAD-систем
(Rapid Application Development — среда быстрой разработки приложений
) лежит технология визуального проектирования и событийного программирования, суть которой заключается Turbo Delphi — это среда быстрой разработки от корпорации Borland , в которой в качестве языка программирования используется одноименный язык программирования Delphi , ранее известный как Object Pascal . Версия Turbo Delphi , с которой будем работать, называется Turbo Delphi Explorer — это бесплатно распространяемая версия, имеющая некоторые функциональные ограничения. Для запуска Turbo Delphi необходимо дважды щелкнуть левой клавишей мыши на соответствующем ярлыке либо, нажав на кнопку Пуск , выбрать пункт Программы /Borland Developer Studio 2006 /Turbo Delphi . После запуска появится главное окно среды разработки, в центре которого по умолчанию будет открыта HTML-страница Welcome Page во встроенном интернет-браузере (рис. 1). На ней находятся ссылки на разделы документации и список последних открытых проектов (Recent Projects ). Закройте страницу приветствия и создайте новый проект, выбрав Среда разработки примет вид, представленный на рисунке 3. Данное окно содержит несколько частей, с содержимым которых сейчас и познакомимся. Конструктор форм (3) Центральную часть окна занимает окно конструктора форм
(Form
designer
) приложения. Формой
(Form
) приложения на этапе разработки принято называть окно программы (во время разработки это форма, на этапе выполнения — окно). В окне конструктора форм вы будете формировать внешний вид своего будущего приложения: изменять само окно, Переключаться между этими окнами можно нажатием клавиши F12 (либо нажатием на специальные вкладки Code и Design в нижней части окна). Рисунок 1 Рисунок 2 Рисунок 3 Редактор кода (3) Попробуйте активизировать окно редактора кода. Содержимое вашего экрана вместе с кодом программы будет выглядеть так, как это изображено на рисунке 4. Необходимо отметить, что большая часть работы при создании проекта в среде Delphi сводится к работе с конструктором форм или редактором кода, при этом посредством конструктора создается внешнее окно приложения, а в редакторе прописывается код программы. В центральной части окна теперь располагается исходный код (листинг ) вашей программы. Несмотря на то, что вы сами еще не написали ни единой строчки текста программы, это окно уже содержит код модуля, необходимый для отображения окна приложения. Исходный код содержит заголовок модуля (unit Unit 1 ); интерфейсную часть, начинающуюся со служебного слова interface и содержащую описание одного типа TForm 1 и одной переменной этого типа Form 1 ; реализационную часть, начинающуюся со слова implementation и содержащую большую часть написанного нами программного кода. При закрытии конструктора форм или редактора кода автоматически закрывается и приложение. Рисунок 4 Инспектор объектов (2) Слева от окна конструктора находится окно инспектора объектов (Object Inspector ). Это окно теперь не пустое. Оно заполнилось информацией о выделенном объекте (в данный момент — формы). Окно Object Inspector (рис. 5) имеет две вкладки — Properties (Свойства ) и Events (События ). Первая вкладка используется для редактирования свойств объектов. Свойство (Property ) объекта — это одна из характеристик, определяющая его поведение в программе. Объект способен обладать самыми разными свойствами, которые могут объединяться в группы. Попробуйте, например, изменить свойство Caption , находящееся в группе Visual — это свойство отвечает за заголовок формы. Изначально оно равно Form 1 , измените его на любое другое и нажмите клавишу Enter , сразу увидите, что ваша форма изменилась, теперь она имеет тот заголовок, который вы ввели. Во время выполнения окно вашего приложения будет иметь введенный вами заголовок. Свойство Icon позволяет ассоциировать приложение с некоторой пиктограммой. Поначалу группировка свойств может вызвать затруднения (свойств довольно много у любого объекта и для запоминания основных из них нужно некоторое время), поэтому такую группировку можно отключить. Для этого необходимо навести указатель мыши на окно Object Inspector
Рисунок 5 Рисунок 6 После этого все свойства, которые имеет объект, будут упорядочены по алфавиту. Если вы хотите вернуть окно к первоначальному виду, то следует проделать аналогичные действия и выбрать пункт Arrange /by Category . Каждый компонент обладает своим собственным набором свойств Остановимся на наиболее общих свойствах компонентов. Например, имя компонента задает свойство Name
, свойства, определяющие размеры и положение компонента на форме: Width
— ширина, Height
— высота, Left
— смещение влево, Top
— смещение компонента вниз (изменять Логическое свойство Visible
определяет, будет ли виден данный Также стоит отметить такое свойство формы, как BorderStyle , позволяющее задавать внешний вид окна. Если это свойство, например, установить в значение bsDialog , то при исполнении форма будет содержать на заголовке формы единственную кнопку, которая закрывает приложение. В этом случае при запуске нельзя будет свернуть приложение или изменить его размер. Вторая вкладка окна Object Inspector — Events используется для описания событий (Events ), на которые будет реагировать выделенный объект (в данный момент им является ваша форма). Именно при выборе необходимого вам события в редакторе кода появится заготовка процедуры обработки, где надо записывать код программы. Менеджер проекта (4) В окне менеджера проекта (Project Manager ) отображается структура приложения (проекта, над которым вы сейчас работаете). В этом окне содержится общая информация о проекте, информация об используемых внешних модулях (библиотеках), а также обо всех файлах проекта. Палитра компонентов (5) Палитра компонентов (Tool Palette ) — это один из наиболее часто используемых инструментов Delphi . Она состоит из большого числа групп, где располагаются компоненты. Компонент
(Component
) — это элемент пользовательского интерфейса, который может быть перенесен на форму. Это кнопки, метки, поля для ввода всевозможных данных, выпадающие списки, в общем, все то, что вы обычно видите на окнах в операционной системы Windows
(такие компоненты называют визуальными —
Visual
). Кроме того, это могут быть также и невидимые
(не визуальные
) компоненты, т. е. те, которые Все компоненты объединяются в группы по функциональному назначению. После создания проекта раскрыт список компонентов группы Standard
, содержащий основные элементы диалоговых окон Windows
. Структура проекта (1) Окно структуры проекта после создания проекта отображается в левой верхней части экрана. Оно содержит информацию о структуре исходного кода программы (именно поэтому не содержит информации, если активно окно дизайнера формы). Для того чтобы посмотреть данную информацию, следует переключиться в окно редактора кода. После активизации окна редактора кода окно Structure заполнится информацией (рис. 7). Рисунок 7 Рассмотрим возможность создания первой программы в среде Delphi , которая в данном случае называется проектом. Проект (Project ) — совокупность файлов, используемые средой разработки (точнее говоря, компилятором Turbo Delphi ) для итоговой генерации программы. Вы уже создали новый проект ранее, выбрав в главном меню пункт File , New , VCL Forms Application — Delphi for Win 32 . Turbo Delphi позволяет создавать программы только для операционной системы Windows (отсюда сочетание Delphi for Win 32 ) на основе библиотеки визуальных компонентов Visual Components Library (VCL ). Каждое Windows -приложение выполняется в собственном окне — главном окне соответствующего приложения. Закрытием этого окна пользователь закрывает приложение. При создании проекта создается одна форма — она и является главным окном приложения. Если в проекте несколько форм, то при необходимости можно сделать главным окном любую другую форму. Размеры формы можно менять произвольным образом и размещать Поместите на форму компонента произвольные компоненты с закладки Standard . Обратите внимание, содержимое инспектора объектов будет меняться в зависимости от выбранного компонента (рис. 4). Созданное окно может принять вид, представленный на рисунке 8. Рисунок 8 Если, используя инспектор объектов, добавить процедуру обработки нажатия на кнопку, для чего необходимо выполнить двойной щелчок мышью на требуемом событии (событие onClick для компонента Button 1 ) в инспекторе объектов, то содержимое редактора кода будет иметь вид: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; RadioGroup1: TRadioGroup; Label1: TLabel; CheckBox1: TCheckBox; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin end; end. Из листинга видно, что в рамках формы класса TForm 1 описываются все присутствующие на форме компоненты: Label 11 , Button 1 , CheckBox 1 , RadioGroup 1 , Memo 1 , и заголовок процедуры Button 1 Click . В реализационной части, после служебного слова implementation, создана заготовка для всей процедуры, в которой и будем вписывать необходимый код. Параметр Sender передается в любой процедуре обработки события и определяет компонент формы, где произошло событие. Все события, на которые приложение может реагировать, разделяются на пользовательские и системные. К пользовательским относятся события, связанные с клавиатурой или мышью, например OnClick — одинарный щелчок левой клавишей мыши (именно это событие является наиболее распространенным и именно для его обработки нами была создана процедура в предыдущем примере); OnDblClick — двойной щелчок левой клавишей мыши; OnMouseDown — нажатие клавиши мыши; OnMouseUp — отпускание клавиши мыши; OnMouseMove — перемещение мыши. В некоторых из этих событий в качестве параметров могут передаваться координаты точки на экране, где произошло событие — X , Y , кнопка мыши — параметр Button , значение которого является одна из констант, соответствующей нажатой левой клавиши — mbLeft , средней клавиши — mbMiddle , правой клавиши — mbRight , а также параметр Shift , значение которого равно ssAlt , если нажата клавиша [Alt ], ssCtrl — если клавиша [Ctrl ], ssShift — если клавиша [Shift ]. Например, автоматически созданный шаблон процедуры обработки нажатия клавиши мыши на форме имеет вид: procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin end; Кроме пользовательских событий, существуют программно управляемые события. Отдельно рассмотрим события, обрабатываемые самой формой: событие OnCreat е происходит в момент создания формы; OnClose генерируется, когда форма должна быть закрыта. Два данных события происходят с формой всего один раз в отличие от других: OnShow — возникает, когда форма должна стать видимой, OnHade — когда форма должна быть убрана с экрана, OnPaint — перед тем, как форма будет перерисована на экране. Существуют события, которые формируют сами элементы управления, например: OnEnter событие, которое появляется, когда элемент управления становится активным, и OnExit событие, возникающее, когда элемент управления перестает быть активным. Данные два события существуют только у элементов управления и только в том случае, если свойство Enabled имеет значение True . Остальные события будут рассмотрены по мере описания отдельных компонентов. Запустить проект на исполнение можно либо нажатием кнопки F9, либо через главное меню: Run
/Run
, либо нажатием соответствующей кнопки на панели инструментов: Проект в простейшем случае представляет собой совокупность 1) файл описания проекта (bdsproj-файл ) — файл специального формата, в котором записана общая информация о проекте; 2) главный модуль (dpr-файл ) содержит инструкции, обеспечивающие запуск нашей программы; 3) модуль формы (dfm-файл
) содержит информацию о настройках 4) модуль реализации (pas-файл
) содержит информацию только 5) файл ресурсов (res-файл ); 6) файл конфигурации (cfg-файл ); 7) исполняемый файл (exe -файл ), который создается при запуске программы на исполнение. Сохранение всех файлов проекта осуществляется через пункт главного меню File , Save all (сохранить все). Первый раз при сохранении потребуется сохранить два файла: модуль формы и файл проекта. Поскольку при работе с проектом автоматически создается довольно много файлов, рекомендуется сохранять их в заранее подготовленном каталоге. Задания: 1. Создайте новый проект, поместите на форму компоненты Label 1 , Edit 1 , Button 1 и заготовки процедур таких событий, как создание формы, двойной щелчок левой клавиши мыши на всей форме, активизация компонента Edit . 2. Измените значения свойств Width , Height , Top , Left как с помощью инспектора объектов, так и непосредственно используя мышь. 3. Измените свойства Visible , Color , Cursor , Enabled и Ctl 3 D для каждого компонента в отдельности. 4. С помощью свойств ShowHint и Hint задайте для каждого элемента управления подсказки. 5. Сохраните данный проект и просмотрите каждый из созданных файлов. 6. Запустите приложение на исполнение.
Лабораторная работа 2
.
Перенесение программы
Цель: научиться создавать простейшие программы на языке программирования Delphi . Перед тем, как изучать язык программирования Delphi , рассмотрим вопрос совместимости и переноса программ. Предположим, что имеется программа на языке программирования Pascal , которая на основании введенного значения высоты вычисляет время падения тела. Данная программа имеет вид, представленный на рисунке 9. Рисунок 9 При начальном знакомстве со средой программирования Delphi и программирования в среде Windows необходимо учитывать два момента: во-первых, операторы ввода и вывода данных не работают, поэтому от них необходимо избавиться; во-вторых, для того чтобы были начаты расчеты, необходимо какое-либо событие. Самым простым и распространенным событием является нажатие на экранную кнопку. Поэтому поместим на форму, используя редактор формы, два компонента Button со страницы Standard . Используя свойство Caption , можно задать надпись на кнопках, а посредством свойства Font — шрифт для данной надписи. Напишем на первой кнопки «Вычислить», а на второй — «Закрыть». Теперь создадим два обработчика событий — нажатие клавиши, — для чего в инспекторе объектов на закладке Event
выверим событие OnClick
. В первой процедуре будем выполнять вычисления, а во второй — закрывать форму, используя следующий, заранее определенный метод — Form
1.
Close
. Если правильно записать имя любого компонента, присутствующего на форме, или имя самой формы, то после символа «точка» появится список всех доступных на этапе выполнения свойств и методов. Свойства обозначаются служебным словом property
, методами могут выступать функции и процедуры, и соответственно обозначаются словами procedure
Для ввода начальных данных и вывода конечных результатов могут использоваться различные компоненты. Например, компонент Edit , со страницы компонент Standard . Поместим два этих компонента на форму, которая примет вид, представленный на рисунке 11. Рисунок 10 Рисунок 11 Компонент Edit имеет свойство Text типа String , в нем записывается вводимая или выводимая строка. Данное свойство допустимо как на этапе проектирования (поэтому может быть изменено с помощью инспектора объектов), так и на этапе выполнения, поэтому в программе допустима запись Edit 1 .Text . Для того чтобы иметь возможность вводить и выводить числовые значения, необходимо преобразовать данную строку в число. Для этой цели существуют несколько функций, например: StrToFloat (St :String ): Real — преобразует строку в значение с плавающей запятой; StrToInt (St :String ):Integer — преобразует строку в целое значение; FloatToStr (a :Real ):String — преобразует значение с плавающей запятой в строку; IntToStr (a :Integer ):String — преобразует строку в целое значение. Кроме этих функций, можно использовать уже известную процедуру, которая применяется в языке программирования Pascal . Это процедура Val (St :String ; Var a :Integer ; Var Kod :Integer ), переводящая строку в число. Предположим, что в компоненте Edit 1 вводится начальное значение высоты, а затем, после нажатие кнопки «Вычислить», в компоненте Edit 2 выводится полученное значение. Создадим следующую процедуру обработки события и следующий код обработки нажатия на первую кнопку. Тогда программа будет иметь вид: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; Edit2: TEdit; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); Const g=9.81; Var h,t : Real; Begin h:=StrToFloat(edit1.Text); t:=sqrt(2*h/g); edit2.Text:=FloatToStr(t); end; procedure TForm1.Button2Click(Sender: TObject); begin Form1.Close; end; end. В процедуре описываются две дополнительных переменных и одна константа. Первым оператором переводится значение соответствующего свойства в вещественную переменную, затем производятся вычисления по известной формуле, и последним оператором выводится полученное значение (данная запись аналогична оператору вывода Writeln ). Рисунок 12 При запуске данной программы на исполнение в поле Edit 1 необходимо ввести соответствующее значение высоты, затем нажать клавишу «Выполнить» и в поле Edit 2 будет выведен результат вычислений. Вычисления можно производить для различных значений высоты. Для того чтобы завершить работу программы необходимо нажать клавишу «Закрыть». Компонент Edit может в определенной мере заменить операторы ввода — вывода, но не является совсем удобным для вывода подсказок и сообщений. Для этой цели может быть использован компонент Label , позволяющий выводить не редактируемый текст. Разместим два данных компонента на форме и свойству Caption одной из них дадим значение «Высота падения (м)», а второй — «Время падения (с)», после чего форма примет вид, изображенный на рисунке 12. Компоненты, размещенные на форме с заданными начальными свойствами посредством инспектора объектов, а также текст соответствующего модуля и самого проекта, представляют собой программу на языке программирования Delphi . Чтобы при запуске программы не отображался в компонентах Edit текст «Edit 1 », «Edit 2 » сделайте «пустым» значение свойства Text у данных компонентов. Замечание. Редактор кода оснащен набором свойств, обеспечивающих выполнение целого ряда вспомогательных функций. Эти средства имеют общее название Code Insight — интуитивный помощник написания кода. Посредством функции дополнительного кода могут быть легко введены имена свойств, методов и обработчика событий объектов. Сначала необходимо ввести имя объекта, поставив в конце точку, и после некоторой паузы на экране отобразится список всех свойств и методов данного объекта (рисунок 11). Кроме этого, если правильно записать имя функции или процедуры и открытую скобку, то появится подсказка относительно аргументов и их типов. Комбинация клавиш <CTRL> + J приведет к появлению окна, в котором перечисляются все возможные структуры. Выбрав любой элемент, появится заготовка с перечислением необходимых для заполнения полей. Аналогичная заготовка появится при записи первого слова из данной конструкции, например, слова if или for . Если вам не нравится, что при запуске форма расположена там, где вы ее оставили при разработке, то обратитесь у формы к свойству Position . Задания : 1. Выполните пример, описанный в лабораторной работе. 2. Реализуйте на языке программирования Delphi задачи из лабораторных работ 1, 2, 3 по языку Pascal . 3. Напишите программу «Калькулятор». Лабораторная работа 3 . Компоненты ввода и вывода данных Цель: изучить компоненты ввода и отображение текстовой информации. Рассмотрим более подробно компоненты ввода — вывода данных, для чего условно разделим их на несколько различных блоков: 1) компоненты вывода текстовой информации на экран; 2) однострочные поля ввода текстовой и числовой информации; 3) многострочные поля ввода. Для вывода определенной информации на экран, кроме уже описанного компонента Label
, есть и другие компоненты. Текст, который будет отображен, можно задавать как на этапе разработки формы, так и в процессе выполнения программы, присвоив значение свойству Caption
. Таблица 1. Основные свойства компонента Label
Отдельно рассмотрим свойство Font
класса TFont
, определяющее шрифт. При выборе данного свойства на этапе проектирования проявляется диалоговое окно, в котором непосредственно задаются характеристики шрифта: стиль, размер и цвет. На этапе выполнения доступ к элементам шрифта осуществляется с помощью свойств класса TFont
: Color
— цвет шрифта, Height
и Size
высота шрифта, заданного либо в пикселях, либо Свойство Label 1. Color задает цвет самого компонента, а свойство Label 1. Font . Color — цвет, который используется для надписи внутри данного компонента. Рассмотрим несколько простых примеров использования данных компонентов. Пример 1 При нажатии на кнопку, на экране выдается, а затем при повторном нажатии исчезает некоторое сообщение, например «Моя первая программа на языке Delphi ». При повторном выводе размер надписи должен увеличиваться. Для этого поместим на форме компонент Label и кнопку Button . Затем определим соответствующее значение свойства Caption и создадим процедуру обработки нажатия кнопки, которая имеет следующий вид: procedure TForm1.Button1Click(Sender: TObject); begin label1.Visible:=not label1.Visible; if label1.Visible then label1.Font.Size:=label1.Font.Size+1; end; В этой программе при каждом очередном нажатии происходит изменение свойства Visible , вследствие чего надпись то появляется, то исчезает с экрана, а также происходит увеличение свойства Size . Для вывода определенной информации на экран, кроме уже описанного компонента Label
, может быть также использован компонент Panel
с той же самой закладки или StaticText
со страницы Additional
. Они имеют Остальные компоненты позволяют вводить и редактировать информацию, включая возможность выделения, копирования, удаления и вставки фрагментов текста. Отметим общие для всех редакторов методы: Clear — удалить весь текст, помещенный в редакторе; ClearSelect — удалить выделенный фрагмент текста; CopyToClipboard — копировать в буфер выделенных фрагмент, CutToClipboard — удалить из текста выделенный фрагмент и поместить его в буфер, PasteFromClipboard — копировать текст из буфера в то место редактора, где в данный момент находится курсор. Для всех редакторов определено дополнительное событие OnChange , возникающее, когда изменяется текст, находящийся в редакторе. Для ввода или вывода одной строки могут использоваться компоненты Edit со страницы Standart и MaskEdit со страницы Additional . Основное свойство данных компонентов — это строка, которая либо вводится, либо выводится. Данное свойство имеет имя Text и тип String , доступное как во время подготовки, так и время выполнения. Логическое свойство ReadOnly позволяет запретить изменения, а целочисленное свойство GetTextLen выдает текущую длину строки. Пример 2 Сделать так, чтобы при вводе текста в первом компоненте Edit , во втором отображалась реальная длина вводимой строки. Кроме этого, при выходе из компонента Edit 1 его содержимое копировалось в буфер и удалялось, а при возвращении появлялось снова. В данном случае будем использовать три события, а именно OnChange , OnEnter и OnExit . Тогда программа будет иметь следующий вид: procedure TForm1.Edit1Change(Sender: TObject); begin edit2.Text:= IntToStr(edit1.GetTextLen); end; procedure TForm1.Edit1Enter(Sender: TObject); begin edit1.PasteFromClipboard; end; procedure TForm1.Edit1Exit(Sender: TObject); begin edit1.SelectAll; edit1.CopyToClipboard; edit1.Clear; end; Событие клавиатуры возникает только в том случае, если нажата или отпущена произвольная клавиша. Имеет значение, была ли нажата клавиша с управляющим символом или с читаемым символом, поэтому имеются несколько различных событий. Событие OnKeyPress происходит лишь при нажатии клавиши, с которой связан читаемый символ, а событие OnKeyDown и OnKeyUp вызываются при нажатии или отпускании произвольной клавиши клавиатуры. Во всех этих событиях присутствует параметр — переменная Key , в которой после события помещается код нажатой клавиши, а также параметр Shift . Пример 3 Сделать так, чтобы в Edit нельзя было вводить подряд два одинаковых символа. Поместим на форму компонент Edit и опишем глобальную переменную ch типа char , в которой будет храниться последний нажатый символ. Затем создаем процедуру обработки события KeyPress
, где параметр Key
типа char
содержит символ нажатой клавиши. Если вновь введенный символ совпадает с только что нажатым символом, то он игнорируется. Var ch:char; procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char); begin if ch=key then key:=#0 else ch:=key; end; Пример 4 Написать программу, которая считает количество нажатий на кнопку и выдает это значение в компоненте Edit . Для решения данной задачи поместим на форму компоненты Button
(кнопка, количество нажатий на которую будем считать) и Edit
(строка, procedure TForm1.Button1Click(Sender: TObject); begin i:=i+1; Edit1.Text:=IntToStr(i); end; Однако остается вопрос, где описывать данную переменную i . Если сделать это внутри данной процедуры, то также необходимо осуществлять обнуление переменной, а это приведет к получению одного и того результата, равного единице. Следовательно, переменная i должна быть глобальной в модуле, а ее начальная инициализация должна происходить в процедуре, которая выполняется всего один раз, и всего один раз происходит это событие. Таким событием создание формы OnCreat произойдет один раз и процедура FormCreate (Sender :TObject ) будет вызвана всего один раз. Следовательно, описание переменной и процедур обработки событий в реализационной части будет иметь вид: Var i:integer; procedure TForm1.FormCreate(Sender: TObject); begin i:=0; end; procedure TForm1.Button1Click(Sender: TObject); begin i:=i+1; Edit1.Text:=IntToStr(i); end; При возникновении необходимости сделать данную переменную i
общедоступной, можно поместить описание переменной в интерфейсной части модуля после служебного слова public
. Именно так, как правило, type TForm1 = class(TForm) Button1: TButton; Edit1: TEdit; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public i:integer; { Public declarations } end; В программе для обращения к переменной i необходимо писать ее полное имя Form 1 .i . Однако код процедур обработки событий можно и не переписывать, поскольку процедуры обработки описаны непосредственно в формы, а следовательно, данное числовое поле доступно непосредственно. Данную программу можно легко модифицировать так, чтобы после определенного количества нажатий появлялось некоторое сообщение или кнопка блокировалась, или приложение автоматически закрывалось. Результат можно отображать не только посредством компонента Edit
, но Свойству Visible
компонента Label
присваиваем False
, т. е. при открытии формы надпись отражаться не будет. Затем, как и ранее, при нажатии на кнопку переменная i
увеличивается на 1. Когда значение переменной i
будет равно 10, 20, 30 или 40 компонент Label
становится видимым, implementation {$R *.dfm} Var i:Integer; procedure TForm1.FormCreate(Sender: TObject); begin i:=0; end; procedure TForm1.Button1Click(Sender: TObject); begin Label1.Visible:=False; i:=i+1; if (i=10)or(i=20)or(i=30)or(i=40) then Begin Label1.Visible:=True; Label1.Caption:='Вы нажали '+intToStr(i)+'раз'; end; if i=50 then Begin Label1.Visible:=True; Label1.Caption:='Вы нажали УЖЕ'+intToStr(i)+'раз'; Button1.Enabled:=False; end; end; В отличие от компонента Edit компонент MaskEdit , обладая теми же возможностями редактирования, позволяет определять маску, на основании которой будет осуществляться ввод информации. Маска редактируется с помощью пункта EditMask инспектора объектов, выбор которого приводит к появлению диалогового окна (рис. 13). Можно выбрать любой имеющийся шаблон ввода текстовой информации или создать собственный. На этапе выполнения вводимый текст должен отвечать этому шаблону. Рисунок 13 Компонент LabeledEdit отличается от компонента Edit только тем, что имеет привязанный к нему компонент Label , свойства которого содержатся в раскрывающейся вкладке EditLabel . Свойство LabelPosition отвечает за расположение Label относительно Edit , а свойство LabelSpacing — за количество пробелов, разделяющих Edit , и прикрепленный к нему Label . Оба компонента находятся на закладке Addition . Для ввода целых чисел стандартных компонентов нет, однако имеется возможность самим сконструировать компонент. Для этого необходимо на форму поместить компонент Edit
и компонент UpDown
со страницы Win
32
, а затем свойству Associate
данного компонента придать значение Edit
1
. После выполнения этой операции компоненты будут связываться между собой, при выполнении программы — располагаться рядом. Основные свойства компонента UpDown
: Min
— минимальное и Max
— максимальное значения. Если последние свойства имеют значение 0, то число, задаваемое в компоненте, не имеет ограничений. Свойство Increment
определяет, на сколько будет изменяться значение при каждом Для ввода или вывода нескольких строк могут использоваться компоненты Memo со страницы Standard и RichEdit со страницы Win 32 (полный текстовый редактор для RTF -файлов). Многие свойства у данных компонентов аналогичны свойствам компонента Edit , однако для возможности доступа к строкам вместо свойства Text имеется свойство Lines , при выборе которого во время проектирования задается начальное значение строк с помощью следующего диалогового окна, представленного на рисунке 14. Во время исполнения данное свойство представляет собой указатель на содержимое окна. Рисунок 14 Для доступа к строкам во время выполнения программы также используется свойство Lines
класса TString
. Подробнее остановимся на классе TString
, с которым в последствии мы будем еще встречаться. Класс TString обладает также рядом методов, среди которых отметим следующие: Add (St : String ): integer добавляет строку St и возвращает номер этой строки; Delete (Index : Integer ) удаляет строку с номером Index ; Insert (Index : Integer , St : String ) вставляет строку с номером Index , Clear полностью уничтожает все содержимое компонента. Все содержимое компонента можно записать в файл с помощью метода SaveToFile или прочитать из файла посредством методом LoadFromFile. Аналогичным образом можно поступить и с потоком, направив в него весь файл, или прочитать файл из потока. Важным свойством компонентов Memo и RichEdit является ScrollBar , которое определяет, будет ли окно содержать горизонтальные или вертикальные линейки прокрутки. Пример 5 Задается текст в компоненте Memo1
и номер строки в компоненте Edit1
. Необходимо вырезать строку с данным номером и поместить ее Для решения данной задачи поместим все необходимые компоненты на форму и напишем процедуру обработки события, в которой задается значение компонента Edit 2 и удаляется строка из Memo 1 : procedure TForm1.Button1Click(Sender: TObject); begin Edit2.Text:=memo1.Lines[strToInt(edit1.Text)-1]; memo1.Lines.Delete(strToInt(edit1.Text)-1); end; Пример 6 Cохранить набранный в Memo файл с именем, определенным в Edit . Для решения данной задачи поместим на форму компонент Memo
1
, Рисунок 15 Процедура обработки события будет состоять из одной строки, и соответственно, листинг будет иметь следующий вид: procedure TForm1.Button1Click(Sender: TObject); begin Memo1.Lines.SaveToFile(Edit1.Text); end; Компонент RichEdit обладает всеми характеристиками, присущими компоненту Memo , однако имеет богатые возможности для работы с текстовым форматом RTF . Данный формат предполагает возможность разбивать текст на параграфы. Для этого существуют специальные свойства: SelAttributes определяет атрибуты выделенного фрагмента и Paragraph — атрибуты абзаца. Задания : 1. Проверьте все программы из данной лабораторной работы и выполните задание, которое соответствует номеру вашего варианта. 2. Создайте приложение, в котором при нажатии на одну из кнопок 3. Сделайте компонент Edit таким образом, чтобы в него можно было бы вводить только цифры. 4. Создайте приложение, в котором при наборе текста в компоненте Edit в момент нажатия буквы t все содержимое данной строки добавляется новой строкой в компонент Memo . 5. Создайте приложение, в котором в строку вводится буква я , выдается некоторое сообщение. Лабораторная работа 4 . Компоненты-переключатели Цель: изучить компоненты выбора переключения с зависимой и независимой фиксацией. Для организации ветвления в языке программирования Pascal используются два оператора: оператор ветвления If …then и оператор выбора Case . Выбор конкретной ветви алгоритма может осуществляться несколькими различными способами. Можно программно анализировать полученные ранее данные, однако в реальном программировании часто встречается ситуация, когда дальнейшие действия должны зависеть от выбора пользователя. Именно для таких ситуаций существует множество компонентов, которые позволяют визуально выбирать некоторый способ продолжения выполнения программы. Эти компоненты будем условно называть переключателями. Существуют два принципиально различных вида переключателей, это, во-первых, те, которые могут принимать единственное значение из предлагаемого набора (иногда они называются переключателями с зависимой фиксацией) и, во-вторых, переключатели, которые в любой момент времени могут быть либо включены, либо выключены (по аналогии они называются переключателями с независимой фиксацией или включателями). Рассмотрим первый тип переключателей. Изображаются они в виде небольшого кружка. У выделенного переключателя внутри этого кружка помещается черная точка. К переключателям относятся компоненты: RadioButton — выбор из одной альтернативы, RadioGroup — выбор из набора альтернатив, ComboBox — выбор из комбинированного списка, который переключателем как таковым не является, но может выполнять подобные функции. Все эти компоненты находятся на странице Standat . Первый компонент RadioButton позволяет выбирать из одной альтернативы, поэтому на этапе выполнения существует ключевое свойство Checked , которое принимает значение True , если данная альтернатива выбрана, и False — в противном случае. С помощью этого свойства на этапе выполнения можно проверять состояние переключателя. Однако выбор из одной альтернативы не является выбором как таковым, поэтому либо группируют несколько подобных компонентов, либо используют другие компоненты. Рассмотрим компонент RadioGroup . На этапе подготовки, пользуясь инспектором объектов, можно редактировать альтернативы с помощью свойства Items класса TString . При выборе данного свойства появляется редактор, где можно перечислять все возможные варианты действий. Данный редактор « String list edit » аналогичен тому, который появляется при выборе свойства Lines компонента Memo . Используя свойство Columns , можно задать число столбцов, где будут помещены выбираемые альтернативы. На этапе выполнения с помощью свойства ItemIndex
можно определить номер выбранной альтернативы, при этом нумерация начинается с 0. Если ни одна альтернатива не выбрана, то данное свойство принимает значение равное –1. Выбор начальной альтернативы можно установить Событие OnClick возникает в тот момент, когда выбирается другой вариант. Приведем пример, использующий компонент RadioGroup . Пример 1 Вычислить время падения с некоторой высоты при условии, что высота может задаваться в метрах, сантиметрах и дюймах. Задача уже была решена раньше, однако не учитывалась возможность ввода данных различного типа. Для решения этой задачи, кроме ранее используемых компонентов, поместим на форму компонент RadioGroup
После выполнения данных операций форма будет иметь вид, представленный на рисунке 16. Рисунок 16 Как и раньше, будем анализировать нажатие на кнопку «Вычислить», но в расчетах учтем выбор соответствующей единицы измерения. Тогда процедура может иметь вид: procedure TForm1.Button1Click(Sender: TObject); Const g=9.81; Var h,t : Real; Begin h:=StrToFloat(edit1.Text); Case radioGroup1.ItemIndex of 0: t:=sqrt(2*h/g); {Высота задается в метрах} 1: t:=sqrt(2*h/100/g); {Высота задается в сантиметрах} 2: t:=sqrt(2*h*2.54/100/g); {Высота задается в дюймах} End; edit2.Text:=FloatToStr(t); end; Недостаток компонента RadioGroup заключается в том, что имеется возможность определить только номер выбранной альтернативы, а не ее текстовое содержание. Для того чтобы определить и текстовое содержание альтернативы, можно использовать комбинированную строку, компонент ComboBox . Комбинированная строка ввода объединяет в себе свойство строки и списка. В обычном состоянии она имеет вид строки Edit со стоящей рядом кнопкой с изображением направленной вниз стрелки. Если нажать эту кнопку, то появится список строк, где можно выбрать произвольную. Данный компонент имеет свойство Items , поэтому задание альтернатив, которые в данном случае будут раскрывающимся списком, происходит аналогичным образом. Однако на этапе выполнения допустимо свойство Text , в котором находится выбранная из списка строка. При работе с данным компонентом необходимо различать свойства ComboBox . Items . Text и ComboBox . Text . Если первое — это свойство, где находятся все строки списка, включая разделители (это свойство имеет подобный смысл и для RadioGroup ), то второе содержит выбранную из списка строку. Если в предыдущем примере использовать компоненты ComboBox
Рисунок 17 Процедура обработки будет: procedure TForm1.Button1Click(Sender: TObject); Const g=9.81; Var h,t : Real; Begin h:=StrToFloat(edit1.Text); if ComboBox1.Text='метры' then t:=sqrt(2*h/g); {Высота задается в метрах} if ComboBox1.Text='сантиметры' then t:=sqrt(2*h/100/g); {Высота задается в сантиметрах} if ComboBox1.Text='дюймы' then t:=sqrt(2*h*2.54/100/g); {Высота задается в дюймах} edit2.Text:=FloatToStr(t); end; Выбор между компонентами RadioGroup и ComboBox во многом зависит от вкусов программистов, поскольку они выполняют одинаковую роль, а имеют различные внешний вид и применение. Необходимо отметить, что в языке Delphi есть большое количество компонентов, имеющих одинаковую область применения, однако отличающихся некоторыми частными внешними особенностями и доступными для применения методами. Рассмотрим пример. Пример 2 (психологический тест) Пусть имеется заданный набор из n , заранее фиксированного числа вопросов. На каждый из вопросов может быть выбран один из трех ответов: «да», «нет», «не знаю». После ответов на все вопросы должен выдаваться результат. Предположим, что необходимо выдавать только количество первых, вторых и третьих ответов, хотя в реальных тестах, как правило, происходит подсчет баллов, на основании некоторого принципа. Для решения данной задачи поместим на форму компонент Edit , в котором будет выдаваться очередной вопрос, а следовательно, свойству ReadOnly придадим значение True . Компонент RadioGroup служит для задания вариантов ответов, которые в данном случае будут «да», «нет», «не знаю», при этом начальное значение свойства ItemIndex должно быть равно единицы. Компонент Label 1 будет необходим для выдачи результатов тестирования. В модуле опишем константу n
для задания количества вопросов и целочисленные переменные i
, i
1
, i
2
, i
3
, в первой из которых будет содержаться номер вопроса, а в остальных — количество ответов каждого В данной задаче нельзя воспользоваться событием OnClick
для самого компонента RadioGroup
, поскольку не всегда на следующий вопрос будет выбираться другой ответ. Следовательно, на форму необходимо поместить два компонента Button
. При нажатии на первую кнопку происходит начало тестирования, т. е. обнуляются соответствующие переменные, Рисунок 18 В модуле опишем дополнительную функцию, которая на основании целочисленного значения формировала соответствующий вопрос. Для создания реального теста эту функцию необходимо доработать в соответствии со способом задания вопросов, например, вопросы можно читать из файла. Тогда программа может иметь вид: Const n=5; Var i,i1,i2,i3:Integer; function Query(i:integer):String ; begin Query:='Вопрос'+IntToStr(i);{Функция формирования очередного вопроса} end; procedure TForm1.FormCreate(Sender: TObject); begin i:=1; Edit1.Text:=Query(1) end; procedure TForm1.Button1Click(Sender: TObject); begin i:=1; i1:=0; i2:=0; i3:=0; Edit1.Text:=Query(1); Label1.Caption:=''; end; procedure TForm1.Button2Click(Sender: TObject); begin i:=i+1; Case RadioGroup1.ItemIndex of 0:i1:=i1+1; 1:i2:=i2+1; 2:i3:=i3+1; end; if i<=n then Edit1.Text:=Query(i) else begin Label1.Caption:=' " Да" '+IntToStr(i1)+ ' "Нет" '+IntToStr(i2)+ ' "Не знаю" '+IntToStr(i3); Label1.Visible:=True; end; end; Переключатель с независимой фиксацией (выключатель) предназначен для задания одного из двух (трех) состояний. Во включенном состоянии К ним можно отнести компоненты CheckBox со страницы Standat, CheckListBox со страницы Additional и компонент ListBox , который может выполнять функции переключателя. Основное свойство AllowGrayed определяет, может ли опция находиться в двух или трех состояниях (включена, выключена и включена частично). В случае, если опция может находиться в двух различных состояниях, логическое свойство Checked определяет, выбрана или нет данная опция. Если имеются три различных варианта, необходимо применять свойство State , значение которого может быть cbUnChecked — опция выключена, cbChecked — опция включена, cbGrayed — опция включена, однако изображается серым цветом. Пример 3 Необходимо на основании курса подсчитать, сколько лет еще необходимо учиться. Для решения данной задачи поместим на экран компонент CheckBox
, свойству AllowGrayed
придадим значение True
. В этом случае данный компонент может имееть три состояния, что соответствует трем возможным вариантам ответа: включена — имеется высшее образование, выключена — нет высшего образования, частично включена — неполное высшее. Поместим на форме компонент RadioGroup
, в котором посредством свойства Item
зададим возможные варианты курсов: первый, второй Проанализируем два различных события: нажатие на компоненты CheckBox
1
и RadioGroup
1
. При первом событии происходит анализ его состояния, если он включен частично, то на экран выводится группа переключателей, во всех других случаях данную группу убираем с экрана, Вся программа может иметь следующий вид: procedure TForm1.CheckBox1Click(Sender: TObject); begin If CheckBox1.State=cbGrayed Then begin RadioGroup1.Visible:=True; RadioGroup1.ItemIndex:=-1; Label1.Caption:=’’ end Else begin RadioGroup1.Visible:=False; If CheckBox1.State=cbChecked Then Label1.Caption:=’Есть высшее образование’ Else Label1.Caption:=’Нет высшего образования’ end; end; procedure TForm1.RadioGroup1Click(Sender: TObject); begin Label1.Caption:=’Еще учиться’+IntToStr(5-RadioGroup1.ItemIndex) end; Рассмотрим компоненты, которые могут задавать несколько опций, Пример 4 Выбрать все отмеченные опции из компонента CheckListBox в Memo . Данную задачу можно интерпретировать как составление счета, при условии, что список опций — это меню. Поместим на экран компонент CheckListBox
, в нем с помощью пункта Item
зададим начальные опции (пункты, которые могут быть выбраны). procedure TForm1.Button1Click(Sender: TObject); Var i:Integer; begin Memo1.Lines.Clear; for i:=0 to CheckListBox1.Items.Count-1 do begin If CheckListBox1.Checked[i] then Memo1.Lines.Add(CheckListBox1.Items.Strings[i]); end; end; Компонент ListBox предназначен для отображения на экране списка строк и в отличие от компонента CheckListBox , позволяющего включать или выключать опции, помогает выбирать некоторые строки из списка. На этапе проектирования, кроме свойства Item , рассмотрим два логических свойства MultiSelect и EnternetSelect . Если первое свойство имеет значение True , то можно выделять несколько строк, в противном случае выделяется только одна строка. Второе свойство определяет способ выделения строк. Если оно имеет значение True , то выбор нескольких рядом стоящих строк осуществляется с помощью клавиши Shift , а не рядом стоящих строк посредством клавиши Ctrl . Для проверки выбранных строк на этапе выполнения может использоваться целочисленное свойство ItemIndex , задающий номер единственной выбранной строки и логическое свойство Selected [Index ], принимающее значение True , если соответствующая строка выбрана. Задания: 1. Проверьте все примеры из лабораторной работы. 2. Доработайте пример 3 таким образом, чтобы имелась возможность вернуться на один вопрос назад. 3. Задана компонента ComboBox , в свойстве Items записаны различные цвета. Сделайте, чтобы при выборе определенного цвета, изменялся цвет формы. Данную задачу выполните и с RadioGroup . Лабораторная работа 5 . Компоненты -таблицы Цель: изучить возможности обработки табличной информации, используя компоненты StringGrid и DrawGrid . Для обработки табличных данных предусмотрены компоненты StringGrid , представляющий собой таблицу строк, и DrawGrid , являющийся таблицей более общего назначения, в ячейках которого может храниться произвольная информация произвольной природы, например, текст, числа, рисунок и т. д. Оба компонента находятся на странице Additional . Компоненты таблицы имеют форму и функциональные возможности электронных таблиц. В компоненте DrawGrid
можно отображать какие-либо данные (числа, рисунки, пиктограммы) в форме таблиц. Кроме того, имеется возможность редактировать данные в каждой ячейке по отдельности. С помощью компонента StringGrid
можно обрабатывать строки С помощью инспектора объектов в свойстве ColCount
можно определить количество строк, а в свойстве RowCount
задать количество столбцов. Свойства DefaulColWidth
и DefaulRowWidth
задают ширину всех строк и высоту всех столбцов. Свойство ScrollBar
является логическим Каждая таблица должна иметь ячейки, в которых будет выводиться служебная информация, постоянно находящаяся на экране, даже если применяются линейки прокрутки. Поэтому существуют свойства FixedCol , FixedRows и FixedColor , задающие количество фиксированных строк и столбцов таблицы, их цвет (по умолчанию FixedCol = 1 и FixedRows = 1). Любая таблица должна иметь хотя бы одну строку и один столбец подобных ячеек. Необходимо помнить, что нумерация и строк, и столбцов начинается с нуля. Поэтому, если оставить одну фиксированную строку и столбец, нумерация, доступная для редактирования, будет начинаться с 1. Рисунок 19 С помощью составного свойства Options можно задать флаги, определяющие поведение таблицы. Среди них отметим следующие: goEditing — показывает, может ли редактироваться содержимое ячеек, goAlweysShowEditing — определяет, становится ли выделенная ячейка сразу и активной (в противном случае ячейка активизируется либо нажатием клавиши F2, либо двойным щелчком мыши, либо нажатием произвольной символьной клавиши). На рисунке 19 изображена форма с компонентом StringGrid . Большинство описанных свойств представлены в инспекторе объектов. Следует знать в виду, что в силу своей универсальности таблица типа DrawGrid не имеет конкретного средства отображения реальных изображений в ячейках таблицы и для каждого нового вида изображений необходимо создавать свои средства, поэтому остановимся более подробно на таблице типа StringGrid . Для доступа к ячейкам таблицы на этапе выполнения программы можно воспользоваться свойствами Cells [ACol , ARow ], Cols [ACol ], Rows [ARow ]. Cells
[ACol
,
ARow
] определяет ячейку, находящуюся в столбце ACol
Cols [ACol ] определяет колонку; Rows [ARow ] определяет строку. Значения целочисленных свойств Col и Row , допустимых только во время выполнения, указывают на активную в данный момент ячейку, строку или столбец. При работе с таблицами дополнительно обрабатываются события, связанные с изменениями в ячейках. Замечание. На этапе проектирования заполнять таблицу начальными данными нельзя. Пример 1 Заполнить таблицу произвольного размера произвольными числами. Поместим на форму компонент StringGrid , где будем располагать числа; два компонента Edit , в которых будут вводиться размеры таблицы; кнопку Button, при нажатии на нее произойдет заполнение таблицы. Тогда процедура будет иметь следующий вид: procedure TForm1.Button1Click(Sender: TObject); var i,j:Integer; begin with StringGrid1 do begin ColCount:=StrToInt(Edit1.Text)+1; RowCount:= StrToInt(Edit1.Text)+1; for i :=1 to ColCount do for j:=1 to RowCount do Cells[i,j]:=IntToStr(50-Random(100)); end; end; Пример 2 В числовой таблице, заданной произвольным образом, подсчитать количество отрицательных значений в каждой строке и в дополнительном столбце. procedure TForm1.Button2Click(Sender: TObject); var i,j,k:Integer; begin with StringGrid1 do begin ColCount:= StrToInt(Edit1.Text)+2; for i:=1 to RowCount-1 do begin k:=0; for j:=1 to ColCount-2 do If StrToInt(Cells[j,i])<0 Then k:=k+1; Cells[ColCount-1,i]:=IntToStr(k); end; end; end; При использовании компонента DrawGrid элементом каждой ячейки является рисунок класса TRect , возможности обработки которого будут продемонстрированы нами в лабораторной работе 7 при изучении графических возможностей. При работе с компонентом StringGrid
имеется один досадный факт, Procedure SaveGrid; var f:textfile; x,y:integer; Begin assignfile (f,’Filename’); rewrite (f); writeln (f, StringGrid1.colcount); writeln (f, StringGrid1.rowcount); For X:=0 to StringGrid1.colcount-1 do For y:=0 to StringGrid1.rowcount-1 do writeln (F, StringGrid1.cells[x,y]); closefile (f); end; Procedure LoadGrid; var f:textfile; temp,x,y:integer; tempstr:string; begin assignfile (f,’Filename’); reset (f); readln (f,temp); StringGrid1.colcount:=temp; readln (f,temp); StringGrid1.rowcount:=temp; For X:=0 to StringGrid1.colcount-1 do For y:=0 to StringGrid1.rowcount-1 do begin readln (F, tempstr); stringgrid.cells[x,y]:=tempstr; end; closefile (f); end; Задания: 1. Проверьте все примеры из лабораторной работы. 2. Дана таблица размера n×n , посчитайте количество четных элементов главной диагонали. 3. Заполните две таблицы случайными числами и перемножить их по правилу перемножения матриц. Ответ выводится в третьей таблице. 4. Дана таблица размера n×n
. Забейте таблицу случайными числами 5. Реализуйте на языке программирования Delphi задания из лабораторных работ по теме «Массива». Лабораторная работа 6 . Окна сообщений и диалоговые окна Цель: изучить возможности формирования сообщений и использования диалоговых компонентов. До сих пор нами рассматривались те компоненты, которые не только могут располагаться на форме, но и при выполнении остаются там же. Однако часто возникает необходимость в выдаче каких-либо сообщений или получении определенной информации от пользователя. Для этой цели в языке программирования Delphi имеются некоторые функции, процедуры и компоненты. Процедура ShowMessage ( Msg : String ) формирует и выдает на экран окно с сообщением Msg . Помимо сообщения это окно имеет кнопку Ok , при нажатии на которую закрывается данное окно. Заголовок окна совпадает с названием приложения. При необходимости выдаваемая информация разбивается на строки. Окно, сформированное данной процедурой, так же, как и все окна, работает в модальном режиме, когда блокируется выполнение приложения до закрытия данного окна. Процедура ShowMessagePos ( Msg : String , X : Integer ; Y : Integer ) выдает окно так, чтобы его левый верхний угол находился в точке с абсолютными координатами (X , Y ). Пример использования данной процедуры может иметь следующий вид: ShowMessage (‘Текст содержит‘ +IntToStr (RichEdit1.Lines.Count )); Данные процедуры позволяют выдавать на экран сообщение, но Общий вид данной функции: MessageDlg(Msg:String; aType:TmsgDlg Type; aButton:TmsgDlgButton; HelpCtx: LongInt): Word; В переменной Msg задается текст выдаваемого сообщения, в переменной aType тип окна. Всего имеется пять предопределенных окон сообщения, следовательно, параметр aType может иметь пять различных значений, которые перечислены в таблице 2. Таблица 2. Значения параметра aType
Параметр aButton определяет, какие кнопки будет содержать окно сообщения. Это параметр имеет тип множество , и его значение должно быть заключено в квадратные скобки. Для данного параметра могут задаваться значения, перечисленные в таблице 3. Таблица 3. Значения параметра aButton
Параметр HelpCtx определяет текст справки, которая должна выводиться, если пользователь нажмет клавишу [F1]. Оператор вывода на экран окна может работать и как процедура (т. е. не иметь выходных параметров), и как функция. В этом случае результатом является значение, определяющее, какая кнопка была нажата: либо mbNone (т. е. ни одна кнопка не была нажата), либо значение соответствующей клавиши, префиксом mr . Примеры использование функции MessageDlg . Пример 1 При нажатии на кнопку формы появляется диалоговое окно. При нажатии на кнопку Yes
содержимое компонента RichEdit
1
сохраняется procedure TForm1.Button1Click(Sender: TObject); begin if MessageDlg('Изменения сохранить ',mtWarning, [mbYes, mbNo, mbCancel],0)=mrYes then RichEdit1.Lines.SaveToFile('D:\Temp\Пример.dat'); end; В данном примере вызывается диалоговое окно предупреждения. Пример 2 Вычислить значение f
(x
) = ln
(x
)×x
c проверкой области значения данной функции. Значение переменной x
определяется в компоненте Edit
1
. procedure TForm1.Button1Click(Sender: TObject); Var x,y:Real; begin x:=StrToFloat(Edit1.Text); if x<=0 then MessageDlg('Логарифм данного аргумента не существует', mtError, [mbOk],0) else begin y:=ln(x)*x; Edit2.Text:=FloatToStr(y); end; end; Пример 3 Использовать окна можно и во время создания формы. Например, можно сделать так, чтобы до появления основной формы появлялось диалоговое окно с приглашением. procedure TForm1.FormCreate(Sender: TObject); begin MessageDlg('Добро пожаловать', mtCustom,[mbYes],0); end; Диалоговое окно MessageDlg
позволяет определить нажатую кнопку, но не имеет возможности для передачи информации от пользователя InputBox (Caption ,Msg ,Default :String ):String — функция, которая выводит диалоговое окно с заголовком Caption , сообщением Msg и поле для ввода информации, в котором вначале находится текст, заданный строкой Default , а также двумя кнопками Ok и Cancel . Если диалоговое окно закрывается нажатием кнопки Ok , то функция возвращает набранную строку, в противном случае возвращается строка по умолчанию Default . InputQuery (Caption ,Msg :String , Var Value : String ):Boolean — функция, которая выводит подобное диалоговое окно, однако строка ввода по умолчанию пустая. Если диалоговое окно закрывается нажатием кнопки Ok , то функция возвращает значение True и в параметре Value передается введенная строка, в противном случае возвращается значение False . Пример 4 При нажатии кнопки появляется диалоговое окно, которое будет закрыто только в том случае, если введен пароль и нажата клавиша Ok . procedure TForm1.Button1Click(Sender: TObject); const pasword:string=’1111’; {Пароль } var Value: string; begin value:=''; Repeat Until (InputQuery(‘Мое приложение ‘,’Введите пароль’,value)) and (value=pasword); end; Изменим условие таким образом, что пароль можно вводить только определенное количество раз. Если пароль был введен неправильно, то все приложение закрывается. В этом случае можно рассмотреть событие on
Create
для самого компонента Form
, в процедуре обработки которого procedure TForm1.FormCreate(Sender: TObject); const pasword:string='1111'; {Пароль } n=3; {Количество попыток} var Value: string; i:integer; begin value:=''; i:=0; Repeat i:=i+1 Until ((InputQuery('Мое приложение ','Введите пароль',value)) and (value=pasword)) or (i=n); if i=n then form1.Close; end; В языке программирования Delphi реализовано несколько компонентов, позволяющие осуществить диалог между пользователем и программой. Эти компоненты находятся на странице Dialogs . Рассмотрим некоторые из них: OpenDialog позволяют просматривать содержимое внешних запоминающих устройств и выбирать имя файла, который затем можно открыть для работы; SaveDialog позволяют выбрать имена файлов для сохранения; OpenPictureDialog SavePictureDialog предназначены для аналогичной работы с файлами, содержащими графическое изображение; FontDialog предназначен для определения параметров шрифта. Существуют также диалоговые окна, выбирающие текущий цвет, параметры печати, осуществляющие поиск файлов и т. д. Все компоненты, которые позволяют отображать диалоговые окна, представлены на рисунке 20. Рассмотрим более подробно компоненты OpenDialog
и SaveDialog
. Свойство FileName
, которое доступно как во время проектирования, так Свойство Filter имеет текст фильтров файлов. Он представляет собой любое количество пар последовательных символов. В каждой паре первая часть задает текст фильтра, выдаваемый в диалоговом окне, а вторая часть содержит сам фильтр. При выборе данного свойства в инспекторе объектов появляется диалоговое окно Filter Edit (рис. 21), которое состоит из двух частей: первая имеет имя Filter Name и предназначена для ввода текста фильтра, вторая имеет имя Filter и задает сам фильтр. Рисунок 20 Рисунок 21 Для вывода диалогового окна на экран предназначен метод-функция Execute , которое возвращает значение True , если диалоговое окно было закрыто кнопкой Ok , и False — в противном случае. В диалоговом окне FontDialog с помощью свойства Font можно установить начальное значение шрифта и затем посредством того же свойства определить выбранный в диалоговом окне шрифт. Пример 5 Создать программу, которая позволяет читать, создавать текстовые файлы в формате RTF, а также менять шрифт. Для решения данной задачи поместим на форму компонента RichEdit , в котором будем обрабатывать содержимое текстового файла, OpenDialog и SaveDialog для выбора имени файла, компонент FontDialog для выбора шрифта и несколько компонентов Button . Первый из них будет отвечать за чтение файла, второй — за запись файла, третий — за выбор шрифта, следовательно, свойству Name первой кнопки можно придать значение « Open », второй «Save », а третьей « Font ». Тогда процедуры обработки нажатий на эти кнопки будут иметь следующий вид: procedure TForm1.SaveClick(Sender: TObject); begin If SaveDialog1.Execute Then RichEdit1.Lines.SaveToFile(SaveDialog1.FileName); end; procedure TForm1.OpenClick(Sender: TObject); begin If OpenDialog1.Execute Then begin RichEdit1.Lines.Clear; RichEdit1.Lines.LoadFromFile(OpenDialog1.FileName); end; end; procedure TForm1.FontClick(Sender: TObject); begin If FontDialog1.Execute Then RichEdit1.Font:=FontDialog1.Font; end; Если всех имеющихся возможностей ввода на экран сообщений и ведения диалога не хватает, то в проект может быть добавлена дополнительная форма с помощью пункта меню File
New
,
Form
. В этом случае При работе в Delphi имеется возможность пользоваться ранее созданными модулями и формами, для этого они должны быть помещены в специальное хранилище — репозиторий. Открыть репозиторий можно при помощи команды меню File , New , Other .. . При этом появляется диалоговое окно New Items (новый элемент), в котором можно выбрать необходимый в новом приложении элемент. Все элементы, находящиеся в репозитории, располагаются на различных страницах. Добавить форму в репозиторий можно с помощью пункта меню Project , Add to Repository … В этом случае необходимо выбрать названия для элемента, страницу, на которой он будет располагаться и пиктограмму. Пример 6 Создать проект, имеющий дополнительную форму, на которой находится дополнительная информация об авторских правах и которая Теперь необходимо в проект добавить эту форму. Можно воспользоваться командой New Form пункта меню File для добавления чистой формы или выбрать заготовленную форму, имеющуюся в репозитории. Для этого выберем команду New пункта File и на закладке Form выберем компонент с именем About Box . После этого в проекте добавится новая форма с именем AboutBox из класса TAboutBox и модуль с именем Unit 2 . Форма AboutBox содержит несколько меток (компонент Label ), одно изображение (компонент Image ) и кнопку (компонент Button ). Воспользовавшись свойством Caption компонента Label , можно изменить выводимую информацию, и свойством Picture компонента Image — выводимую картинку. При нажатии на кнопку форма должна закрываться, следовательно, процедура обработки этого события будет содержать команду Close или AboutBox . Close . В этом случае весь модуль Unit 2 будет иметь вид: unit Unit2; interface uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls; type TAboutBox = class(TForm) Panel1: TPanel; ProgramIcon: TImage; ProductName: TLabel; Version: TLabel; Copyright: TLabel; Comments: TLabel; OKButton: TButton; procedure OKButtonClick(Sender: TObject); private public end; var AboutBox: TAboutBox; implementation {$R *.DFM} procedure TAboutBox.OKButtonClick(Sender: TObject); begin AboutBox.Close; {или просто Close} end; end. Остановимся более подробно на имени процедуры: TAboutBox — это имя класса, в котором происходит событие, OKButton — это имя кнопки, а OKButtonClick — это событие, возникающее при нажатии кнопки. Для того чтобы из модуля первой формы была доступна вторая форма, необходимо подключить этот модуль, тогда весь список подключаемых модулей будет иметь вид: uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, Unit2 ; На главной форме разместим дополнительную кнопку с именем About (свойство Name ). Именно при нажатии на эту кнопку выводится дополнительная форма, тогда процедура обработки события будет иметь вид: procedure TForm1.AboutClick(Sender: TObject); begin AboutBox.Show; end; Задания: 1. Проверьте все примеры из лабораторной работы. 2. В примере 3 выведите дополнительную форму в модальном виде. 3. Сделайте так, чтобы при закрытии окна текстового редактора, если данные не были сохранены, выводилось сообщение. 4. Сделайте так, чтобы при нажатии на кнопку сообщение появлялось в левом верхнем углу, при втором нажатии — в правом верхнем и т. д. (сообщения разные: каждое соответствует своему углу). Лабораторная работа 7 . Графические компоненты Цель: изучить основные графические возможности. Многие компоненты Delphi , включая саму форму, имеют средства рисования. Однако есть специальные средства, предназначенные либо непосредственно для рисования, либо для отображения уже готовых рисунков, либо для того и другого. Для рисования компоненты могут включать свойства определенного класса: TPen , TBrush , TCanvas и класс, который определяет цвет. Рассмотрим их более подробно. Класс TColor позволяет выбирать цвет из таблицы стандартных цветов Windows (clWhite , clRed , …). Однако могут использоваться и нестандартные цвета. В этом случае учитывая, что свойство данного типа хранит четырехбайтовое значение, каждый байт которого (нумерация байтов происходит слева направо) имеет следующее значение: 1 — указатель формата цвета; 2, 3, 4 — интенсивность, соответственно, синей, зеленой и красной Старший байт указывает, каким способом будут использоваться Пример 1 Создать приложение, в котором выбор цвета можно осуществлять как посредством диалога, так и вводом шестнадцатеричного значения цвета. Поместим на форму компоненты ColorDialog
, Panel
, Label
и Button
. При нажатии на кнопку будет вызываться диалоговое окно, после закрытия которого, данным цветом будет закрашиваться компонент Panel
, а в компоненте Label
будет выдаваться шестнадцатеричное представление данного цвета. Компонент Panel
со стандартной панели инструментов используется просто для демонстрации. Никакими дополнительными свойствами, кроме возможности объединять другие компоненты, он не обладает. Для нас интересно только то, что имеется свойство Color
и может менять цвет. В этом случае процедура обработки нажатия на кнопку вызывает диалоговое окно выбора цвета и окрашивает компонент Panel
procedure TForm1.Button1Click(Sender: TObject); begin if ColorDialog1.Execute then begin Panel1.Color:=ColorDialog1.Color; Label1.Caption:=IntToHex(ColorDialog1.Color,8) end; end; Теперь рассмотрим обратную задачу, а именно будем задавать самостоятельно шестнадцатеричное представление цвета. Поскольку нет стандартной функции, переводящей символьное представление шестнадцатеричной константы в число, создадим функцию H exStrToHex , которая будет выполнять данную работу. Программа будет иметь вид: function HexStrToInt(s:string):integer; function hex(c:char):integer ; begin case c of '0'..'9':Result:=ord(c)-ord('0'); 'A'..'F':Result:=ord(c)-ord('A')+10; end; end; Var i:integer; begin result:=0; if s[1]='$' then delete(s,1,1); For i:=1 to length(s) do Result:=result*16+hex(s[i]); end; procedure TForm1.Button2Click(Sender: TObject); begin Panel2.Color:=HexStrToInt(Edit1.Text); end; Класс TPen задает характеристики карандаша, с помощью которого изображаются различные линии. У этого класса есть свойства Color — для задания цвета линии, Mode — для задания стиля рисования, который заключается в выборе одного или нескольких цветов рисования линии, Style — свойство, определяющее стили рисования (штриховая, пунктирная, штрихпунктирная), Width — свойство целого типа, определяющее толщину линии. Класс TBrush задает характеристики кисти, которой закрашивается поверхность изображения. Свойство Bitmap задает собственное заполнение раскрашиваемой поверхности и представляет собой изображение 8× 8 пикселей, Style — свойство, определяющее орнамент кисти (горизонтальные, вертикальные или диагональные линии). Данные классы не могут использоваться самостоятельно, а являются составными частями других, более сложных, классов. TCanvas представляет собой наиболее сложный класс и является поверхностью, на которой размещается созданное изображение. К свойствам данного класса относятся свойство Pen класса Tpen , свойство Brush класса TBrush . Большое количество методов предназначено для отображения геометрических фигур. При отображении фигур контур изображается карандашом Pen с установленными в нем характеристиками. Если фигура является замкнутой и необходимо произвести ее закраску, то будут использоваться значения свойства класса Brush . Для доступа к каждой точке имеется свойство Pixel , которое является двухмерным массивом, содержащим цвет каждой точки. В данном классе имеется ряд методов, которые позволяют строить Методы для вывода картинок на канву — Draw и StretchDraw . В качестве параметров указываются прямоугольник и графический объект для вывода (это может быть TBitmap , TIcon или TMetafile ). StretchDraw отличается тем, что растягивает или сжимает картинку так, чтобы она заполнила весь указанный прямоугольник. Методы для вывода текста — TextOut и TextRect . При выводе текста используется шрифт (Font ) канвы. При использовании TextRect текст выводится только внутри указанного прямоугольника. Длину и высоту текста можно узнать с помощью функций TextWidth и TextHeight . У объектов из библиотеки визуальных компонентов TBitmap , TComboBox , TDrawGrid , TForm , TImage , TPaintBox , TStringGrid есть свойство Canvas (канва), которое предоставляет простой путь для рисования на них. На странице System палитры компонентов есть объект TPaintBox , который можно использовать для построения приложений типа графического редактора. Никаких ключевых свойств, кроме Canvas , данный компонент не имеет, собственно, этот объект является просто канвой для рисования. Рассмотрим некоторые примеры использования графических компонентов и возможности рисования. Пример 2 При перемещении курсора мыши по форме все пиксели формы закрашиваются в красный цвет. Поскольку пиксели необходимо закрашивать при перемещении мыши, можно использовать событие MouseMove
. procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin Form1.Canvas.Pixels[x,y]:=clRed; end; Пример 3 Строятся части прямых линий, которые задаются при перемещении мыши. При первом событии происходит смещение в точки, при следующем эта линия строится. Для решения никаких дополнительных компонентов помещать не будем, поскольку само построение происходит на форме. Необходимо только ввести новую переменную и считать количество нажатий на кнопку. Программа будет иметь следующий вид: var i:Integer; procedure TForm1.FormCreate(Sender: TObject); begin i:=1; end; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin i:=i+1; if odd(i) then Form1.Canvas.LineTo(x,y) else Form1.Canvas.MoveTo(x,y); end; Эту задачу можно решить и другим способом. Обрабатывать отдельно нажатие на кнопку мыши и ее отпускание. В одном случае осуществлять перемещение, а во втором — строить данную линию. Var x1,y1:integer; procedure TForm1.FormMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Form1.Canvas.LineTo(x,y); end; procedure TForm1.FormMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Form1.Canvas.MoveTo(x,y); end; Построение линии подобным образом выглядит не совсем красиво, поскольку она появляется только один раз и остается на этом же месте. При работе с современными графическими редакторами процесс построения линии, да и любого другого объекта, несколько иной. А именно — после фиксации начального положения можно перемещать мышь, при этом появляется динамический характер данного объекта. И только после отпускания кнопки мыши объект фиксируется. Данный эффект принято называть «резиновой линией». Для подобных построений необходимо использовать внутренние функции Windows , т. е. функции API . Изложение данных функций выходит за пределы пособия, однако хочется надеяться, что познавательный интерес возьмет верх и позволит вам разобраться в программе. Пример 4. Построение «резиновой линии». type TForm1 = class(TForm) procedure FormMouseDown(Sender:TObject;Button:TMouseButton; Shift: TShiftState;X,Y:Integer); procedure FormMouseMove (Sender:TObject; Shift:TShiftState; X,Y: Integer); procedure FormMouseUp (Sender:TObject;Button:TMouseButton;Shift: TShiftState; X,Y:Integer); procedure FormCreate(Sender: TObject); private LineDrawing:Boolean; {Эта переменная равна True, если программа находится в режиме рисования} BegX,BegY:Integer; {Начала "резиновой" линии} OldX,OldY:Integer; {Последняя точка "резиновой" линии.} procedure Line(X1,Y1,X2,Y2:Integer); end; procedure LineDrawRandom(X,Y:Integer;Canvas:TCanvas);stdcall; begin Canvas.Pixels[X,Y]:=RGB(Random(256),Random(256),Random(256)) end; {Процедура LineDrawXXX - это функции косвенного вызова (callback-функции) для LineDDE.} procedure TForm1.Line; begin LineDDA(X1,Y1,X2,Y2,@LineDrawRandom,Integer(Canvas)); end; procedure TForm1.FormMouseDown (Sender:TObject; Button:TMouseButton; Shift: TShiftState; X,Y:Integer); begin if Button=mbLeft then begin MouseCapture:=True; OldX:=X; OldY:=Y; BegX:=X; BegY:=Y; LineDrawing:=True {При нажатии на левую кнопку мыши начинаем рисовать "резиновую" линию. Инициализируем все переменные и захватываем мышь в монопольное пользование.} end end; procedure TForm1.FormMouseMove(Sender:TObject;Shift:TShiftState;X,Y:Integer); begin if LineDrawing and ((X<>OldX) or (Y<>OldY)) then with Canvas do begin SetROP2(Handle,R2_Not); Line(BegX,BegY,OldX,OldY); {Стираем старую линию} Line(BegX,BegY,X,Y); {Рисуем новую} OldX:=X; OldY:=Y end end; procedure TForm1.FormMouseUp(Sender:TObject; Button:TMouseButton; Shift:TShiftState; X,Y:Integer); begin if (Button=mbLeft) and LineDrawing then begin Line(BegX,BegY,X,Y); LineDrawing:=False; MouseCapture:=False end end; procedure TForm1.FormCreate(Sender: TObject); begin LineDrawing:=False; end; Пример 5 Рассмотрим пример построение графика произвольной функции. Данная задача может быть решена различными способами. Остановимся на варианте, когда определяется массив точек, а затем строится график функции, используя метод Polyline . Точка определяется типом TPoint , который является записью и содержит два поля: соответственно координату x и y . Function f(x:real):Real; Begin f:=sin(x); End; procedure TForm1.Button1Click(Sender: TObject); var gr:array[1..50] of TPoint; {График — ломаная линия} x0,y0:integer; {Координаты точки начала координат} dx,dy:integer; {Шаг координатной сетки по осям X и Y} i: integer; begin x0:=10; y0:=200; dx:=5; dy:=5; for i:=1 to 50 do {Заполним массив gr } begin gr[i].x:=x0+(i-1)*dx; gr[i].y:=y0-Round(f(gr[i].x))*dy; end; with form1.Canvas do begin MoveTo(x0,y0); LineTo(x0,10); {Ось Y} MoveTo(x0,y0); LineTo(200,y0); {Ось X} Polyline(gr); {График } end; end; Теперь рассмотрим компоненты для создания изображений. Компонент TShape с закладки Addition представляет собой простейшие графические объекты на форме типа круг, квадрат и т. п. Вид объекта указывается в свойстве Shape . Свойство Pen определяет цвет и вид границы объекта, Brush задает цвет и вид заполнения объекта. Эти свойства можно менять как во время дизайна, так и во время выполнения программы. TBevel — компонент с той же закладки, является объектом для украшения программы, может принимать вид рамки или линии. Объект предоставляет меньше возможностей по сравнению с TPanel , но не занимает ресурсов. Внешний вид указывается с помощью свойств Shape и Style . Помимо простейших построений имеется возможность обрабатывать более сложные изображения. Для работы с такими изображениями используются специальные объекты. Обычно изображения хранятся отдельно от обрабатывающего объекта в соответствующем файле или потоке. Вначале рассмотрим классы, которые позволяют обрабатывать изображения. TBitmap
(класс — растровые изображения), TIcon
(класс — пиктограммы Windows
), TMetafile
(класс — векторное изображение или метафайлы). Все эти классы являются потомками абстрактного класса TGraph
, который не имеет возможности работать с графическими изображениями, но содержит все ключевые свойства и методы, например: свойства Height
, Width
задающие высоту и ширину содержащегося в данном классе изображения, логические свойства Empty
и Modified
, первое из которые определяет, содержит ли объект графическое изображение, а второе — было ли модифицировано изображения. Методы LoadFromFile
(FileName
: String
) и SaveToFile
(FileName
: String
) соответственно загружают изображение из файла или сохраняют его в файле. Данные методы перекрываются Любое графическое изображение должно быть помещено в объект класса TPicture , который является надстройкой над изображением и дает ему новые возможности. Являясь надстройкой, сам класс не имеет никаких графических средств и не может самостоятельно обрабатывать включенное в него изображение. Но у него есть несколько особых свойств, например: Graphic — типа TGraphic , которые определяют тип включенного изображения и свойства Bitmap , Icon , MetaFile соответствующих классов, которые определяют вид включенного изображения. При затребовании объекта другого класса, прежний объект, хранящийся в поле, будет уничтожен. Компонент Image со страницы Additional позволяет поместить графическое изображение в любое место на форме. Картинку можно загрузить во время проектирования в редакторе свойства Picture (инспектор объектов). В этом случае открывается диалоговое окно, где с помощью кнопки Load можно осуществлять просмотр и выбор изображения, которое должно храниться в файле формата BMP (bitmap ), WMF или EMF (Windows Meta File ), ICO (icon ). Как известно, форматов хранения изображений гораздо больше трех вышеназванных (например, наиболее известны PCX , GIF , TIFF , JPEG ). Для включения в программу изображений в этих форматах нужно либо перевести их в формат BMP , либо использовать дополнительные модули. Следует помнить, что изображение, помещенное на форму во время проектирования, включается в файл проекта и затем при компиляции добавляется к EXE -файлу. Поэтому такой EXE -файл может получиться достаточно большой. Как альтернативу рассмотрим загрузку картинки во время выполнения программы. Для этого у свойства Picture воспользуемся методом LoadFromFile . Важными являются свойства объекта Image и логические свойства AutoSize , Center и Stretch . Если Center установлено в True , то центр изображения будет совмещаться с центром объекта TImage . Если Stretch установлено в True , то изображение будет сжиматься или растягиваться таким образом, чтобы заполнить весь объект, а если свойство AutoSize будет иметь значение True , то подобным образом будет вести себя сам объект. Кроме перечисленных выше свойств, объект T I mage обладает свойством Canvas , которое позволяет выполнять построения. Пример 6 Создать программу, которая в зависимости от переключателя будет либо сжимать до необходимого размера изображение, либо выдавать его в естественном виде. Поместим на форму компоненты CheckBox , Image , OpenPictureDialog , Button и опишем следующую процедуру обработки нажатия на кнопку: procedure TForm1.Button1Click(Sender: TObject); begin If CheckBox1.Checked Then begin Image1.AutoSize:=True;Image1.Stretch:=False; end Else begin Image1.AutoSize:=False;Image1.Stretch:=True; end; OpenPictureDialog1.Filter:=GraphicFilter(TGraphic); If OpenPictureDialog1.Execute Then Image1.Picture.LoadFromFile(OpenPictureDialog1.FileName) end; Пример 7 В заключение рассмотрим пример создания простейшего графического редактора. Основная работа, т. е. рисование, будет происходить на компоненте Image , диалоговое окно ColorDialog необходимо нам для выбора цвета, а переключатель с независимой фиксацией RadioGroup будет предназначен для выбора инструмента рисования. Две дополнительные кнопки будут служить для вызова диалогового окна выбора цвета либо для очистки формы. Разместив все необходимые компоненты, получим вид формы, изображенный на рисунке 22. Рисунок 22 Основная программа имеет следующий вид: unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Image1: TImage; RadioGroup1: TRadioGroup; ColorDialog1: TColorDialog; Button1: TButton; Button2: TButton; procedure Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } public { Public declarations } x1,y1:integer; i:integer; end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.Image1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin i:=i+1; image1.Canvas.Brush.Style:=bsclear; case RadioGroup1.ItemIndex of 0:if odd(i) then image1.Canvas.Rectangle(x1,y1,x,y) else begin x1:=x; y1:=y; end; 1:if odd(i) then image1.canvas.Ellipse(x1,y1,x,y) else begin x1:=x; y1:=y; end; 2:if odd(i) then image1.canvas.lineto(x,y) else begin x1:=x; y1:=y; image1.Canvas.MoveTo(x1,y1); end; end; end; procedure TForm1.FormCreate(Sender: TObject); begin i:=1; end; procedure TForm1.Button1Click(Sender: TObject); begin if ColorDialog1.Execute then image1.Canvas.Pen.color:=colordialog1.color; end; procedure TForm1.Button2Click(Sender: TObject); begin image1.Canvas.Pen.Color:=clwhite; image1.Canvas.Brush.Style:=bssolid ; image1.canvas.Rectangle(0,0,225,305); image1.Canvas.Pen.Color:=clblack; end; end. Данную программу достаточно легко модифицировать таким образом, чтобы все фигуры строились при повторном нажатии. Кроме этого, можно добавить возможности построения произвольных фигур, закраски замкнутой области, различных распылителей. Задания: 1. Проверьте все примеры из лабораторной работы. 2. Доработайте редактор, чтобы можно было сохранять и загружать рисунок.
Лабораторная работа
8.
Компоненты
-меню Цель: изучить возможности при создании меню и дополнительных элементов интерфейса. Практически все сложные программы в настоящее время обладают системным меню, предназначенным для выбора того или иного пути выполнения программы. Системное меню представляет собой либо древовидную структуру, а следовательно, элемент меню может быть либо подменю, либо командой, либо разделительной линией, если имеется несколько групп. Существуют два различных типа меню: MainMenu (главное меню) и PopurMenu (локальное меню), которые находятся на странице Standart . Если главное меню отождествляется с формой, то локальное меню — с тем или иным компонентом управления. У различных компонентов управления могут быть различные локальные меню, следовательно, на форме может находиться только одно главное меню и несколько локальных меню. Для того чтобы связать любой элемент управления с локальным меню, необходимо свойству PopurMenu задать имя нужного локального меню. Оба этих компонента являются не оконными и не видны в том месте, Обычно главное и локальное меню формируются на стадии проектирования (однако существуют методы, которые позволяют создавать меню и на стадии выполнения программы). Для создания необходимо воспользоваться свойством Items . При активизации этого свойства открывается конструктор меню, позволяющий набирать элементы меню. У каждого пункта элемента меню имеются свойства: Caption — свойство типа String , содержащее текст элемента меню (для того чтобы получить разделитель, необходимо данному свойству дать значение –), GroupIndex — свойство целого типа, содержит номер группы, к которой относится элемент меню, ShotCut — свойство целого типа, определяющее код клавиши быстрого доступа. Компоненты меню могут выполнять роль переключателей с зависимой и независимой фиксацией. Логическое свойство RadioItem определяет, может ли пункт меню выполнять функции переключателя, а Checked — является ли элемент меню отмеченным. Отдельно отметим свойство Name
— имя элемента меню. Если его Предположим, что в нашем приложении необходимо создать основное меню, состоящее из пунктов File
, Edit
, Help
. Подчиненное меню для пункта File
состоит из разделов Open
, Save
Save
As
, для пункта меню Edit
—
из разделов Copy
, Cut
, Paste
. Для пункта Help
— единственный пункт Добавим на форму компонент MainMenu1 и, произведя двойной щелчок левой клавишей мыши, откроем диалоговое окно формирования данного меню. Теперь можно задавать как основные, так и подчиненный пункты, используя свойство Caption . Заданное меню может выглядеть так, как изображено на рисунке 23. Рисунок 23 Описание формы после задания данного системного меню будет иметь следующий вид: type TForm1 = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Edit1: TMenuItem; Help1: TMenuItem; Open1: TMenuItem; Save1: TMenuItem; Saveas1: TMenuItem; Copy1: TMenuItem; Cut1: TMenuItem; Paste1: TMenuItem; N1: TMenuItem; private { Private declarations } public { Public declarations } end; Как видно из текста, появился единственный компонент основного меню (тип TMainMenu
) и несколько компонентов, определяющих подпункты в меню (тип TMenuItem
). Имена практически во всех случаях совпали с теми названиями, которые мы определяли самостоятельно, кроме последнего случая, а когда название было задано русскими буквами, появился компонент с именем N
1
. Это стандартное правило, имеющееся При работе с любым меню определено несколько событий. Среди них необходимо отметить OnClick , которое происходит при выборе элемента меню мышью, клавишами управления клавиатурой или клавишей быстрого доступа. Если воспользоваться предложенным выше меню, то в нашем распоряжение будет 10 процедур, каждая из них вызывается при выборе конкретного пункта меню и задается процедурой вида: procedure TForm1.Open1Click(Sender: TObject); begin end; Данная процедура будет вызвана при выборе пункта меню File , Open . Методы, доступные во время выполнения программы, связаны в основном с корректировкой структуры и определения связи между элементами и включают в себя методы: Add (Item ) — добавить элемент вменю, Delete (Index ) — удалить элемент меню с соответствующим индексом. Не будем специально приводить пример использования системного Рассмотрим дополнительные элементы интерфейса, к которым могут быть отнесены те компоненты, которые позволяют облегчить работу К таким компонентам будем относить строку состояния StatusBar
, которая при выполнении программы располагается в нижней части формы Панель инструментов ToolBar находится на странице Win 32 . На ней могут размещаться кнопки быстрого доступа, причем для панели инструментов разработан специальный класс кнопок ToolButton . Однако данный компонент не представлен в компонентах. Для того чтобы вставить на панель инструментов кнопку, необходимо воспользоваться контекстным меню, в котором выбрать пункт New Button или пункт меню New Separator — для расположения на панели инструментов пустого пространства. У кнопок типа ToolButton следует отметить свойство Style , которое устанавливает внешний вид и функциональные возможности кнопки и может принимать следующие значения: tbsButton — обычная кнопка, tbsCheck — кнопка с фиксацией, которая после нажатия остается в таком положении до следующего нажатия. В данном случае логическое свойство Down принимает значение True , если кнопка нажата, tbsDivider — разделитель, который представляет собой вертикальную линию, разделяющую визуальные кнопки, tbsSeparator — пустое пространство. Свойства ButtonHigth и ButtonWidth устанавливают размеры кнопок. На каждой кнопке может находиться текст (свойство Caption ) и картинка (свойство Image ). Свойство List устанавливает расположение относительно друг друга текста и изображения. Данные кнопки обрабатывают все события, однако событие по умолчанию так и остаются OnClck . Панель инструментов, как правило, располагается на контейнерах — компонентах CoolBar
или ControlBar
. CoolBar
— это панель, снабженная вертикальной полоской в левой части, за которую ее можно перемещать по форме. Основу данного компонента составляет коллекция панелей (свойство Bands
). Чтобы «скомплектовать» новую панель, необходимо выбрать данное свойство и в диалоговом окне с помощью клавиш Add
Каждый элемент панели управления имеет несколько свойств, среди которых свойство Control позволяет связать его с одним из оконных элементов управления, после чего элемент перемещается на отведенную панель. Форма, содержащая системное меню и панель инструментов, представлена на рисунке 24. Как правило, панель инструментов содержит те же команды, что и меню. Следовательно, имеет смысл один раз описать процедуру, а затем Рисунок 24 Рисунок 25 Если все-таки процедуры должны быть одинаковыми, за исключением некоторых аспектов, которые зависят от элементов управления, ставшего источником события, то можно воспользоваться передаваемым параметром Sender или параметром Tag , присутствующим в каждой процедуре. Оператор is предназначен для проверки совместимости по присвоению экземпляра объекта с экземпляром данного класса. Пример 1 Пусть имеется кнопка на форме, панель инструментов и главное меню. Должно происходить одно и то же действие, например запись файла из содержимого компонента RichEdit
1
: или после нажатия кнопки формы, или одной из кнопок панели инструментов, или при выборе определенного пункта из главного меню. Следовательно, можно описать одну процедуру, а затем вызывать ее при возникновении всех изложенных выше событий. Создадим процедуру обработки нажатия на кнопки Button
1
Click
Тогда для определения объекта вызвавшего событие будем применять оператор is и, кроме сохранения содержимого в файле, будем выдавать сообщение о объекте, на котором произошло событие. procedure TForm1.Button1Click(Sender: TObject); begin If SaveDialog1.Execute Then RichEdit1.Lines.SaveToFile(SaveDialog1.FileName); If Sender is TButton then ShowMessage('Нажата кнопка'); If Sender is TToolButton then ShowMessage('Нажата кнопка на панели инструментов'); If Sender is TMenuItem then ShowMessage('Выбран пункт из главного меню'); end; Оператор as
предназначен специально для приведения объектных Компонент StatusBar
находится на странице Win
32
и при добавлении на форму растягивается на всю длину и смещается к нижней части формы, поэтому из свойств расположения у данного компонента доступно только Heigth
— высота. На этапе проектирования можно выделить логическое свойство SimplePanel
, определяющее, на сколько частей будет разбита строка состояния. Если данное свойство имеет значение True
, то панель Рисунок 26 В диалоговом окне при помощи кнопок задается количество разделов строки состояния. Задать некоторый текст можно посредством свойства Text . На рисунке 27 изображена панель редактирования строки состояния StatusBar , на которой определены три раздела, двум из них уже присвоено значение свойства Text . Рисунок 27 Обращаться к каждой части панели можно таким образом StatusBar1 .Panels [<номер>]. Среди других свойств каждой панели отметим следующие: Bevel — вид рамки, Width — свойство целого типа, определяющее горизонтальный размер, Style — свойство, определяющее вид информации, размещенной в панели. Последнее из них может принимать значения psText — задается текст, psOwerDraw — содержимое, определяющее обработчиком события OnDrawPanel . Пример 2 Создать программу, у которой в строке состояния будут выдаваться координаты курсора мыши. Для решения данной задачи поместим на форму компонент StatusBar , для которого с помощью свойства Panels зададим две части, текст первой будет содержать строку 'X =', а текст второй — строку 'Y ='. Затем для объекта Form 1 на закладке Events выберем событие onMouseMove , которое возникает при любом перемещении мыши. В этой процедуре будем обращаться последовательно к каждой панели и, используя свойство Text , формировать необходимую нам строку, которая состоит из двух частей. Первая — это фиксированная строка, вторая — это функция, переводящая значения X и Y — точки, в которой произошло смещение, в строку. Данная процедура может иметь следующий вид: procedure TForm1.FormMouseMove(Sender: TObject; Shift: TShiftState; X,Y: Integer); begin StatusBar1.Panels[0].Text:='X='+IntToStr(x); StatusBar1.Panels[1].Text:='Y='+IntToStr(y); end; Компонент Timer
со страницы System
предназначен для формирования интервалов времени. Прежде всего, отметим событие, которое связано Основные свойства — это логическое свойство Enabled , определяющее, реагирует ли таймер на собственные события (если значение True — то реагирует), и свойство Interval , определяющее временной интервал, через которое произойдет событие OnTime , в миллисекундах. Задания: 1. Создайте текстовый редактор с системным меню. 2. Создайте графический редактор с системным меню 3. Создайте приложение, которое содержит такие элементы интерфейса, как системное меню, строка подсказки и таймер для выполнения определенной работы.
Лабораторная работа
9.
Отображение
Цель:
изучить компоненты, позволяющие обрабатывать звуковую В современной компьютерной технике существует немало звуковых Наиболее простым звуковым файлом является волновой файл .wav
. Другими, часто применяемыми типами звуковых файлов являются файлы цифрового интерфейса музыкальных инструментов (MIDI). В них звук хранится в виде данных о том, на каких инструментах исполняются определенные ноты и как долго они звучат. Если вы знакомы с музыкой, то можете рассматривать содержимое такого файла как цифровой эквивалент дирижерской партитуры. Одним из главных преимуществ MIDI является то, что файлы получаются сравнительно небольшими. Волновые и MIDI
-файлы могут хранить только звук или музыку. Для хранения видеоинформации разработан ряд форматов. Отметим среди них файлы AVI
и MPEG
. Большинство видеофайлов поддерживают также хранение звуковой дорожки, так что звук воспроизводится синхронно Имеется несколько процедур для воспроизведения звуков — это процедуры Веер , MessageBeep и PlaySound . Наиболее простой процедурой, управляющей звуком, является процедура Beep . Она не имеет параметров и воспроизводит стандартный звуковой сигнал, установленный в Windows, если компьютер имеет звуковую карту и стандартный сигнал задан. Если звуковой карты нет или стандартный сигнал не установлен, звук воспроизводится через динамик компьютера просто в виде короткого щелчка. Откройте новое приложение, введите в него кнопку, в обработчике щелчка которой напишите одно слово: procedure TForm1.Button1Click(Sender: TObject); begin Beep; end; Можете запустить приложение, щелкнуть по кнопке и прослушать стандартный звук Windows
или просто щелчок, если стандартный звук Более серьезной является логическая функция MessageBeep
. Она имеет параметр uType
, указываюий воспроизводимый звук как идентификатор раздела реестра [sounds
], в котором записаны звуки, сопровождающие те или иные события Windows
. Значения параметра uType
представлены Таблица 4. Значение п араметра fdwSound
После запроса звука, функция MessageBeep возвращает управление вызвавшей функции и воспроизводит звук асинхронно. Во время воспроизведения приложение может продолжать выполняться. Если невозможно воспроизвести указанный в функции звук, делается попытка воспроизвести стандартный системный звук, установленный по умолчанию. Если и это невозможно, то воспроизводится стандартный сигнал через динамик. При успешном выполнении возвращается ненулевое значение, что соответствует значению True . При аварийном завершении возвращается нуль или значение False . Поместим на форму одну кнопку и напишем для нее обработчик: procedure TForm1.Button1Click(Sender: TObject); begin MessageBeep(МВ_ ICONHAND); end; После нажатия на кнопку будет слышен тот же стандартный звук Windows
, что и при критической ошибке, или если стандартный звук Функция PlaySound позволяет воспроизводить не только звуки событий Windows , но и любые волновые файлы. Функция PlaySound определена следующим образом: PlaySound (pszSound , hmod , fdwSound ). Параметр pszSound
представляет собой строку с нулевым символом Таблица 5. Значение п араметра fdwSound
Продолжение таблицы 5
Флаги могут комбинироваться операцией о r . Если функция не может найти указанный звук, то воспроизведения не будет и вернется значение false . Замечание. Для того чтобы данная функция была доступна, необходимо подключить модуль MMSystem . После этого весь блок подключаемых модулей должен иметь следующий вид: Uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls,MMSystem; Приведем примеры использования функции PlaySound . Оператор PlaySound('C:\Windows\Media\Звук Microsoft.wav' ,0, SND_ASYNC); воспроизводит асинхронно и однократно стандартный звук Microsoft , который вы обычно можете слышать при открытии Windows . В процессе воспроизведения продолжается выполнение приложения. Пример 1 Создать приложение, которое могло бы воспроизводить любой волновой файл. Введите в приложение диалоговый компонент OpenDialog и кнопку со следующим обработчиком щелчка: procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then Begin PlaySound(pchar(OpenDialog1.FileName),0,SND_ASYNC); end; end; В данном примере в функции PlaySound используется преобразование типов строковой переменой, которое имеет свойство OpenDialog1 . FileName указателя на строку типа PChar . В этом случае служебное слово Pchar будет восприниматься как функция, которая преобразует строковую переменную в данный тип, хотя в общем случае PChar — это тип указателя на строку, которая заканчивается нулем. В предыдущих примерах звук задавался именем его волнового файла. Функция PlaySound позволяет воспроизводить и системные звуки, просто называя их псевдонимы. Псевдоним — это системное имя, определяющее путь к конкретному файлу, воспроизводимому на какое-то действие. Все псевдонимы занесены в системный реестр Windows и могут быть изменены с помощью редактора реестра. Например, оператор PlaySound('SystemStart',0,SND_ASYNC); воспроизводит тот же звук открытия Windows , что и приведенный ранее оператор, указывавший имя и путь к нему. Оператор PlaySound( 'C:\Windows\Media\Звук Microsoft.wav', 0,SND_ASYNC or SND_LOOP); многократно асинхронно воспроизводит стандартный звук Microsoft
, начиная его снова и снова, как только он заканчивается. Если вы ввели PlaySound(0,0,SND_PURGE); Все рассмотренные ранее операторы прерывали при своем выполнении звук, который асинхронно воспроизводился в момент вызова PlaySound . Если же вы выполните оператор с флагом SND_NOSTOP , например: PlaySound(‘C:\Windows\Media\3вyк Microsoft.wav’,0, SND_SYNC or SND_NOSTOP); то в случае, если в этот момент драйвер занят воспроизведением другого звука, это воспроизведение не будет прерываться, а функция PlaySound сразу вернет false . Заказанного этим оператором звука не услышите, т. к. в очередь он не встанет. Теперь рассмотрим способ воспроизведения в приложении Delphi стандартных мультипликаций Windows и файлов .avi — клипов без звукового сопровождения. Это позволяет сделать компонент Animate , расположенный на странице Win32 . Компонент Animate со страницы Win 32 позволяет воспроизводить на форме стандартные видеофайлы Windows (типа копирования файлов, поиска файлов и т. п.) и немые видеофайлы avi (Audio Video Interleaved ). Эти файлы представляют собой последовательность кадров битовых матриц. Они могут содержать и звуковую дорожку, но компонент Animate воспроизводит только немые клипы. Воспроизводимое им изображение задается одним из двух свойств: FileName
или CommonAVI
. Первое из этих свойств позволяет в процессе проектирования или выполнения задать имя воспроизводимого файла. Рисунок 28 Если значение свойства CommonAVI задать, например, aviCopyFile , что соответствует стандартному изображению копирования файла, то соответствующий начальный рисунок немедленно появится на компоненте Animate (рис. 29). Рисунок 29 Свойство Repetitions задает число повторений воспроизведения клипа. Если оно равно 0 (значение по умолчанию), то воспроизведение повторяется вновь и вновь до тех пор, пока не будет выполнен метод Stop . При выполнении этого метода генерируется событие OnStop . Если же свойство Repetitions задать больше 0, оно определит число повторений клипа. Логическое свойство Active компонента Animate определяет, показывается или нет в данный момент мультипликация. В компоненте Animate
также предусмотрены события OnClose
, OnOpen
, OnStart
, генерируемые соответственно в моменты закрытия Пример 2 Создать приложение, в котором можно воспроизвести все стандартные мультипликации Windows некоторое заранее заданное, количество раз. Поместим компонент Animate
на форму и установим свойство Visible
Рисунок 30 В приложении будем имитировать начало и окончание события, которое должно сопровождаться мультипликацией, нажатиями кнопок запуска На форме также разместим компонент RadioGroup , в котором будем выбирать номер фрагмента. В свойстве Items зададим следующие строки: номер 1, номер 2 и т. д. до номера 8. Свойству ItemsIndex присвоим значение 0. На форме разместим две кнопки. При нажатии на первую кнопку будет происходить демонстрация видеофрагмента, а на вторую — остановка. Форма может иметь вид, представленный на рисунке 30. Тогда процедуры обработки нажатий могут иметь следующий вид: procedure TForm1.Button1Click(Sender: TObject); begin Animate1.Visible:=True; Animate1.CommonAVI:=TCommonAVI(RadioGroup1.ItemIndex+1); Animate1.Repetitions:=SpinEdit1.Value; Animate1.Active:=True; end; procedure TForm1.Button2Click(Sender: TObject); begin Animate1.Stop; end; procedure TForm1.Animate1Stop(Sender: TObject); begin Animate1.Visible:=False; end; Можете посмотреть воспроизводимое изображение по кадрам. Для этого из локального меню выберите разделы NextFrame (следующий кадр) или PreviousFrame (предыдущий кадр). Это позволит вам выбрать фрагмент клипа, если вы не хотите воспроизводить клип полностью. Воспроизвести фрагмент клипа можно, установив соответствующие значения свойств: StartFrame — начальный кадр воспроизведения и StopFrame — последний кадр воспроизведения. Воспроизводить фрагмент клипа можно и методом Play , который определен следующим образом: procedure Play(FromFrame, ToFrame: Word; Count: Integer); Метод воспроизводит заданную последовательность кадров клипа от FromFrame до ToFrame включительно, воспроизведение повторяется Count раз. Значение ToFrame должно быть не меньше FromFrame и не больше значения, определяемого свойством FrameCount (свойство только для чтения), указывающим полное число кадров в клипе. Если Count = 0, то воспроизведение повторяется до тех пор, пока не будет выполнен метод Stop . В качестве видеофайла можете использовать файл …Delphi5\Demos\ Coolstuf\cool.avi, поставляемый с примерами Delphi , или любой другой видеофайл. В Delphi имеется компонент MediaPlayer — универсальный проигрыватель аудио-, видеоинформации. Этот медиаплеер расположен на странице System библиотеки компонентов. Компонент используется в двух режимах. Во-первых, предоставлять пользователю возможность управлять воспроизведением информации Рисунок 31 Назначение кнопок, перечисленных слева направо, представлено Каждой кнопке медиаплеера соответствует метод, осуществляющий по умолчанию требуемую операцию: Play , Pause , Stop , Next , Previous , Step , Back , StartRecording , Eject . Тип устройства мультимедиа, с которым работает медиаплеер, определяется его свойством DeviceType
. Если устройство мультимедиа хранит объект воспроизведения в файле, то имя файла задается свойством FileName
. По умолчанию свойство DeviceТуре
имеет значение dtAutoSelect
, Таблица 6. Назначение кнопок компонента MediaPlayer
Воспроизведение видеоинформации по умолчанию производится В компоненте MediaPlayer
определены события OnClick
и
OnNotify
. Первое из них происходит при выборе пользователем одной из кнопок медиаплеера. Второе — OnNotify
— происходит после возвращения очередного метода, если свойство медиаплеера Notify
было установлено Свойства Notify и Wait действуют только на один очередной метод, поэтому их значения надо каждый раз восстанавливать в обработчиках событий OnClick или OnNotify . Пример 3 Создадим проект, который позволяет проигрывать мультимедийные файлы. Начните новый проект и перенесите на форму компоненты MediaPlayer , Button и OpenDialog . В фильтре компонента OpenDialog можно задать, например, имена фильтров и сами фильтры, как показано на рисунке 32. Рисунок 32 Обработчик нажатия на кнопку может содержать операторы procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute() then MediaPlayer1.FileName:= OpenDialog1.FileName; MediaPlayer1.Open; end; В данной процедуре открывается устройство мультимедиа, соответствующее выбранному пользователем файлу. При этом надо проследить, чтобы в компоненте MediaPlayer свойство DeviceType равнялось dtAutoSelect . Это обеспечит автоматический выбор соответствующего устройства мультимедиа, исходя из расширения выбранного файла. В компоненте MediaPlayer при желании можно указать имя файла FileName , открываемого в момент начала выполнения приложения. Тогда надо установить свойство AutoOpen в true . С помощью данного приложения вы можете слушать музыку, смотреть немые и звуковые клипы, т. е. наслаждаться всеми прелестями мультимедиа, если, конечно, они уже есть в вашем компьютере. Задания: 1. Проверьте все примеры из лабораторной работы. 2. Создайте программу, в которой непрерывно прослушивается один и тот же звуковой файл во все время работы приложения. 3. Создайте приложение, которое позволяет запускать видеоклипы, посредством компонента Animate . Лабораторная работа 1 0. Исключительные ситуации Цель: изучить класс Exception и возможности при обработке ошибок. Класс Exception является прямым потомком базового класса TObject . Вместе со своими потомками он предназначен для обработки исключительных ситуация (исключений), возникающих при некорректных действиях программы: например, в случае деления на 0, при попытке открыть несуществующий файл, при выходе за пределы выделенной области динамической памяти и т. п. Рассматриваются основные свойства исключений и их использование для повышения надежности программ. При работе в среде Delphi эксперименты с исключениями плохо прослеживаются, т. к. при каждом исключении среда перехватывает управление программой. В этом случае бывает полезно отменить такое поведение среды. Для этого вызовете опцию Tools , Debugger Options и на странице Language Exceptions уберите флажок в переключателе Stop on Delphi Exceptions. Для обработки исключений в Object Pascal предусмотрен механизм защищенного блока, который может записываться в двух различных видах. Первый имеет следующий вид: try <операторы> except <обработчики исключений> else <операторы> end; Второй определяется в виде try <операторы> finally <операторы> end; Защищенный блок начинается зарезервированным словом try
(попытаться [выполнить]) и завершается словом end
. Существуют два типа защищенных блоков — except
(исключить) и finally
(в завершение), отличающихся способом обработки исключения. В блоке except
порядок В блоке finally операторы в секции finally ... end получают управление всегда, независимо оттого, возникло ли исключение в секции try ... finally или нет. Если исключение возникло, все операторы в секции try ... finally , стоящие за «виновником» исключения, пропускаются и управление получает первый оператор секции finally ... end . Если исключения не было, этот оператор получает управление после выполнения последнего оператора секции try ... finally . Обработчики исключений в блоке except имеют такой синтаксис: on < класс исключения> do <оператор>; Здесь on , do — зарезервированные слова; <класс исключения> — класс обработки исключения; <оператор> — любой оператор Object Pas cal . Обратите внимание: имя класса служит своеобразным ключом выбора, а собственно обработка осуществляется оператором, стоящим за do (этот оператор может быть составным, так что обработка исключения может занимать произвольное количество операторов Object Pascal ). Поиск нужного обработчика осуществляется с начала списка вниз до тех пор, пока не встретится класс, способный обрабатывать исключение данного типа. Если подходящего класса не обнаружено, управление передается операторам, стоящим за словом else , а если таковых нет, то выполняется умалчиваемая обработка исключения. Если важен лишь факт возникновения исключительной ситуации try ……….. except ShowMessage(‘Ошибка’); ……………… end; Защищенные блоки могут вкладываться друг в друга на неограниченную глубину и встречаться в блоке обработки исключительной ситуации. Класс Exception является родительским для всех классов исключений. У этого класса имеется множество дочерних классов, каждый из которых отвечает за конкретное исключение. При возникновении исключительной ситуации объекты классов обработчиков создаются и уничтожаются автоматически. Таких классов очень много, поэтому рассмотрим только некоторые: EAbort — обработка любой исключительной ситуации; EIntError
— любая ошибка в целочисленных вычислениях, среди EMatcError — любая ошибка при выполнении вычислений с плавающей запятой, среди которых: EZeroDivide — вещественное деление на 0; EOverflow — переполнение; EInfalidArgument — аргумент функции вне допустимого диапазона; EArrayError — ошибка при работе с массивами; EConvertError — ошибка в функциях StrToInt и StrToFloat ; EFOpenError — ошибка при открытии файла; EInOutError — любая ошибка в файловых операциях; EInvalidGridOperator — любая ошибка при работе с таблицами; EInvalidGraphOperator — недопустимая графическая операция. Рассмотрим еще некоторые исключительные ситуации, которые будут работать с объектами, рассматриваемыми в следующих лабораторных работах: EStrimError — произвольная ошибка при работе с потоками данных, EThread — ситуация борьбы за общий ресурс в программе с несколькими потоками событий, EDatabaseError — ошибка при работе с базами данных. Пример 1 Необходимо заполнить таблицу числа по следующему правилу: генерируется случайное число, а затем в ячейке компонента StringGrid 1 сохраняется обратное значение. Заранее не известно, был ли сгенерирован 0, и будет ли допустима операция деления. Для корректной работы данной программы необходимо задавать защищенный блок; процедура формирования таблицы будет иметь вид: procedure TForm1.Button1Click(Sender: TObject); var i,j:Integer; a:real; begin with StringGrid1 do begin ColCount:=SpinEdit1.Value+1; RowCount:=SpinEdit2.Value+1; for i :=1 to ColCount do for j:=1 to RowCount do Try {Начало блока} a:=Random(10); Cells[i,j]:=FloatToStr(1/a); except On EZeroDivide do ShowMessage('Деление на ноль в ячейке '+IntToStr(i)+’,’ +IntToStr(j)); {Проверка класса ошибки} end; end; end; Если необходимо использовать поля и методы класса-обработчика, то можно перед именем класса поставить идентификатор и двоеточие: On EObject:Expecrion do …………. Для стандартных классов такой прием позволяет использовать единственное строковое свойство Message , со стандартным сообщением об ошибке, которое получают все наследники класса Exception . В некоторых случаях бывает необходимо инициализировать исключительную ситуацию самостоятельно. Для этого используется зарезервированное слово raise
(возбудить). Если этот оператор вставить в секцию Try
…
except
или try
…
finally
, то немедленно начнет работу секция обработки исключительной ситуации. Если данный оператор встретился в секции except
…
end
или finally
…
end
, то считается, что данный защищенный блок на текущем уровне вложенности завершил свою работу и управление В качестве примера рассмотрим программу, реализованную в лабораторной работе, посвященной графическим компонентам. В этой программе необходимо было ввести шестнадцатеричное число в компоненте Edit , перевести его в десятичное число и включить данный цвет. Функция, переводящая строку, которая является шестнадцатеричным числом, в десятичное число имеет вид: function HexStrToInt(s:string):integer; function hex(c:char):integer ; begin case c of '0'..'9':Result:=ord(c)-ord('0'); 'A'..'F':Result:=ord(c)-ord('A')+10; end; end; Var i:integer; begin result:=0; if s[1]='$' then delete(s,1,1); For i:=1 to length(s) do Result:=result*16+hex(s[i]); end; Функция hex на основании символа возвращает число. Если данный символ является цифрой или латинской буквой от A до F , то возвращаемое число будет истинно, однако если это не так, то результат будет просчитан неправильно. Следовательно, в операторе case необходимо учесть ветвь иначе, где должна вызываться исключительная ситуацию. Тогда функция hex будет иметь вид: function hex(c:char):integer ; begin case c of '0'..'9':Result:=ord(c)-ord('0'); 'A'..'F':Result:=ord(c)-ord('A')+10; else raise EConvertError.Creat (‘Недопустимое представление шестнадцатеричного числа ’); end; end; В данном примере оператор raise инициализирует событие EConvertError , которое возникает при ошибке комвертации и в качестве параметра передает необходимое сообщение. Задания: 1. Проверьте все программы из данной лабораторной работы. 2. Создайте текстовый редактор, который корректно работает при попытке открыть отсутствующий файл. Лабораторная работа 1 1. Классы Цель: Научиться создавать простейшие программы на языке программирования Delphi . Классами в Object
Ра
s
са1
называются специальные типы, которые Важным отличием классов от других типов является то, что объекты класса всегда распределяются в динамической памяти, поэтому объект-переменная фактически представляет собой лишь указатель на динамическую область памяти. Однако в отличие от других указателей при ссылке на содержимое объекта запрещается использовать символ «^» за именем объекта. Класс может содержать поля, методы и свойства. Понятие пóля и метода при описании класса полностью совпадают с данными понятиями, реализованными в описание объектов. Полями называются инкапсулированные в класс данные. Поля могут быть любого типа, в том числе классами. Инкапсулированные в классы процедуры и функции называются методами. Более подробно остановимся на понятии свойства. Свойство — это специальный механизм классов, регулирующий доступ к полям. Свойства объявляются с помощью зарезервированных слов property , read и write (слова read и write считаются зарезервированными только в контексте объявления свойства). Обычно свойство связано с некоторым полем и указывает те методы класса, которые должны использоваться при записи в это поле или при чтении из него. Например: Type TaClass= class IntField: Integer; Function GetField: integer; Procedure SetField (value: Integer); Property IntegerValue: integer read GetField write SetField; End; В контексте программы свойство ведет себя как обычное поле. Например, можно написать такие операторы: Var aClass: TaClass; Value: integer; Begin AClass:=TaClass.Create; {Обязательное обращение к конструктору перед обращением к полю или свойству!} ………. aClass.IntegerValue:= 0; ………. Value:= aClass.IntegerValue; ………. aClass .Destroy; {Удаление ненужного объекта } ………. End. Более того, возможен и такой оператор присваивания: aClass.IntField:= NewValue; Разница между этим оператором и оператором AClass.IntegerValue:= NewValue; заключается в том, что при обращении к свойству автоматически подключается метод SetField , в котором могут реализовываться специфические действия. Если нет необходимости в специальных действиях при чтении и записи свойства, вместо имени соответствующего метода можно указывать имя поля: Type TaClass= class IntField:Intege; Procedure SetField (value:Integer); Property IntegerValue: integer read IntField write SetField; End; Свойство может и не связываться с полем. Фактически оно описывает один или два метода, которые осуществляют некоторые действия над данными того же типа, что и свойство. Любой вновь созданный класс может иметь секции (разделы), определяемые зарезервированными словами published
(декларированные), pri
vate
(личные), protected
(защищенные), public
(доступные) и automated
(автоматизированные). Внутри каждой секции вначале описываются поля, Секции определяют области видимости элементов описанного класса. Секция public не накладывает ограничений на область видимости перечисленных в ней полей, методов и свойств — их можно вызывать в любом другом модуле программы. Секция published также не ограничивает область видимости, однако в ней перечисляются свойства, которые должны быть доступны не только на этапе исполнения, но и на этапе конструирования программы (т. е. в окне инспектора объектов). Секция published используется только при разработке нестандартных компонентов. Среда Delphi помещает описания компонентов, вставленных в форму, в специальную секцию без названия, которая располагается сразу за заголовком класса и продолжается до первой объявленной секции. Эта секция — published . Программисту не следует помещать в нее собственные элементы описания класса или удалять из нее элементы, вставленные средой. Секция private сужает область видимости до минимума: личные элементы описания доступны только внутри методов данного класса и в подпрограммах, находящихся в том же модуле, где описан класс. Элемент, объявленный в секции private , становится недоступным даже ближайшим потомкам класса, если они размещаются в других модулях. Секция protected доступна только методам самого класса, а также любым его потомкам независимо от того, находятся ли они в том же модуле или нет. Наконец, секция automated используется только для объявления свойств и методов, которые будут добавлены к так называемому интерфейсу OLE - объектов автоматизации; область видимости членов этой секции не ограничена. Разрешается сколько угодно раз объявлять любую секцию, причем порядок следования секций не имеет значения. Любая секция может быть пустой. Рассмотрим основополагающие абстрактные классы объектов Delphi . Имеется сложная структура иерархии классов, которые могут использоваться в программе, создавая объекты этих классов или формировать классы потомков. В начале этой иерархии стоят абстрактные классы, которые являются родоначальниками целых семейств классов. Самая общая структура абстрактных классов имеет следующий вид:
Класс TObject
является предком всех других классов, используемых Среди методов класса TObject
можно отметить следующие: ClassName
—
функция, которая формирует строку, содержащую имя класса, заданное ему при создании (например TEdit
, Tbutton
, TForm
и т. д.), ClassParent
— строковая функция, применимая только к классам и определяющая класс непосредственного предка, InstanteSize
— целочисленная функция, применимая только к классам и возвращающая размер класса или объекта Пример 1 Для произвольного класса выдать все родительские классы и их размеры. Поместим на форму два компонента Edit , в одном из которых будет выдаваться имя класса, а во втором — размер класса. Определим дополнительное поле class1 типа TClass , в котором будем хранить имя класса. Вся работа в программе сводится к двум процедурам обработки событий — это создание формы и нажатие на кнопку. При создании формы в переменной class1 будем записывать имя произвольного класса, а при нажатии кнопки будем в одном компоненте Edit выдавать имя класса в другой размер данного класса, а также определять класс непосредственного предка. Тогда программа будет иметь вид: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, AxCtrls, OleCtrls, vcf1, MPlayer, StdCtrls; type TForm1 = class(TForm) Edit1: TEdit; Button1: TButton; Edit2: TEdit; procedure Button1Click(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public class1:TClass; {описание поля - класс} { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin Class1:=TButton; {задание произвольного класса} end; procedure TForm1.Button1Click(Sender: TObject); begin Edit1.Text:=class1.ClassName; {определение имени класса} Edit2.Text:=IntToStr(class1.InstanceSize); {определение размера объекта класса} class1:=class1.ClassParent; {определение непосредственного предка} end; end. Класс TPersistent
(постоянный) является потомком класса TObject
Класс TComponent
является родоначальником всех компонентов, используемых в приложении. Класс TComponent
содержит ряд свойств Свойство Component [Index: Integer ] типа TComponent задает список вспомогательных компонентов. Свойство Owner типа TComponent содержит указатель на основной компонент. Пример 2 Получить имена и классы всех компонентов, расположенных на форме. Поместим на форму четыре компонента Edit и один компонент Button . В разделе public формы опишем целочисленную переменную i , в которой будем хранить номер компонента. Начальное значение данной переменной будет задаваться при создании формы. При нажатии на кнопку в соответствующих компонентах Edin будем выдавать имя компонента, имя класса и порядковый номер. Тогда программа может иметь следующий вид: procedure TForm1.FormCreate(Sender: TObject); begin I:=0; Edit4.Text:=IntToStr(Form1.ComponentCount); end; procedure TForm1.Button1Click(Sender: TObject); begin If i<=Form1.ComponentCount-1 then begin Edit1.Text:=Form1.Components[i].Name; Edit2.Text:=Form1.Components[i].ClassName; Edit3.Text:=IntToStr(i); i:=i+1; end; end; В программе при создании формы происходит обнуление переменной, а при каждом последующем нажатии кнопки выдается информации об очередном элементе формы. Класс TControl является родоначальником всех элементов управления, с помощью которых вводится информация на экран при помощи клавиатуры и мыши. Все компоненты управления могут отображаться на экране, а следовательно, они должны содержать свойства, в которых хранятся экранные координаты компонента (Left , Top , Height , Weight ), свойства определяющие внешний вид и положение элемента на экране (Align , Color , Caption , Cursor , Fount , Visible , ...). Класс TWinControl характеризуется наличием у объектов его семейства оконных функций, что приводит к возможности реакции такого элемента на внешнее воздействие. Класс имеет характеристики, позволяющие формировать изображение элементов управления в стиле Windows . Класс TScrollingWinControl
является предком всех прокручиваемых элементов управления. Дополнительно к наследуемым характеристикам он обладает средствами прокрутки изображения, если оно целиком Класс TGraphControl отличается тем, что у объектов его семейства отсутствуют оконные функции, в силу чего они не могут реагировать на внешние воздействия. В связи с этим такие элементы могут служить только для вывода на экран графической информации. Правило Object Pascal о совместимости типов классов позволяет использовать класс-потомок там, где требуется класс-предок, но не наоборот. Делая явное преобразование типов, мы можем вызвать очень неприятную ошибку времени выполнения (или, что еще хуже, незаметное изменение содержимого памяти), поскольку компилятор не может определить, является ли тип объекта корректным и существуют ли в действительности вызываемые методы. Чтобы решить эту проблему, мы можем использовать технику, основанную на информации о типе времени выполнения (Run - time type information , RTTI ). Суть состоит в том, что каждый объект «знает» свой тип, а также класс своего родителя. Мы можем обратиться к этой информации, используя оператор is или некоторые методы класса TObject . Параметрами оператора is являются объект и тип класса, а возвращаемое значение имеет тип Boolean . Например, If Omyclass is TMyClass then Выражение is принимает значение True , если OMyClass в данный момент ссылается на объект класса TMyClass или его потомка. Теперь, когда вы уверены, что переменная совместима с типом TMyClass , можно произвести безопасное приведение (преобразование) типов. Такие же операции выполняются напрямую другим оператором RTTI , оператором as , который преобразует объект только в том случае, если тип запрашиваемого класса совместим с текущим. Параметрами оператора as являются объект и тип класса, а результатом является объект, приведенный к новому типу. Разница между традиционным преобразованием типов и использованием оператора as заключается в том, что последний вызывает исключительную ситуацию (EInvalidCast ), если тип объекта не совместим с типом класса, к которому вы пытаетесь его привести. Задание: 1. Проверьте все программы из данной лабораторной работы. Лабораторная работа 1 2. Потоки Цель: изучить классы TStream и TThread , возможности при создании многопоточных приложений. В языке программирования Delphi имеется два различных вида потоков: поток данных и поток команд. В начале несколько слов о потоках данных — класс TStream . Потоки данных — это обобщенная модель двоичных данных, размещенных на устройствах-накопителях, таких как диски, оперативная память и т. д. Любой поток обладает двумя ключевыми свойствами — размером в байтах (свойство Size ) и текущей позицией (Position ). Родоначальником всех потоков является абстрактный класс TStream , от которого порождены некоторые специализированные потоки, такие как: TFileStream (файловый поток), TMemoryStream (поток буферов в памяти) и т. д. Более подробно данные потоки можно изучить самостоятельно, а сейчас рассмотрим потоки событий. Одна из возможностей, которая имеется в операционной системе Windows
и поддерживается языком программирования Delphi
— это потоки действий или нити (thread
). Смысл потоков заключается в том, что одновременно может выполняться несколько различных видов работы. Например, приложения Word
и Excel
задействуют сразу несколько потоков. Word
может одновременно корректировать грамматику, печатать документ Каждое приложение выполняется посредством одного, главного потока, однако имеется возможность создавать и запускать другие потоки, которые будут выполняться параллельно. При этом имеется свойство, которое отвечает за то, как быстро будет выполняться поток. В языке программирования Delphi потоки реализованы в виде объектов, которые получают время работы процессора квантами (около 19 мс). Класс TThread позволяет программировать потоки. В отличие от визуальных компонентов из библиотеки VCL , которые автоматически формируются при создании формы, потоки необходимо самостоятельно инициализировать посредством конструктора Creat ( CreatS : Boolean ). Если значение логического параметра CreatS имеет значение False , то поток сразу после создания начинает исполняться, если значение данного параметра будет True , то для запуска метода на исполнение необходимо использовать метод Resume . Деструктор Destroy вызывается, когда необходимость в потоке отпадает, при этом поток останавливается и освобождаются все ресурсы, связанные с этим потоком. Метод Terminate осуществляет завершение потока (без последующего запуска), а метод Suspend позволяет приостановить выполнение потока. Логическое свойство Suspended проверяет, приостановлен ли поток или продолжает выполняться. С помощью этого свойства можно приостановить и запустить поток на исполнение. Установив его в True , получаем тот же эффект, что и при вызове метода Suspend , а установив в False , возобновляем выполнение потока, как и метод Resume . Главный метод потока из класса TThread
— это виртуальный, абстрактный метод Execute
. В его теле должен содержаться код, который Рассмотрим еще несколько важных свойств и методов потоков. Свойство Priority класса TThreadPriority позволяет запрашивать и определять приоритет потоков. Приоритет определяет, насколько часто поток будет получать время работы процессора. Допустимые значения приоритетов — tpIdle , tpLowest , tpLower , tpHigher , tpHigest , tpTImeCritical . В данном списке перечислены приоритеты от самого низкого — фонового приоритета, до самого высокого — приоритета реального времени. Необходимо быть очень внимательным при использовании двух последних приоритетов, поскольку они могут влиять на выполнение всего приложения. Как правило, используются приоритеты tpLowest и tpLower . Метод Synchronize ( Method : TThreadMethod ) создан для безопасного вызова методов VCL внутри потока. В качестве аргумента передается имя метода, который производит обращение к VCL ; вызов Synchronize аналогичен вызовам данного метода из модуля. К примеру, в основной форме приложения необходимо предусмотреть процедуру: procedure TForm1. ShowMessage; Var i:Integer; begin i:=RichEdit1.Lines.Count; ShowMessage ('Данный текст содержит ' +IntToStr(i)+' строк '); end; При написании данной процедуры необходимо помнить, что если описывается процедура класса TForm 1 , то ее заголовок должен быть помещен в описание класса. Для того чтобы вызвать данную процедуру из модуля формы, достаточно описать вызов ShowMsgCount , однако для вызова из потока необходимо записать Synchronize (TForm 1.ShowMessage ). Для того чтобы добавить поток в проект, можно воспользоваться unit Unit2; interface uses Classes; type TMyThread = class(TThread) private { Private declarations } protected procedure Execute; override; end; implementation { TMyThread } procedure TMyThread.Execute; begin { Код потока помещается здесь} end; end. В данном примере многие комментарии, которые присутствуют Пример 1 Создадим простое многопоточное приложение, в котором в потоке будут производиться некоторые арифметические действия, например накопление суммы, с достаточно малым шагом. Для решения данной задачи, имея пустую форму и используя репозиторий, добавим к проекту новый класс потока с именем TMyThread
. Выбрав соответствующую закладку, будем редактировать данный модуль. Цель работы потока заключаются в том, что с достаточно малым шагом накапливается вещественное число, которое будет доступно из модуля главной формы. Для этого в описании класса создадим раздел Public
unit Thrd; interface uses Classes; type TmyThread = class(TThread) private { Private declarations } protected procedure Execute; override; Public a:Real; end; procedure TMyThread.Execute; begin a:=0; While a<=100000000 do a:=a+0.000001 end; end. Сохраним модуль с описанным в нем потоком под именем Thrd .pas , для чего выберем команду Save As из пункта меню File . Откроем главный файл модуля и добавим Thrd к списку используемых модулей, после чего он должен выглядеть так: uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, Thrd; В секцию public формы TForm 1 поместим две переменные типа поток следующей строкой: Thread1,Thread2:TmyThread; Инициализацию и запуск данных потоков будем производить в момент создания формы, используя событие onCreate . В этой же процедуре зададим различные приоритеты для данных потоков, после этого процедура будет иметь вид: procedure TForm1.FormCreate(Sender: TObject); begin Thread1:=TMyThread.Create(False); Thread1.Priority:=tpLower; Thread2:=TMyThread.Create(False); Thread2.Priority:=tpNormal; end; Поместим на форму два компонента. Метку, в которой будет отражаться текущее значение, полученное нами из потоков, и кнопку, при нажатии на которую это произойдет, тогда процедура будет: procedure TForm1.Button1Click(Sender: TObject); begin Label1.Caption:=FloatToStr(Thread1.a); Label2.Caption:=FloatToStr(Thread2.a); end; После этого основную форму можно задать произвольным образом, например, поместив на форму компонент RichEdit
, в котором будем набирать любой текст. При запуске программы на исполнение работа приложения будет состоять из выполнения трех потоков. Первый и в то же время главный поток приложения будет позволять редактировать текст, При решении данного примера использовались два модуля, один из которых являлся модулем формы, а второй содержал описание потока, при этом к главному модулю подключался модуль с потоком. Как правило, работа с потоками осуществляется именно так, однако в этом случае из модуля потока нельзя обратиться к компонентам формы. Поэтому когда поток должен работать с формой, необходимо объединить эти два модуля в один. После объединения многопоточное приложение будет иметь вид: unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls; type {описание потока} TmyThread = class(TThread) private protected procedure Execute; override; procedure UpdateCaption; Public a:Real; end; type {описание формы} TForm1 = class(TForm) RichEdit1: TRichEdit; Label1: TLabel; Label2: TLabel; Button1: TButton; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); private public Thread1 , Thread2:TMyThread; {два потока, описанные внутри формы } end; var Form1: TForm1; implementation {$R *.DFM} procedure TmyThread.Execute; Var i,j:integer; begin a:=1; While a<=100000000 do a:=a+0.000001; end; procedure TForm1.FormCreate(Sender: TObject); begin Thread1:=TMyThread.Create(False); Thread1.Priority:=tpLower; Thread2:=TMyThread.Create(False); Thread2.Priority:=tpNormal; end; procedure TForm1.Button1Click(Sender: TObject); begin Label1.Caption:=FloatToStr(t.a); Label2.Caption:=FloatToStr(t1.a); end; end. Модифицируем данную программу так, чтобы значения, полученные Задания: 1. Проверьте все программы из данной лабораторной работы. 2. Выполните задание, которое соответствует номеру вашего варианта. 3. Сделайте так, чтобы параллельно с вводом текста с клавиатуры Прочитав данную книгу, читатель может
(хотя, конечно, он должен
) усвоить основные знания по созданию программ на языке высокого уровня Delphi
. Это касается основных, первичных знаний языка высокого уровня. Достаточно одного взгляда на палитру имеющихся компонентов и на список литературы, чтобы представить себе все области современной информатики, в которой можно создавать приложения в среде программирования Delphi
. В первую очередь это приложения, позволяющие обрабатывать базу данных посредством различных технологий — BDE
, COM
, ADO
. На закладках Data
Access
и Data
Control
собраны подобные компоненты. Закладки dbExpress
, BDE
, dbGo
также содержат компоненты работы с базами данных, однако применяются другие технологии доступа к ним. И как следует из самих названий закладок, существует огромное количество компонентов, которые позволяют работать с сетью и создавать как простые, так и интернетовские серверы. Кроме этого, в языке Delphi
имеются все средства для создания чатов как локальных, так Нельзя не отметить возможности интеграции приложений, созданных в Delphi
, приложений MS Office
, возможности обмена информацией В данном пособии изложены минимальные сведения о самых простых как визуальных, так и не визуальных компонентах, способы их обработки. Дальнейшее изучение является личным делом каждого человека, но хочется надеяться, что прочтение данной работы разбудило ваш интерес. Список рекомендуемой литературы Основная 1. Бобровский, С. И. Delphi 7: учебный курс / С. И. Бобровский. — СПб. : Питер, 2004. — 736 с. 2. Желонкин, А. В. Основы программирования в интегрированной среде DELPHI : практикум / А. В. Желонкин. — 2-е изд. М. : БИНОМ. Лаборатория знаний, 2006. — 236 с. 3. Истомин, Е. П. Высокоуровневые методы информатики и программирования / Е. П. Истомин, В. В. Новиков, М. В. Новикова. — М. : ООО «Андреевский издательский дом», 2006. 4. Пономарев, В. А. Базы данных в Delphi 7. Самоучитель / В. А. Пономарев. — СПб. : Питер, 2003. — 224 с. 1. Галисеев, Г. В. Компоненты в Delphi 7. Профессиональная работа / Г. В. Галисеев. — М. : Диалектика. 2004. — 624 с. 2. Григорьев, А. Б. О чем не пишут в книгах по Delphi / А. Б. Григорьев. — СПб. : БХВ-Петербург, 2008. — 576 с. 3. Дарахвелидзе, П. Г. Программирование в Delphi 7 / П. Г. Дарахвелидзе. — СПб. : БХВ-Петербург, 2003. — 785 с. 4. Елманова, Н. Э. Delphi 6 и технология COM / Н. Э. Елманова, С. В. Трепалин, А. Тенцер. — СПб. : Питер, 2002. — 640 с. 5. Кондукова, Е. Delphi и 1C: Предприятие. Программирование информационного обмена / Е. Кондукова. — СПб. : БХВ-Петербург, 2007. — 592 с. 6. Корняков, В. Н. Программирование документов и приложений MS Office 7. Культин, Н. Б. Основы программирования в Delphi 2007 / Н. Б. Культин. — СПб. : БХВ-Петербург, 2008. — 480 с. 8. Попов, С. А. Delphi и 1С: Предприятие. Программирование информационного обмена / С. А. Попов. — СПб. : БХВ-Петербург, 2007. — 592 с. 9. Хомоненко, А. Д. Delphi 7 / А. Д. Хомоненко, В. Гофман, М. Мещеряков 10. Шкрыль, А. А. Разработка клиент-серверных приложений в Delphi / Учебно-методическое издание Кузнецов Олег Анатольевич Основы программирования в среде Delphi Учебно-методическое пособие для студентов физико-математических специальностей вузов Редактор М. Б. Иванова Корректор Н. Н. Дробышева Подписано в печать 14.04.09. Формат 60×84/16. Уч.-изд. л. 5,6. Усл.-печ. л. 6,5. Тираж 100 экз. Заказ № Издательство «Николаев», г. Балашов, Саратовская обл., а/я 55. Отпечатано с оригинал-макета, изготовленного издательской группой 412309, г. Балашов, Саратовская обл., ул. К. Маркса, 29. Печатное агентство «Арья», ИП «Николаев», Лиц. ПЛД № 68-52. 412309, г. Балашов, Саратовская обл., ул. К. Маркса, 43. E-mail: arya@balashov.san.ru |