Записи и вариант. Сетка строк TStringGrid
Цель лекции
Изучить типы данных record и variant, освоить работу с сеткой строк TStringGrid.
Запись - пользовательский тип данных
В Паскале предусмотрены не только стандартные типы, можно использовать и новые типы данных, определенные пользователем. Один из таких типов - запись.
По сути, запись является мини-объектом, который имеет свойства (поля), но не имеет методов и событий. Еще запись можно сравнить с массивом - в ней также хранятся различные данные, объединенные в одной переменной, только в отличие от массива, эти данные могут быть разнотипными.
Записи часто применяют для сохранения и загрузки различных данных, например, настроек программы. С помощью записей можно даже сделать небольшую базу данных, используя типовой файл, что мы и проделаем в следующей лабораторной работе.
Использование записей происходит в два этапа: вначале объявляется сама запись, затем объявляется переменная, которой присваивают тип этой записи. Кстати, тип записи можно присвоить не только переменной, но и массиву, и типизированному файлу.
Записи объявляются в разделе type перед разделом var, и могут иметь как локальную область видимости (запись объявлена внутри подпрограммы), так и глобальную. Синтаксис объявления следующий:
type <имя_записи> = record <поле1>: <тип_поля>; <поле2>: <тип_поля>; …; <полеN>: <тип_поля>; end;
Здесь, имя_записи - имя, которым пользователь называет новый созданный тип данных. Поле - имя поля записи, фактически, это переменная внутри другой переменной. Тип_поля - один из стандартных типов. Как уже говорилось, объявлять тип string в записи не запрещается, однако использовать такую запись в типизированном файле не получится. Обусловлено это тем, что при создании типизированного файла, компилятор должен точно знать, сколько байт на каждую запись он должен отвести в файле. Строка string является динамическим символьным массивом, то есть, заранее узнать её длину невозможно. Однако, можно решить и эту проблему, если поставить ограничитель на строку, например, string[50] - строка из 50 символов. В этом случае, типизированный файл можно создать. И если строка будет пустая, или в ней до 50 не будет хватать символов, то часть этой записи в файле просто окажется пустой, хотя место под нее будет выделено. Правда, использование кириллицы в кодировке UTF-8 создает некоторые трудности, но и они решаемы.
После того, как запись объявлена, нужно создать переменную, присвоив ей тип этой записи. Делается это обычным образом, в локальном или глобальном разделе var:
var NewPerem: <имя_записи>;
После чего, можно обращаться к отдельному полю этой записи, разделяя его от имени переменной точкой, например:
NewPerem.Pole1:= 10;
Давайте освоим работу с записями на примере программы, которая сохраняет свои настройки, такие как положение и размеры формы, состояние некоторых компонентов, в типизированном файле, а при последующей загрузке программа считывает эти настройки и подстраивается под них.
Откройте Lazarus с новым проектом. Сразу договоримся, что поскольку проект очень простой и пробный, то имена формы, модуля, проекта и компонентов мы оставим по умолчанию. Сразу же сохраните проект в папку 24-01. Теперь, на форме нам потребуются:
- Метка TLabel;
- Строка TEdit;
- Кнопка TButton;
- Флажок TCheckBox.
В Caption метки напишите "Заголовок формы:". Очистите Text у Edit1. В Caption кнопки напишите "Применить". А с флажком можно ничего не делать. В результате у вас должна получиться примерно такая форма:
Теперь самое главное - нам нужно описать запись, в которую затем сохраним параметры формы. Для этого нужно создать раздел type ПЕРЕД глобальным разделом var, тем самым, в котором описана переменная формы:
var Form1: TForm1;
И не смущайтесь, что выше раздел type уже был, таких разделов может быть много. Код нашей вставки следующий:
type myForm = record //запись Left: integer; //левая граница формы Top: integer; //верхняя Height: integer; //высота формы Width: integer; //ширина Caption: string[100]; //заголовок Checked: boolean; //состояние флажка CheckBox1 wsMax: boolean; //окно развернуто? end; //record
Как видите, внутри раздела type мы описали новый, пользовательский (наш) тип данных - запись. Теперь нам нужна переменная этого типа, с которой мы будем работать. Нашей программе нужно сохранять свои настройки при выходе, делать это лучше в событии OnClose формы. Но ей также нужно и считывать эти настройки при загрузке, делать это будем в событии OnCreate формы. Поскольку переменная нам будет нужна и там, и там, то значит, опишем её в глобальном разделе var, сразу ПОСЛЕ описания переменной Form1:
var Form1: TForm1; MyF: myForm; //наша переменная-запись
Теперь займемся кодированием. Прежде всего, нам нужно "научить" программу менять свой заголовок. Для этого сгенерируйте событие OnClick для кнопки "Применить", его код:
procedure TForm1.Button1Click(Sender: TObject); begin if Edit1.Text <> '' then Form1.Caption:= Edit1.Text; end;
Тут всё просто: мы проверяем - не пуста ли строка Edit1, и если не пуста, то присваиваем её текст свойству Caption формы, тем самым, меняя заголовок окна. Пойдем далее. А далее нам нужно научить программу сохранять свои настройки. Для этого выделите форму, щелкнув по её любому свободному месту. Теперь перейдите на вкладку События Инспектора объектов, и двойным щелчком сгенерируйте событие формы OnClose, его код:
procedure TForm1.FormClose(Sender: TObject; var CloseAction: TCloseAction); var f: file of myForm; //типизированный файл для сохранения данных begin //сначала настроим переменную-запись: //не сохраняем размеры и положение, если окно wsMaximized: if not (Form1.WindowState = wsMaximized) then begin MyF.Left:= Form1.Left; MyF.Top:= Form1.Top; MyF.Height:= Form1.Height; MyF.Width:= Form1.Width; MyF.wsMax:= False; end else MyF.wsMax:= True; //остальные настройки: MyF.Caption:= Form1.Caption; MyF.Checked:= CheckBox1.Checked; //теперь создаем или перезаписываем файл настроек: try AssignFile(f, 'MyProg.dat'); Rewrite(f); Write(f, MyF); //записываем в файл данные из записи finally CloseFile(f); end; end;
Давайте разберем этот код. В разделе var мы описали переменную f, которая будет ассоциироваться с типизированным файлом, имеющим тип нашей записи. Видите, мы присвоили наш тип и переменной, и типизированному файлу!
Далее нам требуется сохранить в переменную-запись настройки нашей формы, но тут есть одно НО: если окно программы было развернуто, то такие данные, как левая и верхняя граница окна, его высота и ширина становятся недействительными. Поэтому мы пошли на хитрость: если окно не было развернуто, то мы сохраняем эти параметры и, кроме того, полю wsMax присваиваем False, тем самым указывая, что окно не было развернуто. Если же окно было развернуто, то мы присваиваем этому полю True, не трогая границы окна:
if not (Form1.WindowState = wsMaximized) then begin MyF.Left:= Form1.Left; MyF.Top:= Form1.Top; MyF.Height:= Form1.Height; MyF.Width:= Form1.Width; MyF.wsMax:= False; end else MyF.wsMax:= True;
Как видно из кода, мы обращаемся к отдельным полям записи через точку:
MyF.Left
Остальные параметры (заголовок окна и состояние флажка) нам нужно сохранять в любом случае:
MyF.Caption:= Form1.Caption; MyF.Checked:= CheckBox1.Checked;
Далее мы работаем с файлом, создавая или перезаписывая его. В файл мы записываем одну-единственную запись - нашу переменную MyF, в которой уже хранятся все нужные настройки, после чего файл закрываем. Забегая вперед, скажу, что если вы попытаетесь открыть такой файл редактором текстов, то увидите в нем двоичный код:
Неискушенный пользователь не рискнет пытаться править такой файл, а если вы случайно чего-то в нем измените, и программа перестанет загружаться, то просто удалите файл - без него программа загрузится с настройками по умолчанию, а при следующем закрытии файл MyProg.dat будет создан снова.
Теперь нужно научить программу считывать настройки из файла, и применять их. Сгенерируйте событие формы OnCreate, его код:
procedure TForm1.FormCreate(Sender: TObject); var f: file of myForm; //типизированный файл для сохранения данных begin //если файла еще нет, просто выходим: if not FileExists('MyProg.dat') then exit; //иначе открываем файл и считываем из него настройки в запись: try AssignFile(f, 'MyProg.dat'); Reset(f); Read(f, MyF); //считали данные в переменную типа запись finally CloseFile(f); end; //теперь настройки нужно применить к форме: //если окно было развернуто, разворачиваем его, иначе настраиваем края: if MyF.wsMax then Form1.WindowState:= wsMaximized else begin Form1.Left:= MyF.Left; Form1.Top:= MyF.Top; Form1.Height:= MyF.Height; Form1.Width:= MyF.Width; end; //остальные настройки: Form1.Caption:= MyF.Caption; CheckBox1.Checked:= MyF.Checked; end;
Вначале мы проверяем - есть ли файл. Если нет (программа открывается впервые), то мы выходим, ничего не считывая и не меняя настроек. В этом случае, все настройки будут, как при разработке формы.
Комментировать работу с файлом я не буду - всё должно быть предельно ясно по прошлой лекции и по предыдущему коду сохранения файла. В нашу переменную-запись MyF считались настройки, сохраненные в файле, и нам осталось только применить их к форме. Делается это как при сохранении, но в обратном направлении - не в запись из формы, а в форму из записи. Также, если окно было развернуто, разворачиваем его, иначе применяем настройки положения и размеров формы.
Теперь сохраните проект, запустите его на исполнение и попробуйте менять положение и размеры окна, разворачивать его - все эти настройки при выходе должны сохраняться, а при следующем запуске - восстанавливаться.