вторник, 3 мая 2011 г.

Урок 7. Как запомнить настройки (файл ini)

В предыдущем уроке для отладки работы таймера в качестве стартового значения я использовал величину 3 секунды. А еще раньше — приготовил несколько кнопок, которым что-то планировал назначать в момент старта программы. Вот и встает вопрос: где же хранить стартовые значения и настройки (надписи и т.п. для кнопок), сделанные оператором в ходе эксплуатации программы?


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


Обычный текстовый файл,
Текстовый файл ini,
Реестр windows,
и др...


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


Хранить какие-то записи в реестре Windows не так уж сложно и мудрено, как может показаться на первый взгляд, но! Для установки программы в компьютер и удаления ее, нужно будет написать специальную программу — инсталлятор, которая правильно обработает реестр. На данном этапе мы себе такой задачи не ставим.


А посему — воспользуемся золотой серединой — файлом ini.


Для того, чтобы программа могла работать с такими файлами, необходимо в разделе interface в uses в дополнение имеющегося списка дать ссылку на соответствующую библиотеку:


Uses iniFiles;

в разделе объявления глобальных переменных объявить переменную:
ini: TIniFile;


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


MyTimer.ini, в который вписать (можно скопировать из этого текста) следующее содержание:


[General]
StartMin=1
StartSec=30


[FixedBtns]
B1Capt=Яйцо всмятку
B1Min=2
B1Sec=25
B1Hnt=Яйцо всмятку
B2Capt=
B2Min=0
B2Sec=0
B2Hnt=Подсказка не указана
B3Capt=
B3Min=0
B3Sec=0
B3Hnt=Подсказка не указана
B4Capt=
B4Min=0
B4Sec=0
B4Hnt=Подсказка не указана
B5Capt=-
B5Min=0
B5Sec=0
B5Hnt=Подсказка не указана
B6Capt=-
B6Min=0
B6Sec=0
B6Hnt=Подсказка не указана


В первой секции [General] задаются стартовые значения минут и секунд. А в следующей секции [FixedBtns] для шести подготовленных нами «быстрых» кнопок заданы последовательно:


Подпись,
Минуты,
Секунды,
Текст всплывающей подсказки (Hint).


Не забудьте сохранить созданный файл.
В какой момент нужно обратиться к нему? Форма в процессе своего создания проходит стадии, точнее: в процессе создания формы возникают события создания (Create), показа (Show) и активации (Activate). В чем принципиальная разница каждого из этих моментов, Вы легко узнаете из учебников. Я же по секрету Вам скажу, что все, что я напишу в обработчике события создания формы будет работать и в двух других случаях.


А напишу я там вот этот фрагмент текста:


procedure TForm1.FormCreate(Sender: TObject);
begin


// Подготовить к работе файл ini, расположенный в текущем каталоге
ini:=TiniFile.Create(GetCurrentDir + '\MyTimer.ini');


// Установить стартовые значения цифровым полям
Minutes.Value:=Ini.ReadInteger('General','StartMin',1);
Secunds.Value:=Ini.ReadInteger('General','StartSec',30);


// Назначить интервал срабатывания главного таймера
Timer1.Interval:=CalcInterval();


// Установить статус элементов управления формы (1 — статус после старта программы, т.е. Таймер не запущен)
SetRecBtnStatus(1);
SetBtnStatus;


// Настроить фиксированные кнопки
FixedBtns.B1_Caption:=Ini.ReadString('FixedBtns','B1Capt','-');
FixedBtns.B1_Min:=Ini.ReadInteger('FixedBtns','B1Min',0);
FixedBtns.B1_Sec:=Ini.ReadInteger('FixedBtns','B1Sec',0);
FixedBtns.B1_Hint:=Ini.ReadString('FixedBtns','B1Hnt','Подсказка не указана');
FixedBtns.B2_Caption:=Ini.ReadString('FixedBtns','B2Capt','-');
FixedBtns.B2_Min:=Ini.ReadInteger('FixedBtns','B2Min',0);
FixedBtns.B2_Sec:=Ini.ReadInteger('FixedBtns','B2Sec',0);
FixedBtns.B2_Hint:=Ini.ReadString('FixedBtns','B2Hnt','Подсказка не указана');
FixedBtns.B3_Caption:=Ini.ReadString('FixedBtns','B3Capt','-');
FixedBtns.B3_Min:=Ini.ReadInteger('FixedBtns','B3Min',0);
FixedBtns.B3_Sec:=Ini.ReadInteger('FixedBtns','B3Sec',0);
FixedBtns.B3_Hint:=Ini.ReadString('FixedBtns','B3Hnt','Подсказка не указана');
FixedBtns.B4_Caption:=Ini.ReadString('FixedBtns','B4Capt','-');
FixedBtns.B4_Min:=Ini.ReadInteger('FixedBtns','B4Min',0);
FixedBtns.B4_Sec:=Ini.ReadInteger('FixedBtns','B4Sec',0);
FixedBtns.B4_Hint:=Ini.ReadString('FixedBtns','B4Hnt','Подсказка не указана');
FixedBtns.B5_Caption:=Ini.ReadString('FixedBtns','B5Capt','-');
FixedBtns.B5_Min:=Ini.ReadInteger('FixedBtns','B5Min',0);
FixedBtns.B5_Sec:=Ini.ReadInteger('FixedBtns','B5Sec',0);
FixedBtns.B5_Hint:=Ini.ReadString('FixedBtns','B5Hnt','Подсказка не указана');
FixedBtns.B6_Caption:=Ini.ReadString('FixedBtns','B6Capt','-');
FixedBtns.B6_Min:=Ini.ReadInteger('FixedBtns','B6Min',0);
FixedBtns.B6_Sec:=Ini.ReadInteger('FixedBtns','B6Sec',0);
FixedBtns.B6_Hint:=Ini.ReadString('FixedBtns','B6Hnt','Подсказка не указана');


// Освободить память
ini.Free;


// Настроить фиксированные кнопки
SetFixedBtns;


// Визуализация
SetMyLabel(); // Внести изменения :=CalcT();


end;



Для работы программы необходимо объявить еще ряд переменных и функций


Function TForm1.CalcT(): Integer;
begin


// Подсчитывает количество секунд, переводя минуты в секунды
Result:=(Minutes.Value*60+Secunds.Value);


end;


Function TForm1.CalcInterval(): Integer;
begin


// Подсчитывает интервал работы таймера в мс
Result:=(Minutes.Value*60+Secunds.Value)*1000;


end;



А чтобы все новые функции и процедуры работали, необходимо в самом начале модуля формы объявить пару новых типов — записей:


Type // Объявление типа
TBtnsStatus = record
BtStop: Boolean;
BtStart: Boolean;
N_File: Boolean;
N_Do: Boolean;
N_Service: Boolean;
N_Help: Boolean;
BtnMinPlus: Boolean;
BtnMinMinus: Boolean;
BtnSecPlus: Boolean;
BtnSecMinus: Boolean;
Btn1: Boolean;
Btn2: Boolean;
Btn3: Boolean;
Btn4: Boolean;
Btn5: Boolean;
Btn6: Boolean;
end;


Type // Объявление типа
TFixedBtns = record
B1_Caption: String;
B1_Min: Integer;
B1_Sec: Integer;
B1_Hint: String;
B2_Caption: String;
B2_Min: Integer;
B2_Sec: Integer;
B2_Hint: String;
B3_Caption: String;
B3_Min: Integer;
B3_Sec: Integer;
B3_Hint: String;
B4_Caption: String;
B4_Min: Integer;
B4_Sec: Integer;
B4_Hint: String;
B5_Caption: String;
B5_Min: Integer;
B5_Sec: Integer;
B5_Hint: String;
B6_Caption: String;
B6_Min: Integer;
B6_Sec: Integer;
B6_Hint: String;
end;,



не забыв объявить две новые переменные на основе этих типов:

BtnsStatus: TBtnsStatus;
FixedBtns: TfixedBtns;

В первой будет храниться статус элементов управления (кнопок, пунктов меню), во второй — настройки фиксированных кнопок.


Пара функций SetRecBtnStatus и SetBtnStatus всегда работают совместно:
первая — устанавливает необходимые значения переменной BtnsStatus, вторая — собственно устанавливает статусы элементов управления на основе значений этой переменной. Конструкция может на первый взгляд показаться громоздкой для такой незначительной программы, но хорошая привычка, выработанная на простом, будет только в плюс при разработке больших и сложных программ. Здесь я показываю один из приемов, а ваше дело — использовать его в дальнейшем или нет в своей практике.


Теперь, когда программа умеет отображать статус элементов управления и подсчитывать интервал работы таймера, нужно переписать процедуру запуска отсчета в следующем виде


procedure TForm1.Do_StartExecute(Sender: TObject);
var
i: integer;
begin


i:=CalcInterval();
If i=0 // Если пользователь ошибся с назначением времени отсчета,
then // то - выход
exit;


// Перевод элементов управления в режим отсчета
SetRecBtnStatus(2);
SetBtnStatus;


// Назначение интервала срабатывания основного таймера
Timer1.Interval:=i;


// Визуализация
SetMyLabel();


// Старт таймера
Timer2.Enabled:=True;
Timer1.Enabled:=True;


end;



Нужно внести изменения в процедуру остановки


procedure TForm1.Do_StopExecute(Sender: TObject);
begin


// Переводэлементов управления в исходное состояние
SetRecBtnStatus(1);
SetBtnStatus;


// Остановка таймера
Timer1.Enabled:=False;
Timer2.Enabled:=False;


// Визуализация
MyLabel4.Caption:='Таймер остановлен';


end;



Вернитесь к процедуре


procedure TForm1.Timer1Timer(Sender: TObject);
begin


// Остановить таймер
Timer1.Enabled:=False;
Timer2.Enabled:=False;


// Кнопки в положение проигрывание
SetRecBtnStatus(2);
SetBtnStatus;


// Вывод сообщения оператору
MyLabel4.Caption:='Отсчет завершен';


// Воспроизвести звук несколько раз или бесконечно


// Вернуть элементы управления в стартовое состояние
SetRecBtnStatus(1);
SetBtnStatus;


end;



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


Для работы быстрых кнопок, под событие нажатия каждой кнопки подложите вот такой код:

procedure TForm1.Button1Click(Sender: TObject);
begin
Minutes.Value:=FixedBtns.B1_Min;
Secunds.Value:=FixedBtns.B1_Sec;
SetMyLabel();
end;,


изменив, соответственно индекс (номер кнопки).


И последнее:
напишите обработчики нажатия кнопок увеличения и уменьшения количества минут и секунд по вот этому образцу:


procedure TForm1.Do_MinPlusExecute(Sender: TObject);
begin


// + минута
Minutes.Value:=Minutes.Value+1;
SetMyLabel();


end;



procedure TForm1.Do_SecMinusExecute(Sender: TObject);
begin


// - секунда
If Secunds.Value>0 // При уменьшении количества секунд,
then // ограничиться положительными значениями
begin
Secunds.Value:=Secunds.Value-1;
SetMyLabel();
end;


end;



В результате всех этих действий получится вполне работоспособный таймер. Но для использования в быту он еще мало пригоден, поскольку нем как рыба. Позже мы еще вернемся к работе с ini файлом, хранящим настройки, когда поведем разговор о сохранении текущих настроек в него. А в наглядном видео уроке, который Вы можете посмотреть или скачать, пройдя по ссылке, я покажу, что произойдет, если файл ini потерялся, и как избежать неприятных последствий.


Что же дальше?


Знакомство с медиа проигрывателем - научим таймер подавать голос!

Комментариев нет:

Отправить комментарий