Студопедия

КАТЕГОРИИ:

АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

События компонента DrawGrid




Лабораторная работа 6. Сетки строк

Класс TDrawGrid

Компонент DrawGrid предназначен для создания таблицы, в ячейках которой расположены данные. Компонент обеспечивает двумерное представление данных, упорядоченных по строкам и столбцам.

Таблица делится на две части – фиксированную и рабочую. Фиксированная часть служит для показа заголовков столбцов/строк и для ручного управления их размерами. Обычно фиксированная часть занимает крайний левый столбец и самый верхний ряд таблицы. Она может содержать произвольное количество столбцов и рядов, при чём эти величины можно изменять как в процессе разработки, так и программно. Рабочая часть состоит из ячеек, в которых находятся данные. Если рабочая часть не помещается целиком в пределах окна компонента, то у компонента автоматически появляются полосы прокрутки. При прокрутке рабочей области фиксированная часть не исчезает, но меняется её содержимое – заголовки строк и рядов.

Заносить данные в ячейки таблицы можно только в ходе работы программы.

Свойства компонента DrawGrid

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

Рассмотрим основные свойства, доступные во время разработки.

BorderStyle определяет наличие или отсутствие внешней рамки таблицы;
ColCount устанавливает количество столбцов таблицы, включая столбцы фиксированной части;
DefaultColWidth определяет ширину столбца по умолчанию;
DefaultDrawing при значении, равном True, происходит автоматическая прорисовка служебных элементов таблицы (фиксированной зоны, фона и прямоугольника сфокусированной ячейки и т.д.). Если свойство установлено в False, то прорисовки этих элементов необходимо определять в обработчике события OnDrawCell;
DefaultRowHeight содержит значение высоты строки по умолчанию;
FixedColor устанавливает цвет фиксированной зоны;
FixedCols определяет количество столбцов фиксированной зоны;
FixedRows определяет количество строк фиксированной зоны;
RowCount устанавливает количество строк таблицы.

Дополнительно к перечисленным в таблице свойствам необходимо обратить особое внимание на свойство Options, определяющее некоторые особенности поведения компонента DrawGrid. Свойство определяется следующим образом:

Type

 TGridOption = (goFixedVertLine, goFixedHorzLine, goVertLine, goHorzLine, goRangeSelect, goDrawFocusSelected, goRowSizing, goColSizing, goRowMoving, goColMoving, goEditing, goTabs, goRowSelect, goAlwaysShowEditor, goThumbTracking);

 TGridOptions = set of TGridOption;

 property Options: TGridOptions;

Каждое значение характеризует особенности поведения таблицы в процессе работы приложения:

goAlwaysShowEditor значение, равное True, позволяет редактировать сфокусированную (выделенную) ячейку. Редактирование возможно после выбора ячейки клавишей Tab (Tab+Shift). Подсвойство игнорируется, если goEditing установлено в False;
goColMoving значение, равное True позволяет перемещать столбцы (для этого нужно нажать левую кнопку мыши на фиксированной ячейке перемещаемого столбца и, удерживая кнопку нажатой, переместить столбец на новое место);
goColSizing контролирует изменение ширины столбцов;
goDrawFocusSelected включение этого свойства приводит к выделению ячейки, в которой находится фокус. Если же свойство равно False, то ячейка, имеющая фокус, не выделяется никаким цветом;
goEditing Значение True свойства позволяет редактировать содержимое ячейки (свойство игнорируется, если значение goRowSelect равно True). Редактирование начинается после щелчка мыши или нажатия клавиши F2 и завершается при щелчке по другой ячейке или нажатии Enter;
goFixedHorzLine включение свойства заставляет прорисовывать горизонтальные полосы для разделения строк в фиксированной области;
goFixedVertLine установление значения в True заставляет использоваться вертикальные полосы для разделения столбцов в фиксированной области;
goHorzLine при значении False будут отсутствовать горизонтальные линии в рабочей области;
goRangeSelect для того чтобы пользователь мог выбирать насколько ячеек одновременно, данное свойство следует установить в True (значение свойства будет игнорироваться, если свойство goEditing равно True)
goRowMoving свойство аналогично goColMoving, разрешает перемещение ряда;
goRowSelect значение True этого свойства позволяет выделять все (а не отдельные) ячейки строки, в этом случае будет игнорироваться свойство goAlwaysShowEditor;
goRowSizing включение свойства позволяет вручную (мышью) изменять высоту строк;
goTabs если свойство установлено в True, то можно выбирать ячейки клавишей Tab (Shift+Tab);
goThumbTracking ячейки таблицы будет обновляться в процессе использования полосы прокрутки. Если значение равно False, то обновление ячеек произойдёт только после окончания прокрутки.
goVertLine при значении свойства, равном False, в рабочей области отсутствуют вертикальные линии.

Кроме перечисленных свойств, во время выполнения программы становятся доступными ещё некоторые свойства.

Свойство Col/Row определяет номер столбца/строки сфокусированной (выделенной) ячейки. Нумерация и строк и столбцов начинается с нуля, включая строки и столбцы фиксированной зоны.

Номер самого левого столбца, видимого в прокручиваемой зоне ячеек, содержится в LeftCol, а номер самого верхнего ряда в свойстве TopRow.

Свойство EditorMode отвечает за возможность редактирования ячеек (свойство будет игнорироваться, если goAlwaysShowEditor равно True или goEditing равно False). Когда во время работы программы пользователь нажимает кнопку F2, EditorMode устанавливается в True автоматически. После того как пользователь нажимает клавишу ввода, свойство принимает значение False.

Свойство Selection позволяет определить координаты текущего выделения. Описывается свойство следующим образом:

Type

 TGridCoord = record

X: Longint;

Y: Longint;

 end;

 TGridRect = record

case Integer of

0: (Left, Top, Right, Bottom: Longint);

1: (TopLeft, BottomRight: TGridCoord);

 end;

property Selection: TGridRect;

Свойство Selection определяет группу выделенных ячеек в координатах левая верхняя и правая нижняя ячейки. После выделения сфокусированной окажется правая нижняя ячейка.

Методы компонента DrawGrid

Экранные координаты прямоугольника ячейки можно получить по номерам столбца ACol и ряда ARow с помощью метода CellRect:

function CellRect(ACol, ARow: Longint): TRect;

где тип TRect – это

Type

 TRect = record

case Integer of

0: (Left, Top, Right, Bottom: Integer);

1: (TopLeft, BottomRight: TPoint);

 end;

 TPoint = record

X: Longint;

Y: Longint;

 end;

Получить номер столбца ACol и номер строки ARow по экранным координатам (X,Y) точки можно с помощью метода MouseToCell:

procedure MouseToCell(X, Y: Integer; var ACol, ARow: Longint);

Например, необходимо определить по какой ячейке был произведён щелчок мышью, то можно воспользоваться обработчиком события OnMouseDown:

procedure TForm1.DrawGrid1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);

 var Acol, Arow :integer; {переменные для хранения номера столбца/строки}

Begin

 DrawGrid1.MouseToCell(x, y, Acol, Arow);

{используя параметры события OnMouseDown,

определяем номера строки и столбца}

end;

События компонента DrawGrid

Событие OnColumnMoved возникает при перемещении столбца. Оно происходит только тогда, когда подсвойство goColMoving равно True. Заголовок обработчика этого события имеет вид:

procedure TForm1.DrawGrid1ColumnMoved(Sender: TObject; FromIndex, ToIndex: Integer);

Параметр FromIndex содержит «старый» индекс столбца, а ToIndex – «новый» индекс перемещаемого столбца.

Событие OnRowMoved возникает при перемещении строки. Оно происходит только тогда, когда goRowMoving включено в свойство Options. Заголовок обработчика этого события имеет вид:

procedureTForm1.StringGrid1RowMoved(Sender: TObject; FromIndex, ToIndex: Integer);

Событие OnTopLeftChanged происходит при изменении значения TopRow или LeftCol в результате прокрутки рабочей зоны:

procedure TForm1.DrawGrid1TopLeftChanged(Sender: TObject);

Событие OnSelectCell возникает при попытке выделить ячейку с табличными координатами (ACol, ARow). В параметре CanSelect обработчик сообщает о возможности выделения ячейки. Установите его значение равным False, чтобы пользователь не мог выделять ячейку. Событие описывается следующим образом:

procedure TForm1.DrawGrid1SelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);

Cобытие OnSetEditText возникает по завершении редактирования ячейки с координатами (ACol, ARow). В параметре Value обработчик получает результат ввода или редактирования текста. Событие произойдёт только в том случае, когда в свойство Options содержит значение goEditing. Описывается событие так:

procedure TForm1.DrawGrid1SetEditText(Sender: TObject;
ACol, ARow: Integer; const Value: String);

События OnGetMaskEdit и OnGetEditText возникают при редактировании текста в ячейке с табличными координатами (ACol, ARow). В параметре Value первого события обработчик должен вернуть шаблон для редактора TEditMask. Параметр Value для события OnGetEditText должен содержать текстовую информацию для редактора TEditMask. Описание событий выглядит следующим образом:

procedure TForm1.DrawGrid1GetEditMask(Sender: TObject;
ACol, ARow: Integer; var Value: String);

procedure TForm1.DrawGrid1GetEditText(Sender: TObject;
ACol, ARow: Integer; var Value: String);

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

procedure TForm1.DrawGrid1DrawCell(Sender: TObject;
ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

Событие происходит в случае необходимости перерисовки ячейки с номером столбца ACol и номером строки ARow. Параметр Rect определяет прямоугольник прорисовки, а State - состояние ячейки (gdSelected ‑ ячейка выделена, gdFocused ‑ ячейка сфокусирована, gdFixed ‑ ячейка принадлежит фиксированной зоне таблицы). Для прорисовки используется свойство Canvas.

Упражнение 6.1.1. Создайте приложение, которое позволяет просматривать символы системных шрифтов.





Решение

Создайте новый проект. Сохраните новое приложение в папке Fonts, файл модуля – под именем Main.pas, файл проекта – fonts.dpr.

1 этап. Визуальное проектирование

Измените значения свойств формы следующим образом:

Name Fonts
Caption Символы

Положите на форму компонент TPanel:

Align alTop
Caption  

Разместите на компоненте Panel1 компонент ComboBox (рис. 6.1.1.). Пусть имя этого компонента будет FontListCB.

Рис. 6.1.1

Далее расположите на форме компонент TDrawGrid:

Name FontDG
Align alClient
RowCount 7
ColCount 32
FixedCols 0
FixedRows 0
DafaultColWidth 20
DefaultRowHeight 20

Измените размеры формы так, чтобы сетка не имела полос прокрутки, а вокруг ячеек не было пустого пространства.

 

2 этап. Разработка программного кода

Для того чтобы содержимое каждой ячейки перерисовывалось, создадим обработчик события OnDrawCell для компонента FontDG. Для изображения символов шрифта воспользуемся свойством Canvas компонента FontDG. Непосредственно нам понадобится метод TextRect свойства Canvas. Этот метод используется для вывода текстовой информации в определённой ячейке. Обработчик события будет выглядеть так:

procedure TFonts.FontDGDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

Begin

 with FontDG.Canvas do

TextRect (Rect, Rect.Left, Rect.Top, Char((ARow+1)*32+ACol));

{параметры ячейки для вывода символов шрифта берутся из параметров обработчика события, а символ шрифта для отображения в ячейке определяется в зависимости от строки и столбца}

end;

Эксперимент. Сохраните проект. Убедитесь, что в ячейках таблицы отображаются символы системного шрифта, установленного по умолчанию. t

 

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

Названия всех экранных шрифтов можно узнать с помощью глобальной переменной Screen типа TScreen. Данная переменная автоматически добавляется во все приложения Delphi. Переменная Screen содержит информации о текущем состоянии экрана приложения: названия форм и модулей данных, которые используются приложением; данные об активной форме и компонентах, используемых этой формой; размер и разрешение используемого экрана; информацию о доступных приложению курсорах и шрифтах.

Информация о доступных приложению шрифтах содержится в свойстве Font, принадлежащем переменной Screen.

Создадим следующий обработчик:

procedure TFonts.FormCreate(Sender: TObject);

Begin

 with FontListCB do begin

Items := Screen.Fonts ;

{в свойстве Fonts переменной Screen содержатся названия всех экранных шрифтов}

ItemIndex :=Items.IndexOf(Font.Name);

{свойства IndexOf содержит номер строки в списке FontListCB,

которая выбрана, и, соответственно, содержит имя текущего шрифта}

 end;

end;

Эксперимент. Сохраните и запустите проект. Компонент FontDG содержит символы шрифта, установленного в FontListCB. Сколько шрифтов установлено на компьютере. Что происходит при выборе другого шрифта? t

 

Для того чтобы связать значение имени шрифта у FontDG и FontListCB, создадим ещё один обработчик события:

procedure TFonts.FontListCBClick(Sender: TObject);

Begin

 FontDG.Font.Name := FontListCB.Text ;

end;

Эксперимент. Сохраните и запустите проект. Что происходит при изменении шрифта? t

Класс TStringGrid

Компонент StringGrid предназначен для создания таблиц, в ячейках которых располагаются произвольные текстовые строки. Класс TStringGrid является прямым потомком класса TDrawGrid, от которого им унаследовано большинство свойств и методов. У данного класса появляется лишь несколько новых свойств.

Cells[ACol, ARow: Integer] определяет содержимое ячейки с координатами (ACol, ARow);
Cols[Index: Integer] содержит все строки колонки с номером Index;
Objects [ACol, ARow: Integer] обеспечивает доступ к объекту, связанному с ячейкой (ACol, ARow);
Rows[Index: Integer] содержит все строки столбца с номером Index.

Хорошей иллюстрацией работы компонента TStringGrid служит программная реализация игры «Жизнь».

Упражнение 6.2.1. Игра «Жизнь». Идея игры состоит в том, чтобы, начав с какого-нибудь простого расположения фишек (организмов), расставленных по различным клеткам доски, проследить за эволюцией исходной позиции под действием «генетических законов» Конуэя, которые управляют рождением, гибелью и выживанием фишек.

Генетические законы игры сводятся к следующему.

· Выживание. Каждая фишка, у которой имеются две или три соседние фишки, выживает и переходит в следующее поколение.

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

· Рождение. Если число фишек, с которыми граничит какая-нибудь пустая клетка, в точности равно трем (не больше и не меньше), то на этой клетке происходит рождение нового «организма», т. е. следующим ходом на нее ставится одна фишка.

Таким образом, что гибель и рождение всех «организмов» происходят одновременно. Вместе взятые, они образуют одно поколение или один «ход» в эволюции начальной конфигурации. Ходы Конуэй рекомендует делать следующим образом:

1) начать с конфигурации, целиком состоящей из черных фишек;

2) определить, какие фишки должны погибнуть, и положить на каждую из обреченных фишек по одной черной фишке;

3) найти все свободные клетки, на которых должны произойти акты рождения, и на каждую из них поставить по одной фишке белого цвета;

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

Пусть в нашей игре фишки n-го поколения будут умирать не сразу, а лишь после появления (n+2)-го поколения. Фишки разных поколений будут отличаться друг от друга цветом.

Решение

Создайте новый проект Delphi. Сохраните новое приложение в папке GameLife – файл модуля под именем Main.pas, файл проекта – GameLife.dpr.

1 этап. Визуальное проектирование (рис. 6.2.1).

Измените значения свойств формы следующим образом:

Name LifeFrm
Caption Жизнь

Положите на форму компонент TToolBar (панель инструментов) со страницы Win32. Измените его свойство следующим образом:

EdgeBorders [ebTop,ebBottom]

Сейчас панель инструментов будет находиться в самом верху формы, а её верхняя и нижняя сторона будут выделены вдавленной линией.

 

Рис. 6.2.1

Разместите на панели инструментов 5 кнопок. Для этого щёлкните правой кнопкой мыши на панели инструментов и в появившемся контекстном меню выберите пункт NewButton. На панели инструментов появится кнопка типа TToolButton. С помощью этой кнопки мы будем задавать произвольную первоначальную конфигурацию расположения фишек, поэтому назовите её RandomTBt.

Добавьте ещё одну кнопку и назовите её NewTBt. Эта кнопка понадобится для очистки игрового поля.

Поместите разделитель на панель инструментов. Для этого опять вызовите контекстное меню панели инструментов и выберите в нём пункт NewSeparator.

Поместите ещё одну кнопку на ToolBar1 (её свойство Name сделайте равным FadeTBt), разделитель и ещё две кнопки типа TToolButton (с именами соответственно RunTBt и StopTBt). С помощью этих кнопок мы будем управлять ходом игры. Кнопка FadeTBt будет регулировать отображение трёх или одного поколений фишек. Кнопки RunTBt и StopTBt для начала и остановки игры.

 

Для того чтобы поместить изображения на кнопки, нам понадобится компонент TImageList со страницы Win32. Этот компонент может содержать серию изображений.

Создадим изображение для кнопки RandomTBt. Воспользуемся программой ImageEditor, входящей в состав Delphi.

· Запустите ImageEditor, выполнив команду Пуск/ Программы/ Borland Delphi 5/ Image Editor.

· Для создания пиктограммы выберите в пункте меню File команду New Bitmap File (.bmp). В диалоговом окне Bitmap Properties задайте размеры изображения (Height и Width), равными 20.

· С помощью инструментов программы Image Editor создайте изображение для кнопки RandomTBt.

· Cохраните в папке Life под названием Bitmap1.bmp.

Задание для самостоятельного выполнения. Создайте изображение для кнопки NewTBt и сохраните его под именем Bitmap2.bmp.

 

Для остальных кнопок воспользуемся стандартным набором изображений Delphi.

Поместите изображения, предназначенные для кнопок приложения в компонент TImageList.

· Щёлкните правой кнопкой мыши по этому компоненту и в контекстном меню выберите пункт ImageList Editor…

· В диалоговом окне редактора изображений LifeFrm.Image1List ImageList щёлкните по кнопке Add.

· В диалоговом окне открытия файла выберите файл Bitmap1.bmp с изображение для кнопки RandomTBt. В редакторе изображений появится выбранное изображение под индексом 0. Аналогичным образом добавьте изображение для кнопки NewTBt (оно должно иметь индекс 1).

Изображения для трёх остальных кнопок выберите в папке С:/ Program Files/ Common Files/ Borland Shared/ Images/ Buttons.

· В диалоговом окне редактора изображений LifeFrm.Image1List ImageList щёлкните по кнопке Add, выберите файл С:/ Program Files/ Common Files/ Borland Shared/ Images/ Buttons/ Day.bmp. После щелчка по кнопке Open, появится окно (рис. 6.2.2) с сообщением «Размер изображения в day.bmp больше, чем размер, определенный в ImageList. Разделить на 2 обособленных изображения?» Щелкните по кнопке No.

· Установите Options диалогового окна редактора изображений в значение Crop – обрезать.

Добавьте изображения для кнопок FadeTBt (индекс равен двум), для RunTBt (индекс равен трём), для StopTBt (индекс равен четырём).

Рис. 6.2.2

Чтобы показать изображения на кнопках, установите свойство Images компонента ToolBar1 в ImagelList1, а у каждой кнопки свойству ImageIndex присвоить индекс соответствующего изображения в редакторе изображений (для кнопки RandomTBt - 0, для NewTBt - 1 и т.д.).

Эксперимент. Сохраните проект. Запустите, на панели инструментов должны появиться кнопки с созданными Вами изображениями. t

 

Для изображения жизни организмов нам понадобится компонент TStringGrid. Установите его свойства следующим образом:

Align alClient
ColCount 50
DefaultColWidth 10
DefaultRowHeight 10
FixedCols 0
FixedRows 0
Name LifeSGd
RowCount 25

Измените размеры формы так, чтобы у компонента LifeSGd не было полос прокрутки.

Смену поколений организмов будет отражать через каждую секунду. Воспользуемся компонентом Timer (страница System).

Класс TTimer поддерживает единственный обработчик события OnTimer. Это событие появляется через интервал времени заданный свойством Interval. Таким образом, если свойство Interval установлено в 1000 (миллисекунд), то обработчик события OnTimer будет вызываться каждую секунду.

В классе TTimer определено свойство Enabled, значение False которого приводит к игнорированию событий OnTimer, значение True позволяет обрабатывать события OnTimer.

Компонент Timer – это невизуальный компонентам Delphi, т.е. отображается он только на этапе проектирования приложения. Положите компонент Timer на форму установите значения свойств следующим образом:

Enabled True
Interval 1000

Итак, визуальное проектирование приложение завершено. Сохраните проект.

 

2 этап. Написание программного кода

Опишем глобальные переменные.

В разделе Const раздела Interface опишите две глобальные константы

MX = 50;                          {количество столбцов в LifeSGd}

MY = 25;                            {количество строк в LifeSGd}

В разделе Private класса LifeSGd опишите глобальную переменную

Fade: Boolean;

Эта переменная будет отвечать за количество поколений отображаемых приложением: если значение Fade равно True – будут отображаться три поколения организмов (фишек), иначе - только живые организмы (фишки), т.е. одно поколение.

Воспользуемся свойством Cells компонента LifeSGd для хранения состояния организмов колонии. Введем следующие обозначения:

0 - фишка мертва;

1 - фишка жива;

2 - фишка мертва одно поколение (на предыдущем ходе она была жива);

3 - фишка мертва два поколения.

 

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

procedure TLifeFrm.FormCreate(Sender: TObject);

 var i,j:integer;


Begin

 Timer1.Enabled := False;

 Fade := False;

 for I :=0 to MX-1 do

  for j :=0 to MY-1 do LifeSGd.Cells[i,j] := '0';

end;

Рассмотрим процедуру задания произвольной расстановки фишек – событие OnClick кнопки RandomTBt.

procedure TLifeFrm.RandomTBtClick(Sender: TObject);

 var x,y: Integer;

Begin

 Randomize;                   {включаем генератор случайных чисел}

 for y :=0 to MY-1 do

for x :=0 to MX-1 do

LifeSGd.Cells[x,y]:=IntToStr(Random(2));

{если в ячейку записывается единица, то фишка жива,

если в ячейку записывается ноль, то фишка считается мертвой}

end;

Кнопка NewTBt используется для очистки содержимого ячеек компонента LifeSGd. Поэтому в обработчике события OnClick данной кнопки нужно просто значению каждой ячейки присвоить ноль. Кроме того, надо выключить таймер. Обработчик события будет выглядеть так:

procedure TLifeFrm.NewTBtClick(Sender: TObject);

 var y,x: Integer;

Begin

 for y := 0 to MY-1 do

for x :=0 to MX-1 do LifeSGd.Cells[x,y] := '0';

 Timer1.Enabled := False;

end;

При нажатии кнопки FadeTBt будем изменять значение переменной Fade, которая показывает изображать или нет несколько поколений. Если Fade равно True, то кнопка будет вдавленной. Создайте следующий обработчик события:

procedure TLifeFrm.FadeTBtClick(Sender: TObject);

Begin

 Fade := not(Fade);

 FadeTBt.Down := Fade;

end;

Для запуска игры служит кнопка RunTBt. При её нажатии таймер должен начинать работать, кнопка RunTBt - становиться вдавленной, а кнопка StopTBt - принимать обычный вид. Все эти действия выполняются в данном обработчике:

procedure TLifeFrm.RunTBtClick(Sender: TObject);

Begin

 Timer1.Enabled := True;

 RunTBt.Down := True;

 StopTBt.Down := False;

end;

Кнопка StopTBt используется для остановки работы программы. Обработчик события OnClick этой кнопки должен выглядеть так:

procedure TLifeFrm.StopTBtClick(Sender: TObject);

Begin

 Timer1.Enabled := False;

 StopTBt.Down := True;

 RunTBt.Down := False;

end;

Эксперимент. Сохраните проект. Убедитесь в правильности функционирования написанного кода. t

 

Задавать расположение фишек можно и вручную. Для этого достаточно щелкнуть левой кнопкой мыши по нужной вам ячейке. Запрограммируем такой вариант расстановки фишек. Удобнее всего помечать фишки как живые в событии OnSelectCell компонента LifeSGd:

procedure TLifeFrm.LifeSGdSelectCell(Sender: TObject; ACol, ARow: Integer; var CanSelect: Boolean);

Begin

 if LifeSGd.Cells[Acol, Arow]='1'

then LifeSGd.Cells[Acol, Arow]:='0'

 else LifeSGd.Cells[Acol, Arow]:='1';

end;

Остановимся подробнее на том, как изменяется цвет каждой ячейки. Известно, что прорисовка ячеек происходит в событии OnDrawCell. Это событие происходит столько раз, сколько ячеек содержит компонент StringGrid (в задаче ‑ LifeSGd). Кроме того, событие вызывается каждый раз при изменении значения свойства Cells. Именно поэтому не приходилось вручную перерисовывать LifeSGd.

Схема изменения цвета ячейки достаточно проста: обработчик данного события проверяет значение свойства Cells ячейки (ACol, ARow) и в зависимости от него присваивает нужный цвет кисти свойства Canvas компонента LifeSGd. Живые фишки изображаются синим цветом, предыдущее поколение (фишки мёртвые в течение одного хода) ‑ светло- голубым цветом, фишки мёртвые в течение двух ходов ‑ светло-фиолетовым цветом, мёртвые фишки ‑ белым цветом. Однако если значение переменной Fade равно False, то отображаются только живые и мертвые клетки (без промежуточных состояний). После того как цвет установлен, остаётся только заполнить этим цветом нужную ячейку с помощью метода FillRect свойства Canvas. В результате процедура будет выглядеть следующим образом:

procedure TLifeFrm.LifeSGdDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);

Begin

 LifeSGd.Canvas.Brush.Color := clWhite;

 сase StrToInt(LifeSGD.Cells[ACol, ARow])of

1: LifeSGd.Canvas.Brush.Color := clBlue;

2: if Fade then LifeSGd.Canvas.Brush.Color := clBlue - 13000;

3: if Fade then LifeSGd.Canvas.Brush.Color := clBlue-17000;

 end;

 LifeSGd.Canvas.FillRect(Rect);

end;

Эксперимент. Запустите проект, обратите внимание, что после щелчков мышью по полю таблицы, клетки перекрашиваются. t

 

Итак, осталось написать последнюю процедуру, в которой будем определять, какие фишки выживут, а какие умрут. Именно здесь нам и понадобится таймер. На каждый «тик» таймера будет вызываться процедура OneStep, в которой оценивается текущее состояние фишек, и в зависимости от него строится новое расположение фишек. Добавьте название процедуры OneStep в раздел public описания класса формы TLifeFrm.

Public

 procedure OneStep;

Принцип выбора живых фишек следующий: просматриваем поочерёдно все ячейки; для каждой ячейки считаем количество окружающих её живых фишек; в зависимости от количества этих фишек заполняем элементы двумерного массива A либо нулём, либо единицей; далее просматриваем элементы этого массива A, и в зависимости от их значений изменяем свойство Cells компонента LifeSGd.

Для реализации этого принципа нам понадобится двумерный массив A, элементы которого соответствуют ячейкам компонента LifeSGd. Размерность массива A будет аналогична размерности LifeSGd. Кроме того, нам будут нужны два массива - константы DX и DY, содержащие приращение по вертикали и горизонтали, соответственно. Эти массивы понадобятся для просмотра соседних с клеткой ячеек.

procedure TLifeFrm.OneStep;

 const

DX : array [1..8] of Integer = (-1, 0, 1, 1, 1, 0,-1,-1);

DY : array [1..8] of Integer = (-1,-1,-1, 0, 1, 1, 1, 0);

 var

i, j, k, Count: Integer;

A: array [0..MX, 0..MY] of Byte;

Begin

 FillChar(A,SizeOf(A),0);          {обнуляем значения массива A}

 for i:=1 to MX-1 do                      {просматриваем все ячейки}

for j:=1 to MY-1 do begin

Count:=0;

{переменная Count используется для подсчёта количества живых фишек}

for k:=1 to 8 do

{просматриваем все ячейки, которые являются соседними для ячейки (i, j)}

if LifeSGd.Cells[i+DX[k],j+DY[k]]='1' then Inc(Count);

case Сount of

{анализируем полученное значение переменной Count

и в зависимости от него заполняем массив A}

0..1,4..8: A[i,j]:=0;

2: if LifeSGd.Cells[i,j]='1' then A[i,j]:=1 else A[i,j]:=0;

3: A[i,j]:=1;

end;

end;

for i:=0 to MX-1 do          {меняем значения ячеек компонента LifeSGd}

for j:=0 to MY-1 do

if A[i,j]=1 then LifeSGd.Cells[i,j]:='1'

{помечаем фишку как живую}

else if (LifeSGd.Cells[i,j]='1')

 then LifeSGd.Cells[i,j]:='2'

{помечаем фишку как мертвую в течение одного поколения}

else if (LifeSGd.Cells[i,j]='2')

 then LifeSGd.Cells[i,j]:='3'

{помечаем фишку как мертвую в течение двух поколений}

else LifeSGd.Cells[i,j]:='0';

{помечаем фишку как окончательно мертвую}

end;

Эксперимент. Мы завершили создание приложения. Сохраните проект.

Запустите приложение. Проследите за изменением популяции клеток.

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

Придумайте колебательные и устойчивые конфигурации популяции. t










Последнее изменение этой страницы: 2018-06-01; просмотров: 546.

stydopedya.ru не претендует на авторское право материалов, которые вылажены, но предоставляет бесплатный доступ к ним. В случае нарушения авторского права или персональных данных напишите сюда...