рефераты конспекты курсовые дипломные лекции шпоры

Реферат Курсовая Конспект

Запись и чтение из файла не текстовых данных

Запись и чтение из файла не текстовых данных - раздел Компьютеры, Далее немного вашего внимания уделю процессу установки Delphi на компьютер Рассмотрим Пример, В Котором Программа При Выходе Сохраняет Свои Размеры И По...

Рассмотрим пример, в котором программа при выходе сохраняет свои размеры и положение окна на экране в файл и при последующем запуске восстанавливает состояние, которое было при выходе. Программа состоит из двух процедур OnShow и OnClose для окна Form1 программы.

procedure TForm1.FormShow(Sender: TObject);

Var f:fileof Integer; // файловая переменная, тип integer

i:Integer; // целочистенная переменная

begin

AssignFile(f,'pos.ini');

{$I-}

Reset(f);

{$I+}

if IOResult<>0 then Exit;

 

Read(f,i); //считать из файла значение

Form1.Top:=i; // верхнее положение окна

 

Read(f,i);

Form1.Left:=i; // левое положение окна

 

Read(f,i);

Form1.Width:=i; // ширина окна

 

Read(f,i);

Form1.Height:=i; // высота окна

 

CloseFile(f);

end;

 

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);

Var f:fileof Integer;

begin

AssignFile(f,'pos.ini');

{$I-}

Rewrite(f);

{$I+}

if IOResult<>0 then Exit;

 

Write(f,Form1.Top);

Write(f,Form1.Left);

Write(f,Form1.Width);

Write(f,Form1.Height);

 

CloseFile(f);

end;

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

С уважением, ведущий уроков Semen semen@krovatka.net

 

Урок16. Ini файлы

Для хранения некоторых данных, например параметров программы, как это было рассмотрено в предыдущем уроке, для последующего их использования можно применять реестр или ini файлы. Я имею в виду хранение установок программы во время бездействия программы, чтобы при последующем запуске, она восстанавливала свое состояние. В ini файлах можно также хранить и скрытые от пользователя данные, такие как серийный номер программы, срок истечения лицензии, закодированные пароли на запуск и пр. Такие данные естественно не защищены от постороннего вмешательства, но при умелом использовании кодирующих средств, можно исключить ручное редактирование этих параметров.

TIniFile является низкоуровневым 16-битным классом, совместимым с операционной системой windows 3.x файловой системы хранения параметров в INI файлах. Для хранения параметров в современных программах рекомендуется использовать реестр. Но, как правило, не так просто такую программу скопировать на другой компьютер с переносом всех настроек, а совместное копирование ini файла избавит вас от такой проблемы.
Класс TIniFile находится в модуле IniFiles, который надо указывать в разделе подключаемых модулей Uses.

Объявление переменной, в которую будем заносить (или читать) данные:

Var IniFile : TIniFile;

где: IniFile - любой идентификатор, который будет использоваться в программе. Можно, например, для сокращения просто i.
Дальше переменную необходимо создать:

IniFile := TIniFile.Create('Название_файла');

где: Название_файла - файл, в котором будут храниться данные. Если вы напишите, например project.ini без указания пути к файлу, то такой файл создастся или будет читаться из каталога WINDOWS. Для размещения ini файла в каталоге программы, или относительно его (например КАТАЛОГ_ПРОГРАММЫINI) указывайте вместе с названием файла текущий каталог программы.
В конце использования переменной ее необходимо уничтожить и освободить занимаемую память. Это делается одной командой:

IniFile.Free;

В промежутке между созданием и уничтожением переменной IniFile находятся команды чтения (записи) параметров.
Если мы заглянем в любой файл настроек, например win.ini, то можно увидеть следующую архитектуру файла:

[windows]
NullPort=None
ILOVEBUNNY32=1
ScreenSaveActive=1

[Desktop]
Wallpaper=(None)
TileWallpaper=0
WallpaperStyle=0

[Intl]
iCountry=380

Строка, заключенная в квадратные скобки [] называется заголовком секции, и все данные между двумя заголовками являются секцией. В одной секции может быть только один уникальный параметр, т.е. название параметров в секции не должны повторяться дважды. После названия параметра следует знак равенства, после которого сама хранимая величина.

Чтение параметров:

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

ПЕРЕМЕННАЯ_Integer:=IniFile.ReadInteger(СЕКЦИЯ,ПАРАМЕТР,ЗНАЧЕНИЕ_ПО_УМОЛЧАНИЮ);

где: СЕКЦИЯ и ПАРАМЕТР - строковые значения. На из месте можно писать как саму строковую величину, например 'MAINPARAM', так и подставлять строковую переменную.
Если не обнаружится данного ini файла, или не обнаружится указанной секции, или в секции не будет заданного параметра, то функция возвращает значение_по_умолчанию. Это свойство очень удобно для задания в программе начальных значений.
Далее список функций, которые можно применять при чтении данных из ini файла. Их структура аналогична вышерассмотренной команде за исключением двух: возвращает параметр определенного типа, значение по умолчанию имеет тот же тип.

ReadString - чтение строковой переменной
ReadBool - чтение логической переменной
ReadDate - чтение даты
ReadTime - чтение времени
ReadDateTime - чтение даты и времени в одном параметре
ReadFloat - чтение числа с плавающей точкой

Запись параметров:

Все команды записи параметров являются процедурами. Они не возвращают никаких параметров, и, в случае неудачной попытки записи, программа выдает сообщение об ошибке.
Для записи параметра Integer:

IniFile.WriteInteger(СЕКЦИЯ,ПАРАМЕТР,ЗАПИСЫВАЕМАЯ_ВЕЛИЧИНА);

Далее для записи других типов данных:

WriteString - запись строковой переменной
WriteBool - запись логической переменной
WriteDate - запись даты
WriteTime - запись времени
WriteDateTime - запись даты и времени в одном параметре
WriteFloat - запись числа с плавающей точкой

Рассмотрим пример.

Создаем новый проект, в форму Form1 помещаем компоненты Edit, ComboBox, два компонента CheckBox, две кнопки BitBtn.

Для компонента ComboBox1 изменяем свойство Style в csDropDownList и редактируем свойство Items, занося туда несколько произвольных строк. Дальше для BitBtn1 свойство Caption изменяем на Сохранить, а для кнопки BitBtn2 - Восстановить. Окно принимает вид, показанный на рисунке.

В процедуре события FormCreate для окна Form1 пишем команду

ReadParams;

В процедуре события FormClose для окна Form1 пишем команду

WriteParams;

В процедуре нажатия на кнопку "Сохранить" аналогично закрытию окна команда WriteParams, для кнопки "Восстановить" - ReadParams.

Дальше привожу текст модуля Unit1 обратите внимание на выделенные строки. Их следует прописать вручную.

// ----------------Начало модуля Unit1------------------

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Buttons, inifiles; // подключение модуля, позволяющего работать с ini файлами

type
TForm1 = class(TForm)
Edit1: TEdit;
ComboBox1: TComboBox;
CheckBox1: TCheckBox;
CheckBox2: TCheckBox;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
procedure ReadParams; // процедура чтения параметров
procedure WriteParams; // процедура записи параметров
procedure FormCreate(Sender: TObject);
procedure FormClose(Sender: TObject; var Action: TCloseAction);
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

procedure TForm1.ReadParams;
Var IniFile:TIniFile; // объявление переменной, через которую будут обрабатываться данные
begin
IniFile:=TIniFile.Create('project.ini'); // создаем переменную
Form1.Top:=IniFile.ReadInteger('FORM1','Form1Top',Form1.Top); // верхнее положение окна
Form1.Left:=IniFile.ReadInteger('FORM1','Form1Left',Form1.Left); // левое положение окна
Form1.Height:=IniFile.ReadInteger('FORM1','Form1Height',Form1.Height); // высота
Form1.Width:=IniFile.ReadInteger('FORM1','Form1Width',Form1.Width); // ширина
Edit1.Text:=IniFile.ReadString('FORM1','Edit1Text',Edit1.Text); // текст в Edit1
ComboBox1.ItemIndex:=IniFile.ReadInteger('FORM1','ComboBox1ItemIndex',ComboBox1.ItemIndex); // выбранный пункт
CheckBox1.Checked:=IniFile.ReadBool('FORM1','CheckBox1Checked',CheckBox1.Checked); // состояние CheckBox1
CheckBox2.Checked:=IniFile.ReadBool('FORM1','CheckBox2Checked',CheckBox2.Checked); // состояние CheckBox2
IniFile.Free; // если сами создаем, то сами уничтожаем.
end;

procedure TForm1.WriteParams;
Var IniFile:TIniFile;
begin
IniFile:=TIniFile.Create('project.ini');
IniFile.WriteInteger('FORM1','Form1Top',Form1.Top);
IniFile.WriteInteger('FORM1','Form1Left',Form1.Left);
IniFile.WriteInteger('FORM1','Form1Height',Form1.Height);
IniFile.WriteInteger('FORM1','Form1Width',Form1.Width);
IniFile.WriteString('FORM1','Edit1Text',Edit1.Text);
IniFile.WriteInteger('FORM1','ComboBox1ItemIndex',ComboBox1.ItemIndex);
IniFile.WriteBool('FORM1','CheckBox1Checked',CheckBox1.Checked);
IniFile.WriteBool('FORM1','CheckBox2Checked',CheckBox2.Checked);
IniFile.Free;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ReadParams;
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
WriteParams;
end;

procedure TForm1.BitBtn1Click(Sender: TObject);
begin
WriteParams;
end;

procedure TForm1.BitBtn2Click(Sender: TObject);
begin
ReadParams;
end;

end.

// ----------------Конец модуля Unit1------------------

Вышерассмотренный пример можно забрать по этой ссылке (2 Кб).

Запустите программу несколько раз и проследите за восстановлением внешнего вида программы. Попробуйте сохранять и восстанавливать параметры с помощью кнопок.

Для нашего примера создается файл project.ini, который находится в каталоге WINDOWS. Просмотрите его содержимое. У меня он получился такой.

[FORM1]
Form1Top=256
Form1Left=147
Form1Height=301
Form1Width=368
Edit1Text=111
ComboBox1ItemIndex=2
CheckBox1Checked=1
CheckBox2Checked=0

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

[FORM1]
Form1Top=100
Form1Left=100
Form1Height=300
Form1Width=500

[FORM2]
Form1Top=200
Form1Left=200
Form1Height=100
Form1Width=200

Итак, файл project.ini пишется и читается в каталоге WINDOWS. Следующий пример позволяет построить путь к файлу ini относительно каталога, где находится ваша запущенная программа. Этот кусок программы помещается до создания IniFile, и еще необходимо объявить строковую переменную Path.

Var Path:String; // Переменная, где будет храниться путь к программе
...
Path:=Application.ExeName; // полный путь и название запущенной программы
Path:=ExtractFileDir(Path); // отбрасываем название программы. Остается путь.
if Path[Length(Path)]<>'' then Path:=Path+''; // если последний символ не то добавить его
{Последняя строка нужна для присвоения последнего символа '',
потому что при обрезке файла 'C:PROG.EXE' получим 'C:',
а при обрезке 'C:WINDOWSPROG.EXE' получим 'C:WINDOWS' }
IniFile:=TIniFile.Create(Path+'project.ini'); // полный путь к программе и имя ini файла

Теперь ini файл лежит недалеко от запускаемой программы.

С уважением, ведущий уроков Semen semen@krovatka.net

 

Урок17. Сохранение данных в реестр windows. Некоторые команды для работы со строками.

Сохранение данных в реестр.

На прошлом уроке мы с вами рассмотрели методику записи и чтения пользовательских данных и данных состояния компонентов в ini файл. Эта методика хранения параметров программы является устаревшей. Рекомендуется для этих целей использовать реестр.

Для начала краткая информация о реестре. Проще говоря, реестр windows, эта огромная база данных, хранящая в себе всевозможные пользовательские и системные данные. Установленное оборудование, драйвера, установленные шрифты, установленные принтеры и многое другое записано в соответствующих разделах.
Как же все-таки увидеть данные реестра? Очень просто. Надо нажать на кнопку "Пуск", выбрать пункт "Выполнить" и ввести название программы REGEDIT, которая отображает реестр для чтения и редактирования. Эта программа находится в каталоге windows. Помните, что некорректное изменение некоторых системных ключей в реестре может привести к постоянным сбоям в системе, может привести даже к полному краху операционной системы, поэтому изменения и удаление следует производить очень осторожно.
Внешний вид этой программы состоит из двух панелей. Левая древовидная и правая, в которой отображаются параметры ключей. Ключ - это элемент реестра, который может содержать некоторые данные или содержать другие ключи. Это древовидная структура, которая хранит в себе вложенные параметры, объединенные общей тематикой. Не буду рассказывать назначение отдельных ключей, это может занять не одну книгу, скажу только, что программы, которые работают с реестром в качестве ini файла, автоматически записывают и читают данные из глобального ключа HKEY_CURRENT_USER. Он же дублируется в ключе HKEY_USERSИМЯ_ТЕКУЩЕГО_ПОЛЬЗОВАТЕЛЯ.
Дальше рассмотрим запись и чтение данных. Тут методика аналогична работе с ini файлами.
Для начала в разделе подключаемых модулей Uses нужно указать модуль Registry, который необходим для использования команд работы с реестром.
Объявление реестровой переменной

Var ПЕРЕМЕННАЯ:TRegIniFile;

Создание реестровой переменной, через которую будем читать и писать данные

ПЕРЕМЕННАЯ:=TRegIniFile.Create(НАЗВАНИЕ_КЛЮЧА);

Пример объявления, создания и удаления.

procedure TForm1.FormShow(Sender: TObject);
Var RegIniFile:TRegIniFile; // реестровая переменная
begin
RegIniFile:=TRegIniFile.Create('MySelfRegistryApplication'); // создание реестровой переменной
RegIniFile.Free; // уничтожение вручную созданного объекта
end;

Подробно о командах чтения и записи.

Чтение и запись целочисленного значения, типа integer:

RegIniFile.ReadInteger(СЕКЦИЯ,ПАРАМЕТР,ЗНАЧЕНИЕ_ПО_УМОЛЧАНИЮ);
RegIniFile.WriteInteger(СЕКЦИЯ,ПАРАМЕТР,ЗНАЧЕНИЕ);

Дальше аналогично вышерассмотренной команде следует чтение и запись:
двоичного значения ReadBool и WriteBool;
строкового значения ReadString и WriteString;

Если необходимо сохранить данные не в отдельной секции, а в ключе, то вместо параметра СЕКЦИЯ необходимо указать пустую строку, или две кавычки ''.

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

RegIniFile.ValueExists(ПАРАМЕТР)

Эта команда является функцией, возвращающей истинно (true) или ложно (false), и ее можно использовать в паре с чтением определенного параметра. Например, чтение числа с плавающей точкой:

if RegIniFile.ValueExists('MyFloat') then // если данный параметр существует, то
Edit2.Text:=FloatToStr(RegIniFile.ReadFloat('MyFloat')); // прочитать параметр

Пример.
В новом проекте помещаем в форму следующие компоненты:
· 2 компонента CheckBox
· компонент ComboBox, установите в свойстве Items некоторые строки.
· 2 компонента Edit
· компонент DateTimePicker (страница Win32 палитры компонентов)

Процедура OnShow для окна Form1

procedure TForm1.FormShow(Sender: TObject);
Var RegIniFile:TRegIniFile; // реестровый объект
begin
RegIniFile:=TRegIniFile.Create('MySelfRegistryApplication'); // создание реестровой переменной
Form1.Left:=RegIniFile.ReadInteger('Form1','Form1Left',Form1.Left); // левая граница окна
Form1.Top:=RegIniFile.ReadInteger('Form1','Form1Top',Form1.Top); // верхняя граница окна
Form1.Height:=RegIniFile.ReadInteger('Form1','Form1Height',Form1.Height); // высота окна
Form1.Width:=RegIniFile.ReadInteger('Form1','Form1Width',Form1.Width); // ширина окна
// Восстановление состояния компонентов
CheckBox1.Checked:=RegIniFile.ReadBool('Form1','CheckBox1Checked',CheckBox1.Checked);
CheckBox2.Checked:=RegIniFile.ReadBool('Form1','CheckBox2Checked',CheckBox2.Checked);
ComboBox1.ItemIndex:=RegIniFile.ReadInteger('Form1','ComboBox1ItemIndex',ComboBox1.ItemIndex);
Edit1.Text:=RegIniFile.ReadString('Form1','Edit1Text',Edit1.Text);
if RegIniFile.ValueExists('MyFloat') then // если такой параметр существует, то:
Edit2.Text:=FloatToStr(RegIniFile.ReadFloat('MyFloat')); // чтение числа с запятой
if RegIniFile.ValueExists('MyDate') then // если такой параметр существует, то:
DateTimePicker1.Date:=RegIniFile.ReadDate('MyDate'); // чтение даты

RegIniFile.Free; // уничтожение вручную созданного объекта
end;

Процедура OnClose для окна Form1

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
Var RegIniFile:TRegIniFile;
begin
RegIniFile:=TRegIniFile.Create('MySelfRegistryApplication');
RegIniFile.WriteInteger('Form1','Form1Left',Form1.Left);
RegIniFile.WriteInteger('Form1','Form1Top',Form1.Top);
RegIniFile.WriteInteger('Form1','Form1Height',Form1.Height);
RegIniFile.WriteInteger('Form1','Form1Width',Form1.Width);
// Сохранение состояния компонентов
RegIniFile.WriteBool('Form1','CheckBox1Checked',CheckBox1.Checked);
RegIniFile.WriteBool('Form1','CheckBox2Checked',CheckBox2.Checked);
RegIniFile.WriteInteger('Form1','ComboBox1ItemIndex',ComboBox1.ItemIndex);
RegIniFile.WriteString('Form1','Edit1Text',Edit1.Text);

RegIniFile.WriteFloat('MyFloat',StrToFloat(Edit2.Text));
RegIniFile.WriteDate('MyDate',DateTimePicker1.Date);

RegIniFile.Free;
end;

 

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

После запуска и закрытия этой программы можно запустить редактор реестра и просмотреть результат записи данных. Они находятся в ключе HKEY_CURRENT_USER, подключе MySelfRegistryApplication, как было указано в программе. Данные состояния окна, компонентов CheckBox1, CheckBox2 и Edit1 находятся в секции Form1, остальные данные: число в компоненте Edit2, дата в компоненте DateTimePicker1 находятся непосредственно в ключе MySelfRegistryApplication.
Посмотреть на параметры, записанные вышерассмотренной программой автоматически при закрытии, можно на двух рисунках. В первом рисунке вы видите данные даты и дробного числа, во втором рисунке вы видите содержание секции Form1. Эта секция является одновременно подключом ключа MySelfRegistryApplication.
Удаление того или иного параметра приведет к сбросу сохраняемой величины и при запуске программы будет установлено начальное значение по умолчанию. Удаление всего ключа MySelfRegistryApplication приведет к сбросу всех данных нашей программы. Удалить параметр или ключ в редакторе реестра можно кнопкой Del или выбрав соответствующий пункт из выпадающего меню по правой кнопке мышки.
Программное удаление параметра осуществляется командой
RegIniFile.DeleteKey(СЕКЦИЯ, ПАРАМЕТР);

Этот пример можно забрать по ссылке тут.

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


Некоторые команды для работы со строками

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

РЕЗУЛЬТАТ:=Copy(ИСХОДНАЯ_СТРОКА, ПЕРВЫЙ_СИМВОЛ, ДЛИНА_ЧАСТИ_СТРОКИ);

Удаления части в строке производится процедурой Delete:

Delete(СТРОКА,ПЕРВЫЙ_СИМВОЛ, ДЛИНА);

Для вставки части строки в другую применяем процедуру Insert

Insert(ВСТАВЛЯЕМАЯ_СТРОКА, РЕЗУЛЬТИРУЮЩАЯ_СТРОКА, НОМЕР_СИМВОЛА_ВСТАВКИ);

В любой момент можно узнать длину строки с помощью функции Length(СТРОКА), а установить длину строки можно процедурой SetLength(СТРОКА, НОВАЯ_ДЛИНА).

В pascal'е строковая переменная объявляется как тип String. Если объявляем такую переменную, значит мы будем ее использовать для работы со строками. Но в отличие от языка программирования pascal, в таких строках запрещен доступ к нулевому символу (в этом символе хранилось длина строки). Поскольку в операционной системе windows все строки имеют стандарт PChar (строки, заканчивающиеся символом #0), то тип String здесь оставлен для совместимости. Фактически длина строки String не ограничена 255 символами, как в pascal. Но применяя этот тип, вы незаметно для себя, применяете тип PChar. Все операции перевода одного типа в другой delphi производит автоматически.
Вот пример процедуры обработки строк.

procedure StringOper;
Var st1,st2,st3,st4:String; // объявление строковых переменных
i:integer; // целочисленная переменная
begin
st1:='это 1 строка';
st2:='это 2 строка';
st3:=st1+' '+st2; // результат 'это 1 строка это 2 строка'
st4:=Copy(st3,1,5); // копирование части строки. Результат 'это 1'
Delete(st4,1,4); // удаление части строки. Результат '1'
Insert(' строка',st4,2); // вставка части строки в строку st4. Результат '1 строка'
st4[1]:='2'; // изменение первого символа строки с 1 на 2
i:=Length(st4); // определение длины строки i=8
SetLength(st4,7); // установка новой длины строки. Результат '1 строк'
end;

С уважением, ведущий уроков Semen semen@krovatka.net

 

Урок18. Корректное построение программного кода. Рисование. Построение графика функции

Бесконечные циклы, громоздкие операции и прочие зависшие программы.

Ну кто из вас хоть раз не завершал зависшее приложение через Ctrl+Alt+Del? А ведь в большинстве случаев в ситуации, когда программа зависает, виноват программист, а не пользователь, который ее довел до этого состояния. Зачастую программы имеют в себе до 30% различной проверочных команд. Когда проверяются переполнение списков, проверяется корректность созданного объекта, компонента, проверяется или запущено то или иное внешнее приложение. Именно от этих условий и зависит дальнейшее корректное выполнение вашего приложения.

Рассмотрим принцип работы следующей программы.
Допустим, в оконном модуле есть две процедуры. Первая процедура - реакция на событие нажатия на кнопку Button1, вторая процедура - реакция на событие нажатия на кнопку Button2. Исходный текст процедур:

procedure TForm1.Button1Click(Sender: TObject);
begin
while true do
begin
// бесконечный цикл
end;
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
ShowMessage('Нажата кнопка Button1');
end;

В первой процедуре мы видим типичный программный код, при выполнении которого программа зависнет. Или говоря языком юзера - бесконечно выполняет одно и то же. Естественно, что выхода из такой процедуры не существует, а сама программа ожидает выхода из нее, чтобы выполнять другие события, в том числе и системные.
Принцип работы операционной системы windows основан на посылке сообщений компонентам программы. События при этом становятся в очередь и ожидают своей обработки. Поскольку выхода из первой процедуры нами не предусмотрено, то очередь сообщений не будет обрабатываться, и при нажатии на кнопки Ctrl+Alt+Del через некоторое время, мы видим, что приложение "не отвечает на системные запросы".
В подобных случаях это совсем не означает, что программа не работает. Она может зациклиться на обработки одной или нескольких команд, ожидая выхода из цикла по определенному условию (например, прочтения данных с диска) или обрабатывать большой объем данных опять таки в одной процедуре. А, как известно, корректная работа программы забота программиста, то есть нас с вами. Мы должны учесть все возможные ситуации, просчитать приблизительное время обработки операций даже на слабых компьютерах, при необходимости применить компонент ProgressBar, для того, чтобы пользователь не скучал, глядя на "неотвечающую" программу.

В вышерассмотренном примере, если нажать на кнопку Button1, а потом Button2, то реакция на событие нажатия на вторую кнопку будет помещена в очередь сообщений, но само событие не будет выполнено никогда. Кроме того, приложение перестанет получать все системные сообщения, т.е. окно нельзя будет переместить, свернуть, закрыть. Окно автоматически перестанет перерисовываться (имею в виду старые операционные системы windows).

Есть выход. В автоматически создаваемом компоненте при запуске программы Application, есть такая команда ProcessMessages, которая приостанавливает выполнение текущей процедуры, пока не будет выполнена очередь всех сообщений, посланных в программу. Если вставить строку

Application.ProcessMessages;

внутри продолжительных операций, то гарантировано получим не полностью зависшее приложение, а при умелом написании программного кода, из подобного цикла можно выйти по желанию пользователя (кнопка "Стоп"). И без создания дополнительного потока (считаю, что создание второго потока в программе занятие трудное и в больших проектах с этим можно запутаться). Такой пример "вечного" цикла мы рассматриваем в этом уроке.

Исключительные ситуации.

Это другой неприятный момент для пользователя и программиста. Это когда появляются неожиданные англоязычные ошибки и выполняемая процедура завершает свою работу с места появления ошибки. Разработчики Borland Delphi таким контролем за ошибками и выходом из работающих модулей программы позаботились об остальных частях программы. Если ошибка появилась в первой строке, то имеет ли смысл выполнять вторую?

Рассмотрим такой пример:

procedure TForm1.Button1Click(Sender: TObject);
Var x,y,z:Double; // переменные.
begin
x:=0;
z:=1;
y:=z/x; // деление на нуль
ShowMessage(FloatToStr(y));
end;

При выполнении данного кода мы получаем сообщение "Floating point division by zero". И процедура дальше уже не обрабатывается. После команды деления мы не видим его результат ShowMessage(РЕЗУЛЬТАТ) Или еще такой пример:

procedure TForm1.Button1Click(Sender: TObject);
begin
Form1.ShowModal; // открыть окно модально
ShowMessage('Окно открыто модально');
end;

Если у нас окно Form1 уже открыто, то повторная попытка открыть его модально приведет к возникновению ошибки "Cannot make a visible window modal". И опять программа завершает обработку процедуры. Это приведены примитивные процедуры, но бывает такие, что даже сам программист не ожидает появления подобной ситуации, но нужно предусмотреть все.
Что же делать, если мы открыли несколько файлов, заполняем список, создали вручную некоторые объекты. Выход из процедуры приводит к тому, что файлы не закрыты и повторный вызов этой процедуры приведут к возникновению другой ошибки - открытие уже открытого файла. Созданные объекты мы теряем при выходе из процедуры, а при повторном их создании, если они глобальные, получаем еще одну ошибку. А эта трата драгоценной памяти, которая занимается объектом и остается даже после выхода их программы. И так далее со всеми вытекающими последствиями.

Во-первых, надо при всех операциях деления предусматривать что-то подобное

if x<>0 then y:=z/x; // если x не равно нулю, то делить.

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

Var st:String;
y:Double;
...
InputQuery('Ввод числа','введите любое число',st);
y:=StrToFloat(st);

Если не проконтролировать корректность ввода числа в строковую переменную st, то при попытке преобразования его в переменную типа Double, произойдет ошибка.

При сомнениях, насчет отображения того или иного окна на экране использовать, например:

if not Form1.Visible then Form1.ShowModal; // если окна нет на экране, то открыть его модально

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

В уроке15 мы рассматривали пример, в котором есть директива компилятору об отключении контроля ошибок ввода-вывода. Мы открывали файл, при отключенном автоматическом контроле, после чего сами обрабатывали ошибку открытия.

{$I-} // отключение контроля ошибок ввода-вывода
Reset(f); // открытие файла для чтения
{$I+} // включение контроля ошибок ввода-вывода
if IOResult<>0 then // если есть ошибка открытия, то
begin
ShowMessage('Ошибка открытия файла C:1.TXT');
Exit; // выход из процедуры при ошибке открытия файла
end;

Такой метод можно применять только с старыми форматами команд, совместимыми с языком программирования pascal и работающими только с устройствами ввода-вывода.
В delphi можно применять следующее:

try // начало опасно-ошибочной части процедуры:
Form1.ShowModal;
except // если возникла ошибка, то выполняется следующее:
ShowMessage('Ошибка открытия окна');
end; // конец try
ShowMessage('Дальнейшая обработка процедуры');

Заметьте, что этот кусок кода не вызовет ошибки выполнения. Программа просто вам сообщит об ошибке открытия окна, после чего процедура продолжит свое выполнение. Еще обратите внимание, что если в части, после except возникнет другая ошибка выполнения, то процедура таки точно завершит свою работу немедленно. Все команды, которые могут вызвать ошибку надо писать после try и до except.
Теперь можно без опаски потери данных, после except корректно закрыть все открытые файлы, при необходимости окна, сообщить пользователю о возникшей ошибке и самому выйти из процедуры с помощью Exit.

Аналогом try-except есть try-finally

procedure TForm1.Button1Click(Sender: TObject);
Var StringList:TStringList; // список строк
begin
try
StringList:=TStringList.Create; // создание списка строк
finally // при успешной обработки создания списка:
StringList.Free; // удалить и освободить память
end;
ShowMessage('Дальнейшая обработка процедуры');
end;

После finally следует строки программы, которые следует выполнять в случае успешной обработки команд, следующие после try.

Рисование на форме или на компоненте PaintBox. Генератор колебаний. Пример

Большое спасибо Александру, за идею примера, который мы рассмотрим в этом уроке. Извиняюсь за то, что перевел тему с генератора на построитель функции синуса и косинуса.
У формы и у компонента PaintBox (страница System палитры компонентов) есть свойство Canvas. Это свойство представляет собой растровое изображение, на котором можно рисовать или в которое можно загрузить рисунок. Я не буду рассказывать подробно об особенностях рисования, тем более, что я в этом не силен, но основные сведения дам.
Свойство Canvas доступно только во время работы приложения и с помощью его можно:
* Canvas.Brush - свойство фона. У него можно установить свойство Canvas.Brush.Color в необходимый цвет и с помощью следующей за ней командой Canvas.FillRect(ClientRect) можно очистить всю рабочую область компонента под заданный цвет. С помощью свойтва Canvas.Brush можно в качестве фона установить рисунок. Для этого есть свойство Canvas.Brush.Bitmap, которому нужно присваивать переменную с растровым рисунком.
* Canvas.MoveTo(x,y) - устанавливает перо в заданную точку, где x и y - координаты точки, относительно компонента. Начало координат, точка [0,0] находится в верхнем левом углу. После этой команды перо установлено, но точка не нарисована. Чтобы провести линию от текущего положения пера до заданного Canvas.LineTo(x,y). Поставить точку определенного цвета на холсте Canvas.Pixels[x,y]:=ЦВЕТ_ТОЧКИ.
* Через Canvas можно писать текст, рисовать дуги, сектор круга, овал, прямоугольник, ломаную линию, кривую.
* Свойства пера содержатся в Canvas.Pen. Здесь можно задать толщину пера Canvas.Pen.Width:=ТОЛЩИНА_В_ТОЧКАХ. Задать цвет Canvas.Pen.Color:=ЦВЕТ.

Рассмотрим пример генератора колебаний, который можно скачать здесь (3,1КБ). Генератор сам по себе есть только на экране. Колебания, которые он создает, рассчитываются по формуле. Следовательно, он вам может оказаться полезным. Можно изменить рассчетную функцию и вы получите для этой функции график.

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

1. Программа имеет только одно окно Form1, у которого сразу переименовываем заголовок на подходящее название.
2. Устанавливаем свойство Form1.Position в poDesktopCenter, чтобы окно при каждом запуске и при любом экранном разрешении всегда было ровно посередине экрана.
3. Устанавливаем свойство Form1.BorderStyle в bsSingle, для неизменяемого размера окна. Оставляем во вложенных свойствах BorderIcons только biSystemMenu в true, остальные в false. Это для того, чтобы окно нельзя было свернуть в значек, развернуть во весь экран и окно имело иконку в заголовке.
4. Устанавливаем в форму компонент PaintBox, два компонента RadioButton, CheckBox, три кнопки Button и TrackBar, расположенный на странице Win32.
5. RadioButton1.Caption переименовываем в "Sin". Этот флаг будет признаком рисования синусоиды. RadioButton2.Caption переименовываем в "Cos" - косинусоида. Начальное значение флага Checked для RadioButton1 в true.
6. CheckBox1.Caption переименовываем в "Все". Если флаг установлен, то будет рисоваться два графика.
7. Названия кнопок Button1 - "Старт", Button2 - "Стоп (пауза)" и Button3 - "Выход". Названия на кнопках меняются через свойство Caption. Теперь назначение этих кнопок понятно.
8. Компонент TrackBar1 свойство минимального значения Min устанавливаем в 1, максимальное значение Max - 50.
9. PaintBox1, на котором будет непосредственно рисоваться график размеры высоты Height=140, ширина Width=500.

Привожу текст модуля для окна Form1.

Сразу после слова implementation в модуле окна объявляем глобальные переменные, которые будут доступны из любой процедуры в этом модуле.

Var stop:boolean; // признак рисования
x:Integer; // координата оси X

Реакция на событие нажатия на кнопку Button1 (Начало рисования)

procedure TForm1.Button1Click(Sender: TObject);
Var y:Integer; // ось Y
begin
if x=0 then // если точка в начале координат, то:
begin
PaintBox1.Canvas.Brush.Color:=clWhite; // цвет фона белый
PaintBox1.Canvas.FillRect(ClientRect); // заливка всей рабочей области
end;
stop:=false; // флаг старта процесса рисования
While not stop do // бесконечный цикл, пока флаг остановки не поднят:
begin
if (RadioButton1.Checked)or(CheckBox1.Checked) then // если установлен "Sin" или "Все", то:
begin
y:=Round(Sin(pi*x/100)*50)+70; // вычисление положения синусоиды
PaintBox1.Canvas.Pixels[x,y]:=clBlack; // нарисовать черную точку
end;
if (RadioButton2.Checked)or(CheckBox1.Checked) then // если установлен "Cos" или "Все", то:
begin
y:=Round(Cos(pi*x/100)*50)+70; // вычисление положения косинусоиды
PaintBox1.Canvas.Pixels[x,y]:=clBlack; // нарисовать черную точку
end;
inc(x); // увеличить значение X на едицину. Аналог X:=X+1
if x>500 then // если X вышел за пределы PaintBox1, то:
begin
x:=0; // установить X на начало координат
PaintBox1.Canvas.Brush.Color:=clWhite; // Цвет фона белый
PaintBox1.Canvas.FillRect(ClientRect); // Очистка рабочей области PaintBox1
end;

Sleep(TrackBar1.Position); // Процедура "засыпает" на заданное время в миллисекундах
Application.ProcessMessages; // Обработка всей очереди сообщений
end;
end;

Коротко расскажу работу этой процедуры.
Как только нажата кнопка "Старт" Компонент PaintBox1 очищается и начинается бесконечный цикл While, выйти из которого можно только, пока переменная Stop не примет значение true. Это можно сделать кнопкой Button2, соответствующая процедура которой обработается во время Application.ProcessMessages. С помощью бегунка TrackBar1 можно менять скорость рисования кривой. Этот параметр передается в команду Sleep.

Процедура нажатия на кнопку остановки Button2:

procedure TForm1.Button2Click(Sender: TObject);
begin
Stop:=true; // установить флаг остановки процесса рисования
end;

Процедура создания окна Form1OnCreate:

procedure TForm1.FormCreate(Sender: TObject);
begin
x:=0; // начальное значение X
end;

Если нажата кнопка "Выход", то реакция на это событие будет таким:

procedure TForm1.Button3Click(Sender: TObject);
begin
Close; // закрыть окно
end;

И реакция перед закрытием окна OnClose. Без этой процедуры, если рисование включено, то окно не закроется.

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Stop:=true; // остановить (если включен) цикл рисования
end;

После запуска программы, установки флажка "Все" и нажатии на кнопку "Старт" на экране отобразится этот график:

В принципе, с нашей программой можно отслеживать практически любые функции. Просто надо описать свою отслеживаемую функцию вместо моих строк Y:=Sin...
Если вы хотите убрать постоянную прорисовку графика функции, то следующий код в программе

if x>500 then // если X вышел за пределы PaintBox1, то:
begin
x:=0; // установить X на начало координат
PaintBox1.Canvas.Brush.Color:=clWhite; // Цвет фона белый
PaintBox1.Canvas.FillRect(ClientRect); // Очистка рабочей области PaintBox1
end;

измените на:

if x>500 then // если X вышел за пределы PaintBox1, то:
begin
x:=0; // установить X на начало координат
Stop:=true; // остановка рисования
end;

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

Y:=140 - ФУНКЦИЯ;

Как видите, поле для экспериментов велико. Приступайте к самостоятельному изучению.

С уважением, ведущий уроков Semen semen@krovatka.net

 

Урок19. Всплывающая подсказка

Этот вид подсказок удобен, прежде всего, тем, что назначение элемента, на который подведен указатель мыши, видно до непосредственной его активации. Например, кнопка "Применить" можно снабдить подсказкой "Сохранить все настройки без закрытия окна".

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

Во время инициализации и запуска приложения на выполнение, происходит считывание системных переменных в переменные программы, в т.ч. и параметров всплывающей подсказки. Эти переменные и свойства можно менять во время работы приложения, некоторые еще при проектировании, добываясь тем самым отличия от стандартных windows-приложений.

Для того, чтобы у интересующего вас параметра появлялась всплывающая подсказка, необходимо, прежде всего установить сам текст подсказки. Это свойство Hint. Для каждого компонента программы Hint может быть разный.
Второй шаг, это указать, что подсказку для интересующего нас компонента надо показывать. Это свойство ShowHint. Его нужно установить в true для отображения, и false наоборот.
Два вышеперечисленных свойства доступны еще до запуска программы, во время редактирования проекта. По умолчанию свойство ShowHint имеет значение false, т.е. подсказка не высвечивается.
Целесообразнее устанавливать эти свойства в инспекторе объектов, чем программно, этим самым вы не засоряете текст кода программы. В редакторе кода порой бывает так много строк, что трудно сразу разобраться в возможной ошибке и подобные строки могут сбивать с толку. Исключением в нашем случае может быть постоянно меняющаяся всплывающая подсказка. Например, при изменении функционального назначения кнопки, меняется и текст подсказки.

Программная установка текста всплывающей подсказки для кнопки Button1:

Button1.Hint:='Нажми на меня, и ты узнаешь, что ты наделал';

Программная активация подсказки для кнопки Button1 (только дает возможность всплывающей подсказке высвечиваться, а не выводит ее на экран!)

Button1.ShowHint:=true;

Теперь поговорим про цвет фона подсказки и про некоторые другие параметры.

Цвет фона всплывающей подсказки для всего приложения меняется очень легко.

Application.HintColor:=ЦВЕТ;

Цвет задается через зарезервированные константы или цифровым кодом. Например, белый цвет может быть задан с помощью константы clWhite, с помощью шестнадцатеричного представления $00FFFFFF, или обычным, привычным нам десятичным числом 16777215. Ниже представлена таблица цветов, которые определены как стандартные константы цветов.

Константа Цвет
clAqua  
clBlack  
clBlue  
clFuchsia  
clGray  
clGreen  
clLime  
clMaroon  
clNavy  
clOlive  
clPurple  
clRed  
clSilver  
clTeal  
clWhite  
clYellow  

Стандартный цвет всплывающей подсказки, установленный в свойствах экрана windows, хранится в константе clInfoBk. Она является элементом со статусом "только для чтения" и изменение недопустимо.

Установка паузы перед появлением всплывающей подсказки.

Application.HintPause:=ЗНАЧЕНИЕ;

Значение задается в миллисекундах.
Изменение этого свойства может вам показаться бессмысленным. Но иногда необходимо, чтобы пользователь видел всплывающую подсказку немедленно после наведения на компонент мышкой. Иногда нужно вообще убрать на продолжительный срок появление подсказки, чтобы она лишний раз не привлекала к себе внимание. Обычное начальное значение в windows 500 мс (полсекунды).
Время отображения подсказки на экране равно 2500 мс (2,5 с). Программно для вашего приложения это время задается следующим образом.

Application.HintHidePause:=ЗНАЧЕНИЕ;

Это все по общим свойствам всплывающей подсказки. Можете для закрепления материала скачать пример по этой ссылке. Этот пример может быть интересен и специалистам в области программирования. В нем объясняется принцип отображения подсказки в компоненте TStatusBar без каких-либо дополнительных компонентов.
Еще примечание к примеру: числовые значения вводятся в текстовом виде в компонентах Edit1 и Edit2. На ходу происходит их преобразование в числовые с помощью циклов try-except (урок 18). Некорректное введение числового значения контролируется. Но если программу запускать на выполнение через оболочку delphi (run), а не из проводника windows или другим методом запуска, то delphi контролирует самостоятельно такое преобразование и внутри цикла try-except. И в случае обнаружения ошибки прервет выполнение программы. Это неудобство встречается в delphi3, delhpi4, delphi5 (опробовано лично мной). Поэтому такой некорректный ввод чисел лучше всего тестировать, отдельно запуская программу, или с помощью процедуры Val.

С уважением, ведущий уроков Semen semen@krovatka.net

 

Урок20. Сообщения для пользователя

Автор уроков по delphi для начинающих благодарит вебмастера, программиста, просто хорошего человека jurii jurii@karelia.ru, без которого написание этого урока было бы просто невозможным.

В этом уроке мы с вами рассмотрим организацию некоторых сообщений в программе.

Сообщения присутствуют повсюду: когда вы пытаетесь закрыть не сохраненный проект, при появлении ошибки, когда программа сообщает о некотором событии.
Сообщения, "вылетающие" при работе программы, можно разделить на те, которые программист предусмотрел, и системные сообщения.
В большинстве случаев второй тип сообщений имеет непонятный для обычного пользователя вид. Как правило, сообщается англоязычный термин, иногда имеется и шестнадцатеричный адрес ошибки. Например, сообщение "I/O Error" говорит программисту или пользователю об ошибке ввода-вывода. Это может быть попытка записи данных в неоткрытый файл, попытка открыть несуществующий файл и т.п. Если такая ошибка в вашей русскоязычной версии программы имеет место, то, скорее всего данной ситуации программист просто не предусмотрел. В таких случаях, программа может себя повести совершенно непредсказуемо. Ведь вы помните из прошлых уроков, что не проконтролированный кусок программы на присутствие ошибки ведет к моментальному выходу из обрабатываемой процедуры, со всеми вытекающими из этого последствиями.
Но это маленькое отклонение от темы. Идея такова, надо самостоятельно просчитывать все возможные случаи и самостоятельно обрабатывать эти ситуации. Иногда, если надо, предупреждать пользователя об ошибках, может даже сообщать об окончании обработки данных. Вот о таких сообщениях мы и поговорим в этом уроке.

Можно разделить все программные сообщения на: информационные сообщения ("Загрузка данных с дискеты завершена") , предупреждающие сообщения ("Файл модифицирован. Сохранить?"), сообщения об ошибке ("Файл данных программы не найден. Требуется переустановка программы"). Эта разбивка на типы сообщений является, естественно, не полным, его можно продолжать, но об этом немного позже.

Ради экономии своего времени, вы можете всегда, из любого места программы показать пользователю, к примеру, следующее сообщение:

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

ShowMessage('Привет!');

Тип данных в скобках - String.
Все довольно просто, мы с вами эту команду неоднократно применяли в прошлых уроках.
На этой команде работа процедуры (не всей программы!) приостанавливается. Пока пользователь не нажмет на кнопку Ok, работа с приложением становится невозможным, т.е. нельзя "добраться" до окна, расположенного позади. Т.е. это сообщение открывается модально.

Как вы заметили, заголовок окна простой. Он содержит в себе текст, который отображен на панели задач. По умолчанию имеет название запускаемого EXE файла. Изначально это Project1, в последствии вы его можете сохранить под другим именем ("Save Project As..."), при этом название проекта, вместе с ним название компилируемого EXE файла меняется.
Изменить название запущенной программы в панели задач можно в любом месте программы с помощью команды:

Application.Title:='Название программы';

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

Изначально, еще до запуска программы на выполнение, на этапе разработки, вы можете это задать название программы в панели задач с помощью главного меню delphi "Project", дальше пункт "Options...", в открывшемся окне на вкладке Application указать в поле Title необходимую строку. Эта строка и будет отображена в панели задач. При этом следует помнить, что слишком длинная фраза в кнопке на панели задач полностью не будет показана. При этом она будет обрезана троеточием, а для того, чтобы узнать полное название запущенной программы, нужно будет подвести мышку (всплывающая подсказка Hint вам покажет полное название).

Вы уже знаете все прелести простой команды вывода строки ShowMessage. Из недостатков отмечу, что нельзя отдельно от названия программы в панели задач, менять заголовок окошка, нельзя получить иконку в окошке, нельзя отображать другие кнопки.

В delphi есть, можно сказать, встроенная команда отображения окна сообщения. Звучит оно так:

MessageDLG(ТЕКСТ_СООБЩЕНИЯ,ТИП_СООБЩЕНИЯ,КНОПКИ,ИНДЕКС_ПОМОЩИ);

Скажу сразу, что к нашим программам мы пока не пишем дополнительно файлов справки, поэтому ИНДЕКС_ПОМОЩИ у нас всегда будет нулевым. Для информации скажу, что если у нас таковой файл имеется, то можно в таком сообщении сделать кнопку "Help". Если пользователь озадачен вопросом или сообщением, то может, не закрывая этого окна, узнать подробнее о дальнейших этапах работы при выборе того или иного пункта.
ТЕКСТ_СООБЩЕНИЯ - строковая величина. Как в предыдущей команде, сообщение показывается внутри окна.
ТИП_СООБЩЕНИЯ - может принимать несколько значений. От этих значений зависит содержимое заголовка и иконка в левом верхнем углу окна.

Тип сообщения Описание Вид окна
mtWarning Можно использовать в предупреждающих сообщениях. Например, "Вы действительно желаете удалить все данные с диска С:"
mtError Обычное окошко вывода сообщения об ошибки. Всем знаком его вид т.к. это наиболее частое окно в windows :)
mtInformation Какая-нибудь информация. Например, "Не найден файл настройки, создается заново"
mtConfirmation Это запрос. Запрос на сохранение перед выходом, спрашивает перед удалением параметра, и т.п. На ваш собственный вкус
mtCustom Это сообщение полностью аналогично ShowMessage

КНОПКИ - содержит в себе массив кнопок, которые следует показывать в сообщении.
Даю перечень кнопок.


* mbYes
* mbNo
* mbOK
* mbCancel
* mbHelp
* mbAbort
* mbRetry
* mbIgnore
* mbAll

 

Рассказывать про каждую кнопку не буду, т.к. все равно ее название нельзя сменить. А если вам англоязычный термин непонятен, то тогда какой смысл ее применять :).
Массив кнопок задается в квадратных кавычках []. Например, нам надо задать три кнопки Yes, No, Cancel. Это делается так [mbYes,mbNo,mbCancel].
Поскольку кнопки в сообщении могут быть разные, то MessageDLG является функцией. Она возвращает результат нажатой кнопки.
Соответственно указанным выше кнопкам результат может принимать следующие значения


* mrNone - окно сообщения закрыто не с помощью кнопки (Alt+F4 или кнопкой "закрыть")
* mrAbort
* mrYes
* mrOk
* mrRetry
* mrNo
* mrCancel
* mrIgnore
* mrAll

Рассмотрим пример. Нам надо спросить у пользователя о дальнейших действиях перед выходом из программы.
1. Сохранить файл.
2. Не сохранять файл.
3. Продолжить редактирование.

Var R:Word; // переменная, в которой хранится результат
...
R:=MessageDLG('Сохранить файл перед выходом?',mtConfirmation,[mbYes,mbNo,mbCancel],0);
if R=mrYes then // если нажата кнопка Yes
begin
// сохраняем файл и завершаем программу
end;
if R=mrNo then // если нажата кнопка No
begin
// завершаем работу программы без сохранения
end;
if R=mrCancel then // если нажата кнопка Cancel
begin
// продолжаем работу без сохранения
end;

Мы рассмотрели команду MessageDLG. Это очень гибкая команда, есть много достоинств, но есть один существенный недостаток - англоязычный интерфейс.

Следующая команда использует системные сообщения пользователю вашей операционной системы. Т.е., если у вас установлена, например немецкая версия windows, то кнопки будут иметь соответствующие названия на немецком языке.
Вот эта команда:

MessageBox(Handle,ТЕКСТ_СООБЩЕНИЯ,ЗАГОЛОВОК_ОКНА,ТИП_СООБЩЕНИЯ);

Первый параметр - указатель на владельца окна сообщения. Этот параметр вам пока ничего не говорит, устанавливайте его в Handle (это ссылка на окно, откуда это сообщение вызывается).
ТЕКСТ_СООБЩЕНИЯ и ЗАГОЛОВОК_ОКНА - имеют тип PChar, поэтому, во избежание недоразумений и появления неизвестного рода ошибок, выдаваемых компилятором, меняйте тип String в PChar "на ходу". Например:

MessageBox(Handle,PChar('ТЕКСТ_СООБЩЕНИЯ'),PChar('ЗАГОЛОВОК_ОКНА'),...

Это был перевод из одного типа строковой величины в другой тип.

Теперь поговорим о немного сложном параметре ТИП_СООБЩЕНИЯ. Он включает в себя иконку и кнопки.

Кнопки:
* MB_ABORTRETRYIGNORE - кнопки "Прервать", "Повторить", "Пропустить".
* MB_OK - кнопка "Ok".
* MB_OKCANCEL - кнопки "Ok", "Отмена".
* MB_RETRYCANCEL - кнопки "Повторить" и "Отмена".
* MB_YESNO - две кнопки "Да" и "Нет".
* MB_YESNOCANCEL - кнопки "Да", "Нет", "Отмена".

Для того, чтобы отобразить иконку, нужно указать:
* MB_ICONEXCLAMATION
* MB_ICONWARNING
* MB_ICONINFORMATION
* MB_ICONASTERISK
* MB_ICONQUESTION
* MB_ICONSTOP
* MB_ICONERROR
* MB_ICONHAND
Если у вас в сообщении несколько кнопок, а по умолчанию нужно выбрать определенную, то такая кнопка задается:
MB_DEFBUTTON1 - где последняя цифра указывает номер кнопки, выбранной по умолчанию. Это свойство может быть полезным, например, чтобы обезопасить данные от случайного уничтожения. "Удалить файл?". Две кнопки - "Да", "Нет". По умолчанию мы программно выбираем вторую кнопку. Если пользователь сразу нажал на Enter, не осознавая своего поступка, можно сказать по привычке, то ничего страшного не произойдет.

Как же указать параметры иконки, кнопок, кнопки по умолчанию в одном параметре ТИП_СООБЩЕНИЯ. Очень просто. Простым знаком +
Например:

MessageBox(Handle,PChar('Выйти из программы?'),PChar('Мое сообщение'),MB_ICONINFORMATION+MB_OKCANCEL+MB_DEFBUTTON2);

 

Выглядит это в программе так, как показано на рисунке:

Итак, MessageBox можно считать идеальной командой вывода сообщения пользователю, которая будет совместима со всеми языковыми версиями windows.

Контроль нажатия на кнопку в MessageBox мы осуществляем аналогично MessageDLG, только возвращаемая величина может принимать следующие значение (соответственно нажатой кнопке):

 

* IDABORT
* IDCANCEL
* IDIGNORE
* IDNO
* IDOK
* IDRETRY
* IDYES

 

Оъявление. Автор уроков для начинающих по delphi ищет темы, какие вам было бы интересно узнать. Свои предложения отсылайте мне, Semen'у, по адресу semen@krovatka.net, указав в теме письма слово "предложение". Ваше предложение не должно быть очень сложным для программного решения, понятным для начинающего, тема не должна отклоняться от тематики ведения уроков (например, не рассматривается управление базами данных, SQL, internet и пр.). Материал, написанный по вашему предложению, ориентировочно должен быть дан в объеме одного урока. Предложение в этот урок должно быть отправлено до пятницы.

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

С уважением, ведущий уроков Semen semen@krovatka.net

 

 

Урок21. Программа психологических тестов

Автор благоларит jurii jurii@karelia.ru, за идею этого урока.

На этом уроке мы закрепим знания, полученные в прошлых уроках, и как всегда, изучим много нового.

Программа "Тесты" скорее всего, может пригодиться многим. Тем более что мы ее будем писать, изначально универсальной. Вопросы с ответами будет подгружаться из специального текстового файла.

Рассмотрим пошаговую работу над созданием программы.

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

Итак, вот пример такого планирования.

Сам текст теста располагается в текстовом файле. Значит, в одном текстовом файле у нас будет храниться вся необходимая для него информация, в том числе и служебная, относительно скрытая от пользователя. Почему мы делаем именно текстовый файл, а не работаем с двоичным, потому что заносить данные в такой файл легко, не требуется писать отдельной программы создания файлов теста, написать и изменить можно в любом текстовом редакторе.
Для планировки структуры такого файла мы должны разбить всю хранимую в нем информацию на отдельные строки. Эти строки могут быть объединены по одинаковым признакам. Читаться такой файл программой будет по строкам.

Каждый тест должен имееть следующую структуру:
1. Название.
2. Количество вопросов.
<Начало блока вопросов>
3. Вопрос.
4. Возможные варианты ответов (для нашей программы сделаем четыре варианта ответов).
5. Баллы, присуждаемые за тот или иной ответ.
<Конец блока вопросов>
6. Несколько вариантов результатов теста, зависимых от набранных баллов, которые показываются тестируемому человеку (для нашей программы сделаем четыре результата теста).

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

Тест, взятый для примера в этом уроке, был любезно выдерт мною из первого попавшегося журнала на столе моей сестры. Это журнал "Cool girl" №23 от 1998 года. Староват, да ничего, подойдет. Да простят меня мужчины, но это тест для молодых девушек. Впрочем, если что не нравится - текстовый редактор вам в руки и вперед. Если вы отошлете файл своих собственных тестов (рабочий, проверенный файл тестов, в частности, ищу тест определения темперамента человека) мне, автору уроков, то это будет замечательно. Все ваши тесты постараюсь разместить прямо в этом уроке.

Как создать файл тестов. Создаем в любом текстовом редакторе, желательно в блокноте windows новый файл.
Важно, в таком редакторе убрать опцию "автоперенос слов", чтобы нас не сбивало с толку перенесенные строки, ведь они у нас иногда будут очень длинными.
Первая строчка в файле должна содержать название теста. Для моего теста "Умеешь ли ты отдыхать?". Каждая такая строчка должна завершаться нажатием на клавишу Enter (перевод строки).
Следующая строка содержит число вопросов в тесте. Их у нас 16.
Дальше у нас следует блок вопросов и ответов на них. Этот блок должен повторяться количество раз, заданное в строке количества вопросов - 16.
Первая строка - вопрос.
Вторая строка - первый ответ.
Третья строка - количество баллов за этот ответ.
Четвертая строка - второй ответ.
и т.д.
В конце файла теста следуют результаты теста.
Первая строка - число, начальный интервал баллов.
Вторая строка - число, конечный интервал баллов.
Третья строка - вариант результата теста.
и т.д. для всех результатов теста.

Файл теста мы с вами рассмотрели, теперь примемся за написание программы.

Снова спланируем нашу задачу.
1. Сделаем, чтобы при запуске программы, она спрашивала у нас, какой тест необходимо загрузить. Если теста нет или пользователь отказывается открывать тест, то программа завершает свою работу.
2. При успешном выборе теста, программа открывает этот файл, считывает название, считывает количество вопросов, и предлагает первый вопрос с ответами на него.
3. После перебора всех вопросов открывается окно результатов теста.
4. Завершение работы программы.
Внешний вид программы можно спланировать так, вопрос и возможные варианты ответов будут размещены на разных панелях. На панелях разместим компоненты отображения текста (Label) и по одной кнопке на каждый вариант ответа.
Окно результатов теста планировать не будем, текст результата можно высветить на первых порах разработки программы с помощью команды ShowMessag

– Конец работы –

Эта тема принадлежит разделу:

Далее немного вашего внимания уделю процессу установки Delphi на компьютер

Delphi Делфи... Здравствуйте Меня зовут Semen Я ведущий уроков по Delphi Мы с вами... Что же такое Delphi Это среда разработки используемой прежде всего для создания и поддержки приложений...

Если Вам нужно дополнительный материал на эту тему, или Вы не нашли то, что искали, рекомендуем воспользоваться поиском по нашей базе работ: Запись и чтение из файла не текстовых данных

Что будем делать с полученным материалом:

Если этот материал оказался полезным ля Вас, Вы можете сохранить его на свою страничку в социальных сетях:

Все темы данного раздела:

Коротко про пункты главного меню Delphi
Пункт меню “File” Если нужно сохранить проект, то Вы выбираете пункт главного меню“File” (с помощью мышки или по клавише Alt+F). У вас, в зависимости от установленной верс

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

Открытие проекта
Для открытия проекта необходимо выбрать пункт меню файл "Open Project" и выбрать название интересующего вас проекта DPR. При этом открываются как сам проект, так и становятся доступными в

Функция WinExec
WinExec, оставлена для совместимости с ранними версиями Windows, но я рекомендую для обычного запуска программы с командной строкой использовать эту. У нее мало параметров запуска. Использ

Функция ShellExecute
Функция ShellExecute не только запускает программы, а открывает, редактирует или печатает файл, с учетом зарегестрированного типа, а также открывает указанную папку проводником. Возвращает Handle с

Копирование файлов
Для копирования файлов применяется функция CopyFile. Формат ее такой: CopyFile(Исходный_файл,Записуемый_файл,Флаг_перезаписи); где: Исходный_файл – полный путь и название файла, к

Переименование файлов
Функция RenameFile if not RenameFile('c:2.com','c:3.com') then ShowMessage('Ошибка переименования'); У всех вышесказанных командах параметры исходного и конечного файла имеет тип

Работа с текстовыми файлами. Чтение из текстового файла
На прошлых уроках мы рассматривали пример простейшего текстового редактора. В нем, в компоненте Memo процесс загрузки и записи текстового файла делался следующим образом: Memo1.Lines.LoadF

Хотите получать на электронную почту самые свежие новости?
Education Insider Sample
Подпишитесь на Нашу рассылку
Наша политика приватности обеспечивает 100% безопасность и анонимность Ваших E-Mail
Реклама
Соответствующий теме материал
  • Похожее
  • Популярное
  • Облако тегов
  • Здесь
  • Временно
  • Пусто
Теги