Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
tvp.doc
Скачиваний:
2
Добавлен:
08.11.2019
Размер:
1.12 Mб
Скачать

Первая из них выводит окно с сообщением Msg и кнопку Ok. Вторая выводит в окне сообщение, изображение, определяемое константой

type TMsgDlgType = (mtWarning, mtError, mtInformation, mtConfirmation, mtCustom);

Соответствующее типу окна (предупреждение, ошибка, информация, подтверждение), и набор кнопок, определяемое множеством

TMsgDlgButtons = set of TMsgDlgBtn;

TMsgDlgBtn = (mbYes, mbNo, mbOK, mbCancel, mbAbort, mbRetry, mbIgnore, mbAll, mbHelp);

Результат, возвращаемый функцией, следует проанализировать, например,

if MessageDlg('Вы уверены, что файл надо удалить?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then …

Лабораторная работа № 6. Создание текстового редактора

Работа иллюстрирует использование стандартных диалоговых окон, меню, кнопок быстрого доступа, многострочного редактора Memo.

1. Откройте новый проект и разместите на форме компоненты MainMenu (главное меню), PopupMenu ( всплывающее меню). На странице Dialogs найдите и разместите на форме компоненты OpenDialog (диалоговое окно выбора имени файла для открытия), SaveDialog (диалоговое окно выбора имени файла для сохранения), FontDialog (выбор шрифта), ColorDialog (выбор цвета). Все эти компоненты изобразятся на форме в виде значков. Добавьте компонент Memo (редактор текста) и задайте его свойство Align (выравнивание) в alBottom . Установите заголовок формы - Блокнот.

Memo представляет собой многострочный редактор текста. Содержимое редактора хранится в свойстве Lines. Это - свойство класса TStrings (набор строк).

2. Задайте свойства компонентов для выбора имен файлов:

Компонент OpenDialog:

Свойство

Значение

Комментарий

DefaultExt

txt

Расширение имени файла по умолчанию

Title

Открытие текстового файла

Options. OfFileMustExist

true

Открываемый файл должен существовать

Filter

Все файлы | *.*

При просмотре будут видны все файлы

Компонент SaveDialog:

DefaultExt

txt

Расширение имени файла по умолчанию

Title

Сохранение текстового файла

Options. OverWritePrompt

true

Запрос перед перезаписью файла

Filter

Все файлы | *.*

При просмотре будут видны все файлы

3. Запустите Дизайнер меню, щелкнув два раза по значку MainMenu. В Дизайнере создайте пункты горизонтального меню c заголовками File и Help и названиями (свойство Name) File1, Help1. Создайте ниспадающие меню для пункта File - Open, Save, SaveAs, Exit и пункта Help - About с такими же значениями Name.

Рис. 9

4. Поместите под полосой меню Panel и расположите на ней три кнопки быстрого доступа (SpeedButton). Панель является контейнером для размещенных на ней компонентов, поэтому кнопки будут перемещаться вместе с панелью. Выберите свойство Gliph для нанесения изображений на кнопках. Файлы с изображениями находятся на диске в каталоге C:\Program Files\Common Files\Borland Shared\Images\Buttons. Найдите изображения для обозначения открытия и сохранения файла и выхода из программы. Форма примет вид рис. 9.

5. Создайте обработчики событий выбора пункта меню (щелкнув два раза по пункту меню):

procedure TForm1.OpenClick(Sender: TObject);

begin

// Метод Execute запускает диалог и возвращает True, // если для выхода из диалога была нажата кнопка OK , // т.е. файл был выбран

with OpenDialog1 do

if Execute then

begin

// Загружает в текстовый редактор файл // с заданным именем

Memo1.Lines.LoadFromFile(FileName);

//Добавляет имя файла в «историю»

HistoryList.Add(FileName); // Функция ExtractFileName возвращает имя файла без // пути,

// которое затем отображается в заголовке формы

Caption:=’Блокнот-’+ExtractFileName (FileName);

//Запоминается имя открытого файла

SaveDialog1.FileName:=FileName;

end;

end;

procedure TForm1.SaveClick(Sender: TObject);

begin

if OpenDialog1.FileName<>’’ then

// Если имя не пусто, то оно используется // для сохранения файла

Memo1.Lines.SaveToFile(SaveDialog1.FileName)

else

//иначе вызывается обработчик Сохранить Как

SaveAsClick(Sender);

end;

procedure TForm1.SaveAsClick(Sender: TObject);

begin

with SaveDialog1 do

if Execute then

begin

Memo1.lines.SaveToFile(FileName);

Caption:=’Блокнот-’+ ExtractFileName(File Name);

end;

end;

procedure TForm1.AboutClick(Sender: TObject);

begin

MessageDlg(‘Блокнот v. 1.00’, mtInformation, [mbOK],0);

end;

6. Запустите Дизайнер всплывающего меню, щелкнув два раза по значку PopUpMenu. В Дизайнере меню введите пункты Шрифт и Цвет с именами Font1 и Color1, соответственно, и с обработчиками события выбора пункта меню

procedure TForm1.Font1Click(Sender: TObject);

begin

If FontDialog1.Execute then // Выбор шрифта для текста

begin

Memo1.Font.Name:=FontDialog1.Font.Name;

Memo1.Font.Size:=FontDialog1.Font.Size;

Memo1.Font.Style:=FontDialog1.Font.Style;

end;

end;

procedure TForm1.Color1Click(Sender: TObject);

begin //Выбор цвета фона редактора

if ColorDialog1.Execute then Memo1.Color:=ColorDialog1.Color;

end;

procedure TForm1.ExitClick(Sender: TObject);

begin

Close;

end;

Всплывающее меню, в отличие от главного меню, появляется при щелчке правой кнопкой мыши по элементу, к которому оно привязано. Для привязки его к компоненту Memo1 установите свойство PopUpMenu для Memo1, равное PopUpMenu1 (PopUpMenu1 - имя созданного компонента PopUpMenu).

7. Обработчики событий для кнопок быстрого доступа сделайте такимиже, как и в главном меню, подставив в инспекторе объектов в качестве OnClick для первой кнопки - OpenClick, для второй - SaveClick, для третьей - ExitClick.

Задание: Добавить пункты меню «Поиск слова», «Замена слова» и «Печать». Для реализации последнего пункта воспользуйтесь справочной системой F1 по слову Printer.

Лабораторная работа № 7. Табличный ввод-вывод

Для представления входных или выходных данных в виде таблиц в Delphi может использоваться компонент TStringGrid - таблица, состоящая из переменных типа String. Основными свойствами являются ColCount - число столбцов в таблице и RowCount - число строк.

Для доступа к ячейкам таблицы предназначено индексированное свойство Cells, обращение к которому происходит как к двумерному массиву. Первый индекс у Cells - номер столбца, а второй - номер строки, что отличается от общепринятой математической традиции в матричных операциях.

В качестве примера напишем программу для умножения двух матриц.

1. Разместите на форме три компонента TStringGrid и установите их свойство Name в A,B,C, соответственно. Таблица C будет содержать результат умножения. Для всех таблиц установите в инспекторе объектов значения свойств ColCount и RowCount, равные 3, FixedRows := 0, FixedCols:=0, Options.GoEditing := True. Добавьте Label с надписью X , Button с надписью = (см. рис.), строку редактирования Edit (Рис. 10). При изменении содержимого Edit1 размерности матриц должны соответственно изменяться.

Рис. 10

2. Напишите обработчики событий OnClick и OnChange

procedure TForm1.Button1Click(Sender: TObject);

var i,j,k,n, Sum: integer;

begin

n:=A.ColCount-1;

for i:=0 to n do

for j:=0 to n do

begin

Sum := 0;

for k:=0 to n do

Sum:=Sum+ StrToInt(A.Cells[k,i])*StrToInt(B.Cells[j,k]);

С.Сells[j,i]:=IntToStr(Sum);

end;

end;

procedure TForm1.Edit1Change(Sender: TObject);

var i: integer;

begin

try

i:=StrToInt(Edit1.text);

if i > 0 then

begin

a.colcount:=i; a.rowcount:=i;

b.colcount:=i; b.rowcount:=i;

c.colcount:=i; c.rowcount:=i;

end;

except

ShowMessage('Неправильный ввод');

end;

end;

Задание: переделайте пример так, чтобы матрицы создавались в процессе выполнения программы динамически в соответствии с введенной размерностью (см. следующую лаб. работу).

Лабораторная работа № 8. Динамическое создание интерфейсных элементов

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

Цель - при нажатии некоторой кнопки создать вторую кнопку с названием «Привет». Создайте новый проект и разместите на нем одну кнопку с заголовком «Создать». В обработчик события щелчка этой кнопки запишите

procedure TForm1.Button1Click(Sender: TObject);

begin

// Экземпляр новой кнопки создается методом-конструктором // Create. Адрес экземпляра заносится в переменную // MyButton. Аргументом Create является

// компонент-владелец кнопки, т.е.форма

MyButton := TButton.Create(Form1);

// Далее указывается местонахождение кнопки

MyButton.Parent := Form1;

MyButton.Left := 60; // Расстояние от левого края формы

MyButton.Top := 15; // Расстояние от верхнего края формы}

MyButton.Caption := ‘Привет!’;

end;

Саму переменную класса TButton объявите как глобальную в секции Implementation модуля:

var MyButton: TButton;

Комментарий: Каждый компонент имеет, во-первых, предка, у которого он наследует свойства и методы, во-вторых, владельца (Owner), который может автоматически создавать и уничтожать данный компонент (вызывает его конструкторы и деструкторы при своем создании и уничтожении), в-третьих, родительский компонент (Parent), на котором данный компонент расположен визуально. При динамическом создании необходимо задавать имя владельца Owner параметром метода Create и имя родителя в свойстве Parent компонента, что выше и было сделано. Владельцем компонентов обычно является форма, а родителями могут быть формы, панели и группы.

Заметьте, что метод деструктор Free для уничтожения кнопки здесь не использовался. Кнопку уничтожит владелец-форма «вместе с собой». Если же требуется уничтожить кнопку раньше, до закрытия формы, можно предусмотреть еще одну кнопку с надписью Удалить и в обработчик события OnClick для нее занести строку

MyButton.Free;

Более подробную информацию о динамическом создании элементов можно получить в [4].

Лабораторная работа № 9. Графика в Delphi.

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

Графические функции Delphi объединены (инкапсулированы) в классе TСanvas (холст). Изображения строятся с помощью свойств и методов TCanvas. Свойство Canvas типа TСanvas есть у многих визуальных компонентов, например, у формы. В инспекторе объектов Canvas не отображается, к нему можно обратиться только программно. Если у компонента нет такого свойства, то на этом компоненте часто можно разместить компонент PaintBox («рамка для холста», см. страницу System палитры компонентов), у которого есть свойство Canvas. Для рисования класс Canvas включает свойства: Font (шрифт), Pen (перо) и Brush (кисть).

Перо характеризуется свойствами: Color (цвет), Width (толщина), Style (стиль). Кисть характеризуется цветом и стилем.

Графические функции LineTo (нарисовать линию), Rectangle (нарисовать прямоугольник) и др. являются методами TCanvas. Справку по свойствам и методам Canvas см. в Приложении.

Область рисования на холсте состоит из точек (пикселов). Пикселы нумеруются начиная с нуля. Нумерация по оси X происходит слева направо, по оси Y – сверху вниз. Пикселы образуют целочисленную экранную систему координат.

Например, чтобы нарисовать на форме прямоугольник, необходимо написать

MainForm.Canvas.Rectangle (10, 10, 200, 100) .

Первые два аргумента у метода – координаты IX1 и IY1 правого верхнего угла квадрата, следующие два – координаты IX2 и IY2 левого нижнего угла.

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

Рис. 11. Преобразование физических координат в экранные

График строится исходя из следующих соотношений между физическими координатами и экранными координатами , (напомним, что на экране координата iy растет сверху вниз):

(x-x1) / (x2-x1) = (ix-ix1) / (ix2-ix1),

(y-y2) / (y1-y2) = (ix-iy2) / (iy1-iy2).

Для масштабирования удобно написать следущие четыре функции и постоянно ими пользоваться.

Прямое масштабирование:

function GetIX (x: real): integer;

begin

Result := ixLeft + Round( (x - x1) * ixWidth / (x2 - x1));

end;

function GetIY (y: real): integer;

begin

Result := iyTop + Round( (y2 - y) * iyHeight / (y2 - y1));

// Отсекаем то, что выходит за границы прямоугольника

if Result >= (iyTop+iyHeight)-1 then

Result := iyTop + iyHeight-1;

if Result <= iyTop then

Result := iyTop;

end;

Обратное масштабирование:

function GetX (ix: integer): real;

begin

Result := x1 + ( ix - ixLeft ) * ( x2 - x1 ) / ixWidth ;

end;

function GetY (iy: integer): real;

begin

Result := y1 + ( iyTop + IyHeight - iy ) * (y2 - y1) / iyHeight ;

end;

Здесь ixWidth, iyHeight – ширина и высота,

ixLeft, iyTop – координаты верхнего левого угла экранной области рисования.

Для примера изобразим внутри PaintBox график функции y = sin(x).

N := 100;

x1 := -pi*2;

x2 := pi*2;

Y2 := 1;

Y1 := -1;

dx := (x2-x1) / N;

x := x1;

y := sin(x);

with PaintBox1, PaintBox1.Canvas do

begin

// Экранные границы совпадают с границами PaintBox1

ixLeft := 0;

iyTop := 0;

ixWidth := Width;

iyHeight:= Height;

// Делаем текущей первую точку

ix := GetIX(x);

iy := GetIY(y);

MoveTo(ix,iy)

// В цикле соединяем текущую и новую точки

for i := 1 to n-1 do

begin

x := x + dx;

y := sin(x);

ix := GetIX(x);

iy := GetIY(y);

LineTo(ix,iy);

end;

end;

Где расположить эти строчки кода? Можно, конечно, в любом обработчике событий. Однако следует обратить внимание, что после минимизации окна программы или перекрытия его другими окнами изображение на PaintBox портится. Чтобы этого не происходило, приведенные выше операторы обязательно должны присутствовать (или быть продублированы) в обработчике события OnPaint для компонента PaintBox. Событие OnPaint возникает в случае, если визуальный компонент требует перерисовки.

Также важно помнить следующие правила.

1. В качестве аргументов графических методов следует использовать только относительные значения координат (нормированные относительно размеров области рисования). В противном случае при изменении размеров формы, компонентов или разрешения экрана график неизбежно испортится. При использовании методов масштабирования, описанных выше, такие проблемы, как правило, не возникают.

2. На графике не должно быть «пустот». Максимальные и минимальные значения логических и физических координат должны соответствовать друг другу. Эта проблема также решается правильным масштабированием.

Лабораторная работа № 10. Создание графического класса

Видоизменим написанную нами программу.

Создадим класс TGrafik, включающий поля, свойства и методы, и пригодный для изображения произвольных функций, заданных своими значениями. В качестве базового класса (непосредственного предка) выберем класс TPaintBox, поддерживающий через свойство Canvas основные графические функции. Класс TGrafik будет дополнительно содержать в качестве свойств границы области рисования, которые могут отличаться от границ PaintBox. Добавим индексированное свойство Series, предназначенное для хранения пар значений физических координат (аналогичное свойство есть у компонента Chart). Для этого надо проделать следующие шаги.

1. Откройте новый проект. Выберите пункт меню File | New | Unit. Сохраните модуль. Подключите стандартный модуль ExtCtrls. Запишите объявление типов TPhysCoord и TGrafik.

unit Grafik;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, extctrls;

type

TPhysCoord = record

x, y: real;

end;

TGrafik = class(TPaintBox)

Private

// Поля для экранных коорд.обл.графика

ixLeft, iyTop, ixWidth, iyHeight: integer;

protected

procedure SetTop (v: integer);

procedure SetLeft (v: integer);

procedure SetWidth (v: integer);

procedure SetHeight (v: integer);

public

// Физические координаты области рисования

x1, x2, y1, y2: real;

// методы масштабирования

function GetIX (x: real): integer;

function GetIY (y: real): integer;

function GetX (ix: integer): real;

function GetY (iy: integer): real;

// Метод прорисовки рамки

procedure SetBorder(c: TColor; Cleaning: boolean);

// Основной метод рисования

procedure SetSeries(i: integer; Coord: TPhysCoord);

// Логические координаты области рисования.

// Выполнены в виде свойств.

property iLeft: integer read ixLeft write SetLeft;

property iTop: integer read iyTop write SetTop;

property iWidth: integer read ixWidth write SetWidth;

property iHeight: integer read iyHeight write SetHeight;

// Свойство для хранения физических координат

property Series[i: integer]: TPhysCoord write SetSeries;

end;

Свойство описывается следующим образом: служебное слово property, затем название и тип свойства. После служебных слов read и write записываются имена методов чтения и записи свойства, соответственно. Метод чтения описывается как функция. Если потребности в специальном методе чтения нет, то вместо имени метода чтения указывается имя поля, хранящего значения свойства. Если свойство используется только для чтения или только для записи, то соответствующий метод может быть опущен.

В секции Implementation, как обычно, находятся реализации свойств и методов класса.

implementation

// Методы установки экранных границ области рисования

procedure TGrafik.setTop (v: integer);

begin

if iyTop <>v then

begin

iyTop:=v;

Paint;

end;

end;

procedure TGrafik.SetLeft (v: integer);

begin

if ixLeft <>v then

begin

ixLeft:=v;

Paint;

end;

end;

procedure TGrafik.SetWidth (v: integer);

begin

if ixWidth <>v then

begin

ixWidth:=v;

Paint;

end;

end;

procedure TGrafik.SetHeight (v: integer);

begin

if iyHeight <>v then

begin

iyHeight:=v;

Paint;

end;

end;

// Методы масштабирования

function TGrafik.GetIX (x: real): integer;

begin

Result := ixLeft + Round( (x - x1) * ixWidth / (x2 - x1));

end;

function TGrafik.GetIY (y: real): integer;

begin

Result := iyTop + Round( (y2 - y) * iyHeight / (y2 - y1));

// Отсекаем то, что выходит за границы прямоугольника

if Result >= (iyTop+iyHeight)-1 then

Result := iyTop + iyHeight-1;

if Result <= iyTop then

Result := iyTop;

end;

function TGrafik.GetX (ix: integer): real;

begin

Result := x1 + ( ix - ixLeft ) * ( x2 - x1 ) / ixWidth ;

end;

function TGrafik.GetY (iy: integer): real;

begin

Result := y1 + ( iyTop + IyHeight - iy ) * (y2 - y1) / iyHeight;

end;

// Изображение рамки указанного цвета

// Если Cleaning = True, область рисования очищается

procedure TGrafik.SetBorder(c: Tcolor; Cleaning: boolean);

var p, b: TColor;

begin

with Canvas do

begin

if Cleaning then // Очистка

begin

p:=Pen.Color;

Pen.Color:=c;

// Метод закрашивает прямоугольник

Rectangle(ixLeft, iyTop, ixLeft + ixWidth, iyTop + iyHeight);

Pen.Color:=p;

end

else // Наложение

begin

b:=Brush.Color;

Brush.Color:=c;

// Метод "оконтуривает" прямоугольник

FrameRect(Rect(ixLeft, iyTop, ixLeft + ixWidth, iyTop + iyHeight));

Brush.Color:=b;

end;

end;

end;

// Метод записи свойства Series. Записываемые значения

// (координаты точек) не сохраняются, а сразу отображаются

// на графике.

// Cвойство Series является векторным [4] и метод его

// записи имеет два параметра: порядковый номер точки i

// и пару координат изображаемой точки.

procedure TGrafik.SetSeries(i: integer; Coord: TPhysCoord);

var ix, iy: integer; {Экранные координаты}

begin

// Получаем экранные координаты

ix := GetIX(Coord.x);

iy := GetIY(Coord.y);

if i<=0 then

// Обозначаем первую точку

Canvas.MoveTo(ix,iy)

else

// Соединяем предыдущую и текущие точки

Canvas.LineTo(IX,IY);

end;

end.

2. Для тестирования класса создайте форму со следующими интерфейсными элементами: кнопка bPaint c надписью Рисовать, панель pGraph, группа GroupBox, в которой находятся шесть компонентов ввода-вывода с приглашениями. Внешний вид программы во время выполнения представлен на рис. 12, где в качестве примера представлен график функции y(t)=sin(wt)/(wt).

На странице Win32 палитры компонентов найдите компонент UpDown и расположите его справа от строки редактирования edFreq частоты w. Компонент будет использоваться для автоматического ее приращения. Свяжите UpDown1 с edFreq, указав в его свойстве Associate строку edFreq. В свойстве Position (текущее значение счетчика) укажите значение 2.

Подключите (uses Grafik) ранее созданный модуль с TGrafik. В секции Implementation непосредственно перед обработчиками объявите переменную g: TGrafik.

Рис. 12

3. Создайте обработчик события OnClick для кнопки bPaint с подписью Рисовать.

procedure TMainForm.bPaintClick(Sender: TObject);

var i,n: integer;

x0,xk,dx,w, YMax, YMin: real;

Coord: TPhysCoord;

fontsize: byte;

begin

try

n:=StrToInt(edNum.text);

// Частота равна текущей позиции счетчика:

w:=UpDown1.position;

edFreq.text:=FloatTostr(w);

x0:=StrToFloat(edInit.text);

xk:=StrToFloat(edEnd.text);

Ymax:=StrToFloat(edMax.text);

Ymin:=StrToFloat(edMin.text);

dx := (xk-x0) / n;

with g, g.canvas do

begin

// Физические координаты области значений функции

x1:=x0; x2:=xk;

y1:=YMin; y2:=YMax;

// Рисуем рамку

SetBorder(clGreen,True);

// Задаем цвет и толщину линии

Canvas.Pen.Color:=clRed; // Цвет линии

Canvas.Pen.Width:=3; // Толщина линии

// Формируем ряд из физических координат // и передаем в График

Coord.x:=x0;

for i := 0 to n-2 do

begin

Coord.x:=Coord.x + dx; // Коорд. X

Coord.y:= sinc(w * Coord.x); // Коорд. Y

Series[i]:= Coord;

end;

// Выводим надпись по оси X

Canvas.TextOut(iLeft,Top, 'График функции y(t)=sin(w*t)/(w*t)');

Canvas.TextOut(iLeft, iTop+iHeight+1, 'В р е м я');

// Выводим вертикально расположенную надпись по оси Y

fontsize:=12;

TextOutVert ('А м п л и т у д а', handle, g.iLeft-fontsize-2, g.iHeight+g.itop, fontsize);

end;

except

// Чтобы не зациклить OnPaint, обработчик исключений

// сделан пустым. Теперь при ошибке ввода не появится

// сообщение и не будет выполняться никаких действий

end;

end;

Функция sinc определена следующим образом:

function sinc(x: real): real;

// Функция, которая будет представлена на графике

begin

if x<>0 then

sinc:=sin(x)/x

else

sinc:=1;

end;

Так как класс TCanvas не содержит методов для вывода наклонных текстов, для вывода текста по оси Y здесь используется процедура TextOutVert, содержащая вызов функции API Win32 TextOut.Это тот случай, когда возможностей компонентов Delphi не хватает.

procedure TextOutVert (s: string; h: Thandle; x,y: integer; fh: byte);

// Вывод вертикального текста

var lf: TlogFont;

fnt,oldFnt: hfont;

begin

with lf do

begin

lfheight:=fh; // Высота текста

lfWeight :=FW_NORMAL;

lfWidth:=0;

lfItalic:=1;

lfUnderline:=0;

lfCharSet:= 0;

lfStrikeOut:=0;

LFEscapement:=900;

StrCopy(lfFaceName,'Arial Cyr');

end;

fnt := CreateFontIndirect(Lf);

OldFnt := SelectObject(h,fnt);

SetTextCharacterExtra(h,1);

winprocs.TextOut(h,x, y, pchar(s), length(s));

selectObject(h,oldfnt);

DeleteObject(Fnt);

end;

Чтобы график перерисовывался при изменении его параметров, в инспекторе объектов назначьте приведенный выше обработчик bPaintClick всем строкам редактирования.

4. Важнейший этап – создание и инициализация графика. Это уместно сделать в обработчике события создания формы:

procedure TMainForm.FormCreate(Sender: TObject);

begin

g := TGrafik.create(MainForm); // Владелец - форма

with g do

begin

Parent:=pGraph; // Родительпанель pGraph

Align:=alclient;

// Назначаем событиям обработчики

OnMouseDown := pGraphMouseDown;

OnPaint := bPaintClick;

// Координаты области рисования

// (внутренний прямоугольник)

iLeft:=20; iTop:=20;

iWidth := pGraph.Width - iLeft*2;

iHeight := pGraph.Height - iTop*3;

end;

end;

Обратите внимание, чтобы график g изображался сразу после создания окна или перерисовывался после перекрытий другими окнами, его событию g.OnPaint здесь присваивается обработчик bPaintClick.

5. Создание измерителя значений. В обработчике события OnMouseDown панели pGraph запишем код

procedure TMainForm.pGraphMouseDown(Sender: TObject; Button: TMouseButton;

Shift: TShiftState; X, Y: Integer);

begin

pGraph.ShowHint:=True;

// Измеряем значение кривой в точке

// вызовом функций обратного преобразования

pGraph.Hint:=FloatToStrF(g.GetX(X),ffFixed,5,2) +':'+FloatToStrF(g.GetY(Y),ffFixed,5,2);

end;

Теперь при щелчке на изображении во всплывающей подсказке появятся значения физических координат. Чтобы этот обработчик вызывался при щелчке по графику, в обработчике OnCreate формы (см. листинг п. 4) было произведено назначение

g.OnMouseDown := pGraphMouseDown;

Задания. Модифицируйте класс TGrafik, добавив в него координатную сетку и подписи значений по осям, и введя свойство «тип графика», изменение которого перерисовывает график в виде столбиковой диаграммы. Добавьте свойство, установка которого в True приводит к автоматическому масштабированию графика по размеру рамки. Предусмотрите возможность диалогового изменения цвета и фона рисунка с помощью компонента ColorDialog.

Лабораторная работа № 11. Предопределенные графические классы

Свойства и методы TCanvas предназначены для создания новых изображений, но в Delphi имеются также несколько классов для хранения и обработки изображений, уже созданных в различных графических форматах [1]. Эти классы не являются компонентами, их экземпляры нужно создавать «вручную». Три вида изображений, стандартных для Windows, инкапсулированы в классах TBitMap (битовая карта, растровая картинка), TIcon (значок), TMetaFile (метафайл). Для работы с популярным форматом Jpeg предназначен класс TJpegImage. Эти четыре класса являются потомками абстрактного класса TGraphic.

Опишем некоторые основные методы и свойства, используемые далее в лабораторных работах. На уровне TGraphic определены:

procedure LoadFromFile(const FileName: string); virtual;

Загрузка изображения из файла

procedure SaveToFile(const FileName: string); virtual;

Запись изображения в файл

property Empty: Boolean;

истина, если объект не содержит данных

property Height: Integer;

высота графического объекта

property Width: Integer;

ширина

property Transparent: Boolean;

прозрачен ли объект при отрисовке

Первые два метода перекрываются в классах потомках.

Свойства TBitMap

property TransparentColor: TColor;

Цвет, который будет прозрачным, если TransparentMode = tMFixed и Transparent=True

property TransparentMode: TTransparentMode; type TTransparentMode= (tmAuto, tmFixed);

Если tmAuto, прозрачны будут участки с цветом верхнего левого пиксела

property Canvas: TCanvas;

Холст для рисования (имеется только у TBitMap!)

Изображения формата Jpeg получаются сжатием изображений в формате битовой карты. Соответственно следующее свойство TJpegImage

property CompressionQuality: TJPEGQualityRange;

type TJPEGQualityRange = 1..100

определяет качество сжатого изображения и его размер (значение по умолчанию 75), а метод Compress сжимает Jpeg-изображение с учетом этого значения.

Метод

procedure Assign(Source: TPersistent); override;

классов TJpegImage и TBitMap копирует изображение из Source в объект, вызвавший этот метод, при этом происходит преобразование форматов.

Часто бывает удобно пользоваться классом TPicture, который является надстройкой над TBitMap, TJpegImage, TIcon, TMetaFile и может содержать объекты любого из этих классов.

Объекты хранятся в его свойстве Graphic: TGraphic (к ним также можно обратиться через одноименные свойства TPicture). Методы SaveToFile и LoadFromFile класса TPicture анализируют тип файла по его расширению и вызывают методы SaveToFile и LoadFromFile соответствующих объектов, например TBitMap.

Следующий простой пример демонстрирует использование объекта TBitMap для построения движущихся частично прозрачных изображений. Изображение (эллипс, вписанный в прямоугольник) рисуется на BitMap и двигается по окружности при наступлении события OnTimer компонента TTimer. Интервал Timer1.Interval между событиями OnTimer вводится с помощью TEdit.

Рис. 13

unit Unit1;

interface

uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, ComCtrls;

type

TForm1 = class(TForm)

Timer1: TTimer;

UpDown1: TUpDown;

Edit1: TEdit;

procedure FormCreate(Sender: TObject);

procedure Timer1Timer(Sender: TObject);

procedure Edit1Change(Sender: TObject);

procedure FormPaint(Sender: TObject);

private

{ Private declarations }

public

{ Public declarations }

end;

var

Form1: TForm1;

implementation

{$R *.DFM}

var x, y, orbita, rad: integer;

angle,pi20: real;

b, pic, buffer: TBitMap;

Dest, Source: Trect;

procedure TForm1.FormCreate(Sender: TObject);

begin

b:=TBitMap.Create;

b.LoadFromFile('athena.bmp');

angle:=pi/2;

pi20:=pi/20;

clientwidth:=400;

ClientHeight:=400;

rad:= clientwidth div 4;

orbita:=clientwidth div 2 - rad;

x:=orbita;

y:=0;

buffer:=TBitMap.Create;

buffer.Height:=rad;

buffer.Width:=rad*2;

Pic:=TBitMap.Create;// Создание картинки

Pic.Height:=rad;

Pic.Width:=rad*2;

with pic.Canvas do begin

pen.Color:=clGreen;

brush.Color:=clGreen;

Rectangle(0,0,rad*2,rad);

pen.color:=clBlue;

brush.Color:=ClBlue;

Ellipse(0,0,rad*2,rad);

end;

{Прозрачным на картинке будет голубой цвет}

Pic.TransparentColor:=clBlue;

Pic.Transparent:=true; // Активизация прозрачности

end;

procedure TForm1.Timer1Timer(Sender: TObject);

begin

{ Восстановить фон из buffer}

Canvas.CopyRect(Source, buffer.Canvas, Dest);

angle := angle+pi20;

x := orbita+round(orbita*cos(angle));

y := orbita-round(orbita*sin(angle));

{ Запомнить фон нового места в буфере}

Source := Rect(x,y,x+2*rad,y+rad);

Dest := Rect(0,0,2*rad,rad);

buffer.Canvas.CopyRect(Dest, Canvas, Source);

{ Нарисовать картинку на новом месте}

Canvas.Draw(x,y,Pic);

end;

procedure TForm1.Edit1Change(Sender: TObject);

begin

Timer1.Interval:=StrToInt(Edit1.Text);

end;

procedure TForm1.FormPaint(Sender: TObject);

begin

Source:=rect(x,y,x+2*rad,y+rad);

Dest:=rect(0,0,2*rad,rad);

with Canvas do begin

StretchDraw(ClientRect,b); // Вывод обоев

buffer.Canvas.CopyRect(dest,Canvas,Source);

Draw(x,y,Pic); // Вывод картинки

end;

end;

Упражнения. Нарисуйте другие, более сложные фигуры.

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]