Отладка программы в Delphi
Блоксхема процедуры выбора точки маршрута
Рисунок 12.11. Блок-схема процедуры выбора точки маршрута
Диалоговое окно Обзор папок появляется в результате щелчка на кнопке Папка
Рисунок 12.6. Диалоговое окно Обзор папок появляется в результате щелчка на кнопке Папка
Основную работу выполняет рекурсивная функция Find. У функции Find один-единственный параметр — структура searchRec, которая используется функциями FindFirst и FindNext для поиска соответственнопервого и следующего файла, удовлетворяющего критерию поиска. Следует обратить внимание на то, как осуществляется перебор каталогов в текущем каталоге. Если текущий каталог не корневой, то помимо обычных, то есть имеющих имя, в каталоге есть еще два каталога: .. и ., которые обозначают каталог предыдущего уровня. Эти два каталога не обрабатываются, так как при входе в эти каталоги фактически выполняется выход (переход) в родительский каталог. Если этого не учесть, то программа зациклится.
Кривая Гильберта
Кривая ГильбертаСледующая программа вычерчивает в диалоговом окне кривую Гильберта. На Рисунок 12.7 приведены кривые Гильберта первого, второго и третьего порядков. Если присмотреться, то видно, что кривая второго порядка получается путем соединения прямыми линиями четырех кривых первого порядка. Аналогичным образом получается кривая третьего порядка, но при этом в качестве "кирпичиков" используются кривые второго порядка. Таким образом, чтобы нарисовать кривую третьего порядка, надо нарисовать четыре кривых второго порядка. В свою очередь, чтобы нарисовать кривую второго порядка, надо нарисовать четыре кривых первого порядка. Таким образом, алгоритм вычерчивания кривой Гильберта является рекурсивным.
Диалоговое окно программы Кривая Гильберта, в котором находится кривая пятого порядка, приведено на Рисунок 12.8, текст программы — в листинге 12.4.
Кривые Гильберта первого второго и третьего порядков
Рисунок 12.7. Кривые Гильберта первого, второго и третьего порядков
Рекурсивная функция вычисления факториала
Листинг 12.1. Рекурсивная функция вычисления факториалаfunction factorial(n: integer): integer;
begin
if n <>
1
then factorials n * factorial(n-1)
// функция вызывает сама себя
else factorial := 1; // рекурсивный процесс закончен
end;
Обратите внимание, что функция вызывает сама себя только в том случае, если значение полученного параметра k не равно единице. Если значение параметра равно единице, то функция сама себя не вызывает, а возвращает значение, и рекурсивный процесс завершается.
На Рисунок 12.1 приведен вид диалогового окна программы, которая для вычисления факториала числа использует рекурсивную функцию factorial. Текст программы приведен в листинге 12.2.
Использование рекурсивной функции
Листинг 12.2. Использование рекурсивной функцииunit factor ;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Edit1: TEdit;
Button1: TButton;
Label2: TLabel;
procedure ButtonlClick(Sender: TObject) ;
private
{ Private declarations } public
{ Public declarations } end;
var
Form1: TForm1;
implementation
{$R *.DFM}
// рекурсивная функция
function factorial(n: integer): integer;
begin
if n >
1
then factorial := n * factorial(n-1) // функция вызывает сама себя
else factorial:= 1; // факториал 1 равен 1
end;
procedure TForml.ButtonlClick(Sender: TObject);
var
k:integer; // число, факториал которого надо вычислить
f:integer; // значение факториала числа k
begin
k := StrToInt(Edit1.Text);
f := factorial(k);
label2.caption:='Факториал числа '+Edit1.Text
+ ' равен '+IntToStr(f);
end;
end.
На Рисунок 12.2 приведены два диалоговых окна. Результат вычисления факториала, представленный на Рисунок 12.2, а, соответствует ожидаемому.
Программа поиск файлов
Листинг 12.3. Программа поиск файлов// поиск файла в указанном каталоге и его подкаталогах
// используется рекурсивная процедура Find
unit FindFile_;
interface
uses
Windows, Messages, SysUtils, Variants,
Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileCtr;
type
TForm1 = class(TForm)
Editl: TEdit; // что искать
Edit2: TEdit; // где искать
Memo1: TMemo; // результат поиска
Button1: TButton; // кнопка Поиск
Button2: TButton; // кнопка Папка
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
FileName: string; // имя или маска искомого файла
cDir: string;
n: integer; // кол-во файлов, удовлетворяющих запросу
// поиск файла в текущем каталоге
procedure Find;
var
SearchRec: TSearchRec; // информация о файле или каталоге
begin
GetDir(0,cDir);
// получить имя текущего каталога
if cDir [length (cDir) ] <>
'V then cDir := cDir+'\';
if FindFirst(FileName, faArchive,SearchRec) = 0
then repeat
if (SearchRec.Attr and faAnyFile) = SearchRec.Attr
then begin
Form1.Memo1.Lines.Add(cDir + SearchRec.Name);
n := n + 1; end; until FindNext(SearchRec) <>
0;
// обработка подкаталогов текущего каталога
if FindFirst('*', faDirectory, SearchRec) = 0 then repeat
if (SearchRec.Attr and faDirectory) = SearchRec.Attr then begin
// каталоги .. и . тоже каталоги,
// но в них входить не надо .'.'.'
if SearchRec.Name[1] <>
'.' then begin
ChDir(SearchRec.Name);
// войти в каталог
Find; // выполнить поиск в подкаталоге
ChDir('..');
// выйти из каталога
end;
end;
until FindNext(SearchRec) <>
0;
end;
/ возвращает каталог, выбранный пользователем
function GetPath(mes: string):string;
var
Root: string; // корневой каталог
pwRoot : PWideChar; Dir: string;
begin
Root := '';
GetMem(pwRoot, (Length(Root)+1) * 2);
pwRoot := StringToWideChar(Root, pwRoot, MAX_PATH*2);
if SelectDirectory(mes, pwRoot, Dir) then
if length(Dir) =2 // пользователь выбрал корневой каталог
then GetPath := Dir+'\' else GetPath := Dir else
GetPath := '';
end;
щелчок на кнопке Поиск
procedure TForml.ButtonlClick(Sender: TObject);
begin
Memo1.Clear; // очистить поле Memol
Label4.Caption := '';
FileName := Edit1.Text; // что искать.
cDir := Edit2.Text; // где искать
n:=0; // кол-во найденных файлов
ChDir(cDir);
// войти в каталог начала поиска
Find; // начать поиск
if n = 0 then
ShowMessage('Файлов, удовлетворяющих критерию поиска нет.')
else Label4.Caption := 'Найдено файлов:' + IntToStr(n);
end;
// щелчок на кнопке Папка
procedure TForml.Button2Click (Sender: TObject);
var
Path: string; begin
Path := GetPath('Выберите папку');
if Path <>
''
then Edit2.Text := Path;
end;
end.
Кривая Гильберта
Листинг 12.4. Кривая Гильбертаunit gilbert_;
interface
uses
Windows, Messages, SysUtils,
Variants, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls, ComCtrls;
type
TForml = class(TForm)
procedure FormPaint(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation {$R *.dfm}
var
p: integer =5; // порядок кривой
u: integer =7; // длина штриха
{ Кривую Гильберта можно получить путем
соединения элементов а,b,с и d.
Каждый элемент строит
соответствующая процедура. }
procedure a(i:integer; canvas: TCanvas);
forward;
procedure b(i:integer; canvas: TCanvas);
forward;
procedure с(i:integer; canvas: TCanvas);
forward;
procedure d(i:integer; canvas: TCanvas);
forward;
// Элементы кривой
procedure a(i: integer; canvas: TCanvas);
begin
if i >
0 then begin
d(i-l, canvas);
canvas.LineTo(canvas.PenPos.X+u,canvas.PenPos.Y);
a(i-l, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y+u);
a(i-l, canvas);
canvas.LineTo(canvas.PenPos.X-u,canvas.PenPos.Y);
с (i-1, canvas);
end;
end;
procedure b(i: integer; canvas: TCanvas);
begin
if i >
0 then begin
c(i-l, canvas);
canvas.LineTo(canvas.PenPos.X-u,canvas.PenPos.Y);
b(i-1, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y-u);
b(i-l, canvas);
canvas.LineTo(canvas.PenPos.X+u, canvas.PenPos.Y);
d(i-l, canvas);
end;
end;
procedure c(i: integer; canvas: TCanvas);
begin
if i >
0 then begin
b(i-1, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y-u);
с (i-1, canvas);
canvas.LineTo(canvas.PenPos.X-u,canvas.PenPos.Y);
c(i-1, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y+u);
a(i-1, canvas);
end;
end;
procedure d(i: integer; canvas: TCanvas);
begin
if i >
0 then begin
a(i-1, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y+u);
d(i-1, canvas);
canvas.LineTo(canvas.PenPos.X+u,canvas.PenPos. Y) ;
d(i-1, canvas);
canvas.LineTo(canvas.PenPos.X,canvas.PenPos.Y-u);
b(i-1, canvas);
end;
end;
procedure TForml.FormPaint(Sender: TObject);
begin
Form1.Canvas.MoveTo(u, u) ;
a(5,Form1.Canvas);
// вычертить кривую Гильберта
end;
end.
Следует обратить внимание на следующую особенность реализации программы. Процедура, которая вычерчивает элемент а, помимо самой себя (для вычерчивания элемента а кривой более низкого порядка) вызывает процедуры d и ь, описание (текст) которых в тексте программы находится после процедуры а. Чтобы компилятор не вывел сообщение об ошибке, в текст программы помещено объявление процедуры с ключевым словом forward, означающим, что это только объявление, а описание (реализация) находится дальше. Таким образом, уже в процессе компиляции процедуры а, компилятор "знает", что имена ь и d означают процедуры.
Поиск маршрута
Листинг 12.5. Поиск маршрутаunit road_;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms,
Dialogs, StdCtrls, Grids;
type
TForml = class(TForm)
StringGridl: TStringGrid;
Edit1: TEdit;
Edit2: TEdit;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Button1: TButton;
Label4: TLabel;
procedure FormActivate(Sender: TObject);
procedure ButtonlClickfSender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForml.FormActivate(Sender: TObject);
var
i:integer; begin
// нумерация строк
for i:=1 to 10 do
StringGridl.Cells[0,i]:=IntToStr(i);
// нумерация колонок
for i:=l to 10 do
StringGridl.Cells[1,0]:=IntToStr(i);
// описание предопределенной карты StringGridl.Cells[1,2]:='1' StringGridl.Cells[2,l]:='1'
StringGridl.Cells[1,3]:='1'
StringGridl.Cells[3,1]:='1'
StringGridl.Cells[1,4]:='1'
StringGridl.Cells[4,1]:='1'
StringGridl.Cells[3,7]:='1'
StringGridl.Cells[7,3]:='1'
StringGridl.Cells[4,6]:='1'
StringGridl.Cells[6,4]:='1'
StringGridl.Cells[5,6]:='1'
StringGridl.Cells[6,5]:='1'
StringGridl.Cells[5,7]:='1'
StringGridl.Cells[7,5]:='1'
StringGridl.Cells[6,7]:='1'
StringGridl.Cells[7,6]:='1'
end;
procedure TForml.ButtonlClick(Sender: TObject);
const
N=10;// кол-во вершин графа var
map:array[1..N,1..N]of integer; // Карта.map[i,j]ne 0,
// если точки i и j соединены
road:array[1..N]of integer;
// Дорога - номера точек карты
incl:array[1..N]of boolean; // incl[1]равен TRUE, если точка
// с номером i включена в road
start,finish:integer; // Начальная и конечная точки
found:boolean; i,j:integer;
procedure step(s,f,p:integer);
var
с:integer;// Номер точки, в которую делаем очередной шаг
i:integer;
begin
if s=f then begin
// Точки s и f совпали !
found:=TRUE;
Labell.caption:=Labell.caption+#13+'Путь:';
for i:=l to p-1 do
Labell.caption:=Labell.caption+' '
+IntToStr(road[i]);
end
else begin
// выбираем очередную точку for c:=l to N do
begin // проверяем все вершины
if(map[s,c]<>
0)and(NOT incite1)
// точка соединена с текущей и не включена в маршрут
then begin
road[p]:=c;// добавим вершину в путь
incl[c]:=TRUE;// пометим вершину как включенную
step(c,f,p+l);
incite]:=FALSE; road[p]:=0;
end;
end;
end;
end;// конец процедуры step
begin
Label1.caption: =' ' ;
// инициализация массивов
for i:=l to N do road[i]:=0;
for i:=l to N do incl[i]:=FALSE;
// ввод описания карты из SrtingGrid.Cells
for i:=l to N do
for j:=1 to N do
if StringGrid1.Cells[i,j] <>
''
then map[i,j]:=StrToInt(StringGridl.Cells[i, j] ;
else map[i,j]:=0;
start:=StrToInt(Editl.text);
finish:=StrToInt(Edit2.text);
road[l]:=start;// внесем точку в маршрут
incl[start]:=TRUE;// пометим ее как включенную
step(start,finish,2);
//ищем вторую точку маршрута
// проверим, найден ли хотя бы один путь
if not found
then Labell.caption:='Указанные точки не соединены!';
end;
end.
При запуске программы в момент активизации формы приложения происходит событие onActivate, процедура обработки которого заполняет массив StringGridl.cells значениями, представляющими описание карты. Этаже процедура нумерует строки и столбцы таблицы, заполняя зафиксированные ячейки первого столбца и первой строки StringGridl.
Поиск маршрута инициирует процедура TFormi.Buttoniciick, которая запускается щелчком на кнопке Поиск. Данная процедура для поиска точки, соединенной с исходной точкой, вызывает процедуру step, которая после выбора первой точки, соединенной с начальной, и включения ее в маршрут вызывает сама себя. При этом в качестве начальной точки задается уже не исходная, а текущая, только что включенная в маршрут.
Поиск кратчайшего пути
Листинг 12.6. Поиск кратчайшего путиprocedure TForm1.Button1Click(Sender: TObject);
const
N=10;{ кол-во вершин графа} var
map:array[1..N,1..N]of integer;
// Карта.map[i,j] не 0,если
// точки i и j соединены
road:array[1..N]of integer;
// Дорога — номера точек карты
incl:array[1..N]of boolean; // incl[1]равен TRUE,если точка
// с номером i включена в road
start, finish:integer;
// Начальная и конечная точки
found:boolean; len:integer; // длина найденного (минимального)
// маршрута } c_len:integer; // длина текущего (формируемого)
// маршрута i,j:integer;
// выбор очередной точки
procedure step(s,f,p:integer);
var
с:integer; { Номер точки, в которую делаем очередной шаг }
i:integer; begin
if s=f then begin
len:=c_len;{ сохраним длину найденного маршрута }
{ вывод найденного маршрута }
for i:=1 to p-1 do
Label1.caption:=Label1.caption+' '+IntToStr(road[i]);
Label1.caption:=Label1.caption
+', длина:'+IntToStr(len)+#13;
end
else
{ выбираем очередную точку }
for c:=l to N do { проверяем все вершины }
if(map[s,c]<>
0)and(NOT incite])
and((len=0)or(c_len+map[s,c]< len)) then begin
// точка соединена с текущей, но не включена в
// маршрут
roadtp]:=c;{ добавим вершину в путь }
incl[c]:=TRUE;{ пометим вершину как включенную }
c_len:=c_len+map[s,с];
step(c,f,p+l);
incite]:=FALSE; roadtp]:=0;
c_len:=c_len-map[s,с];
end;
end;
{ конец процедуры step }
begin
Labell.caption:='';
{ инициализация массивов }
for i: =1 to N do road [ i ] : =0;
for i:=l to N do incl[i]:=FALSE;
{ ввод описания карты из SrtingGrid.Cells}
for i:=l to N do
for j:=1 to N do
if StringGridl.Cells[i, j] <>
"
then mapti,j]:=StrToInt(StringGridl.Cells[i,j])
else mapti,j]:=0;
len:=0; // длина найденного (минимального) маршрута с
len:=0,- // длина текущего (формируемого) маршрута
start:=StrToInt(Edit1.text);
finish:=StrToInt(Edit2.text);
road[1]:=start;{ внесем точку в маршрут }
incl[start]:=TRUE;{ пометим ее как включенную }
step(start,finish,2);
{ищем вторую точку маршрута }
// проверим, найден ли хотя бы один путь
if not found
then Label1.caption:='Указанные точки не соединены!';
end;
Диалоговое окно программы поиска кратчайшего пути и процедура обработки события OnActivate ничем не отличаются от диалогового окна и соответствующей процедуры OnActivate программы поиска всех возможных маршрутов, рассмотренной в предыдущем разделе.
Массив тар
Рисунок 12.10. Массив тар
Содержимое ячейки таблицы на пересечении строки i и столбца j соответcтвует значению map [ i, j ].
Помимо массива тар нам потребуются массив road (дорога) и массив incl(от include — включать). В road мы будем записывать номера пройденных городов. В момент достижения конечной точки он будет содержать номера всех пройденных точек, т. е. описание маршрута.
В inci [i] будем записывать true, если точка с номером i включена в маршрут. Делается это для того, чтобы не включать в маршрут уже пройденную точку (не ходить по кругу).
Так как мы используем рекурсивную процедуру, то надо обратить особое внимание на условие завершения рекурсивного процесса. Процедура должна прекратить вызывать сама себя, если текущая точка совпала с заданной конечной точкой.
На Рисунок 12.11 приведена блок-схема алгоритма процедуры выбора очередной точки формируемого маршрута, а диалоговое окно — на Рисунок 12.12.
Для ввода массива, представляющего описание карты, используется компонент stringGridl (значения его свойств приведены в таблице 12.1), для вывода результата (найденного маршрута) — поле метки Label 1. Начальная и конечная точки маршрута задаются вводом значений в поля редактирования Edit1 и Edit2. Процедура поиска запускается щелчком кнопки Поиск (Buttonl). Поля меток Label2, Label3 и Label4 используются для вывода поясняющего текста.
Окно программы вычисления факториала
Рисунок 12.1. Окно программы вычисления факториала
Поиск кратчайшего пути
Поиск кратчайшего путиОбычно задача поиска пути на графе формулируется следующим образом: найти наилучший маршрут. Под наилучшим маршрутом, как правило, понимают кратчайший. Найти кратчайший маршрут можно выбором из всех найденных. Однако совсем не обязательно искать все маршруты.
Можно поступить иначе: во время выбора очередной точки проверить, не превысит ли длина формируемого маршрута длину уже найденного пути, если эта точка будет включена в маршрут; если превысит, то эту точку следует пропустить и выбрать другую.
Таким образом, после того как будет найден первый маршрут, программа будет вести поиск только по тем ветвям графа, которые могут улучшить найденное решение, отсекая пути, делающие формируемый маршрут длиннее уже найденного.
В листинге 12.6 приведена процедура, которая использует процедуру step, выполняющую выбор очередной точки маршрута таким образом, что обеспечивается поиск пути минимальной длины.
Поиск пути
Поиск путиМеханизм рекурсии весьма эффективен при программировании задач поиска. В качестве еще одного примера рассмотрим задачу поиска пути между двумя городами. Если несколько городов соединены дорогами, то очевидно, что попасть из одного города в другой можно различными маршрутами. Задача состоит в нахождении всех возможных маршрутов.
Карта дорог между городами может быть изображена в виде графа — набора вершин, означающих города, и ребер, обозначающих дороги (Рисунок 12.9).
Понятие рекурсии
Понятие рекурсииРекурсивным называется объект, частично состоящий или определяемый с помощью самого себя. Факториал — это классический пример рекурсивного объекта. Факториал числа п — это произведение целых чисел от 1 до п. Обозначается факториал числа п так: n!.
Согласно определению
n! = 1 х 2 х 3 х ... х (п - 1) х п. Приведенное выражение можно переписать так:
n! = nх ((n - 1) х (n - 2) х ...х 3 х 2 х 1) = n х (n - 1)!
То есть, факториал числа п равен произведению числа п на факториал числа (п - 1). В свою очередь, факториал числа ("-!) — это произведение числа (п - 1) на факториал числа (п - 2) и т. д.
Таким образом, если вычисление факториала п реализовать как функцию, то в теле этой функции будет инструкция вызова функции вычисления факториала числа (п - 1), т. е. функция будет вызывать сама себя. Такой способ вызова называется рекурсией, а функция, которая обращается сама к себе, называется рекурсивной функцией.
В листинге 12.1 приведена рекурсивная функция вычисления факториала.
Представление карты дорог в виде графа
Рисунок 12.9. Представление карты дорог в виде графа
Процесс поиска может быть представлен как последовательность шагов. На каждом шаге с использованием некоторого критерия выбирается точка, в которую можно попасть из текущей. Если очередная выбранная точка совпала с заданной конечной точкой, то маршрут найден. Если не совпала, то делаем из этой точки еще шаг. Так как текущая точка может быть соединена с несколькими другими, то нужен какой-то формальный критерий выбора. В простейшем случае можно выбрать точку с наименьшим номером.
Пусть, например, надо найти все возможные пути из точки 1 в точку 5. Согласно принятому правилу, сначала выбираем точку 2. На следующем шаге выясняем, что точка 2 тупиковая, поэтому возвращаемся в точку 1 и делаем шаг в точку 3. Из точки 3 — в точку 4, из 4 — в 6 и из точки 6 — в точку 5. Один маршрут найден. После этого возвращаемся в точку 6 и проверяем, возможен ли шаг в точку, отличную от 5. Так как это возможно, то делаем шаг в точку 7, и затем — в 5. Найден еще один путь. Таким образом, процесс поиска состоит из шагов вперед и возвратов назад. Поиск завершается, если из узла начала движения уже некуда идти.
Алгоритм поиска имеет рекурсивный характер: чтобы сделать шаг, мы выбираем точку и опять делаем шаг, и так продолжаем до тех пор, пока не достигнем цели.
Таким образом, задача поиска маршрута может рассматриваться как задача выбора очередной точки (города) и поиска оставшейся части маршрута, т. е. имеет место рекурсия.
Граф можно представить двумерным массивом, который назовем тар (карта). Значение элемента массива map[i, j] — это расстояние между городами i и j, если города соединены дорогой, или ноль, если города не соединены прямой дорогой. Для приведенного графа массив тар можно изобразить в виде таблицы, представленной на Рисунок 12.10.
Примеры программ
Примеры программПоиск файлов
В качестве примера использования рекурсии рассмотрим задачу поиска файлов. Пусть нужно получить список всех файлов, например, с расширением bmp, которые находятся в указанном пользователем каталоге и во всех подкаталогах этого каталога.
Словесно алгоритм обработки каталога может быть представлен так:
1. Вывести список всех файлов удовлетворяющих критерию запроса.
2. Если в каталоге есть подкаталоги, то обработать каждый из этих каталогов.
Приведенный алгоритм (его блок-схема представлена на Рисунок 12.4) является рекурсивным: для того чтобы обработать подкаталог, процедура обработки текущего каталога должна вызвать сама себя.
Примеры работы программы вычисления факториала
Рисунок 12.2. Примеры работы программы вычисления факториала
Результат, представленный на Рисунок 12.2, б, не соответствует ожидаемому. Факториал числа 44 равен нулю! Произошло это потому, что факториал числа 44 настолько велик, что превысил максимальное значение для переменной типа integer, и, как говорят программисты, произошло переполнение с потерей значения.
Delphi может включить в исполняемую программу инструкции контроля диапазона значений переменных. Чтобы инструкции контроля были добавлены в программу, нужно во вкладке Compiler диалогового окна Project Options (Рисунок 12.3) установить флажок Overflow checking (Контроль переполнения), который находится в группе Runtime errors (Ошибки времени выполнения).
Рекурсивный алгоритм поиска файлов
Рисунок 12.4. Рекурсивный алгоритм поиска файлов
Вид диалогового окна программы приведен на Рисунок 12.5, текст — в листинге 12.3.
Поле Файл (Edit1) используется для ввода имени искомого файла или маски (для поиска файлов одного типа). Имя каталога, в котором нужно выполнить поиск, можно ввести непосредственно в поле Папка или выбрать из стандартного диалогового окна Обзор папок, которое появляется в результате щелчка на кнопке Папка. Окно Обзор папок (Рисунок 12.6) выводит на экран стандартная функция Seiectoirectory. Следует обратить внимание, что имя каталога, который используется в диалоговом окне Обзор папок в качестве корневого, должно передаваться функции SeiectDirectory как Строка WhideChar. Для Преобразования обычной строки в строку WideChar использована функция StringToWhideChar.
Значения свойств компонента
Таблица 12.1. Значения свойств компонента stringGrid1| Свойство |
Значение |
||
| Name |
StringGrid1 |
||
| ColCount |
11 |
||
| RowCount |
11 |
||
| FixedCols |
1 |
||
| FixedRows |
1 |
||
| Options . goEditing |
TRUE |
||
| DefaultColWidth |
16 |
||
| DefaultRowHeight |
14 |
||
Вкладка Compiler диалогового окна Project Options
Рисунок 12.3. Вкладка Compiler диалогового окна Project Options
Отладка программы в Delphi
Диалоговое окно Add Source Breakpoint
Рисунок 13.4. Диалоговое окно Add Source Breakpoint
Точку останова можно добавить, щелкнув мышью на синей точке, помечающей ту инструкцию программы, перед которой надо поместить точку останова (если в программе нет ошибок, то компилятор помечает выполняемые инструкции программы синими точками).
Для точки останова можно задать условие, при выполнении которого программа приостановит свою работу в данной точке (например, если значение переменной равно определенной величине). Условие (логическое выражение) вводится в поле Condition диалогового окна Add Source Breakpoint.
Добавление имени переменной в список Watch List
Рисунок 13.7. Добавление имени переменной в список Watch List
Добавление точки останова
Добавление точки остановаДля того чтобы поставить в программу точку останова (breakpoint), нужно из меню Run выбрать команду Add Breakpoint (Добавить точку останова), затем из меню следующего уровня — команду Source Breakpoint.
В результате открывается диалоговое окно Add Source Breakpoint (Рисунок 13.4), в котором выводится информация о добавляемой точке останова. Поле Filename содержит имя файла программы, куда добавляется точка останова, поле Line number — номер строки программы, в которую добавляется точка останова. О назначении полей Condition (Условие) и Pass count (Число пропусков) будет сказано далее.
После щелчка на кнопке ОК точка останова добавляется в программу, и строка, в которой находится точка останова, помечается красной точкой и выделяется цветом (Рисунок 13.5).
Изменение характеристик точки останова
Изменение характеристик точки остановаПрограммист может изменить характеристики точки останова. Для этого надо из меню View выбрать команду Debug Windows, затем из меню следующего уровня — команду Breakpoints. В открывшемся диалоговом окне Breakpoint List (Рисунок 13.6) нужно щелкнуть правой кнопкой мыши в строке, содержащей информацию о нужной точке останова, и в появившемся контекстном меню выбрать команду Properties. В результате открывается диалоговое окно Source Breakpoint Properties, в котором можно изменить характеристики точки останова, например, изменить условие (содержимое поля Condition) остановки программы в данной точке. Используя это же контекстное меню, можно быстро перейти к инструкции, в которой находится точка останова; для этого надо выбрать команду Edit Source.
Классификация ошибок
Классификация ошибокОшибки, которые могут быть в программе, принято делить на три группы:
Ошибки времени выполнения, в Delphi они называются исключениями (exception), тоже, как правило, легко устранимы. Они обычно проявляются уже при первых запусках программы и во время тестирования.
При возникновении ошибки в программе, запущенной из Delphi, среда разработки прерывает работу программы, о чем свидетельствует заключенное в скобки слово Stopped в заголовке главного окна Delphi, и на экране появляется диалоговое окно, которое содержит сообщение об ошибке и информацию о типе (классе) ошибки. На Рисунок 13.1 приведен пример сообщения об ошибке, возникающей при попытке открыть несуществующий файл.
После возникновения ошибки программист может либо прервать выполнение программы, для этого надо из меню Run выбрать команду Program Reset, либо продолжить ее выполнение, например, по шагам (для этого из меню Run надо выбрать команду Step), наблюдая результат выполнения каждой инструкции.
Контроль значений переменных во время пошагового выполнения программы
Рисунок 13.9. Контроль значений переменных во время пошагового выполнения программы
В окне редактора кода стрелкой помечена инструкция, которая будет выполнена на следующем шаге выполнения программы (при нажатии клавиши
Существует еще один способ, позволяющий проверить значение переменной, не добавляя ее имя в список Watch List. Заключается он в следующем. После того как программа достигнет точки останова, в результате чего откроется окно редактора кода, нужно установить курсор мыши на имени переменной, значение которой надо проверить. В окне редактора кода появится окно подсказки, в котором будет выведено значение переменной (Рисунок 13.10).
Чтобы завершить процесс пошагового выполнения программы, нужно из меню Run выбрать команду Program Reset.
Контроль значения переменной без добавления имени в список Watch List
Рисунок 13.10. Контроль значения переменной без добавления имени в список Watch List
Обработка исключения типа EZeroDivide
Листинг 13.1. Обработка исключения типа EZeroDivideunit UsTry_;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Editl: TEdit; // напряжение
Edit2: TEdit; // сопротивление
Label5: TLabel; // результат расчета - ток
Button1: TButton; //кнопка Вычислить
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations )
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
u: real; // напряжение
r: real; // сопротивление
i: real; // ток
begin
Labels.Caption := ' '; try
// инструкции, которые могут вызвать исключение (ошибку)
u := StrToFloat(Edit1.Text);
r := StrToFloat(Edit2.Text);
i := u/r;
except // секция обработки исключений
onEZeroDivide do // деление на ноль
begin
ShowMessage('Сопротивление не может быть равно нулю!');
exit;
end;
on EConvertError do // ошибка преобразования строки в число
begin
ShowMessage('Напряжение и сопротивление должны быть ' +
'заданы числом. ' +#13+
'При записи дробного числа используйте запятую.';
exit;
end;
end;
Label5.Caption := FloatToStr(i) + ' A';
end;
end.
В приведенной программе исключения могут возникнуть при вычислении величины тока. Если пользователь задаст, что сопротивление равно нулю, то при выполнении инструкции i:=u/r возникает Исключение EZeroDivide.
Если неверно будет введено числовое значение, например, для разделения целой и дробной частей числа вместо запятой будет использована точка, то возникнет исключение типа EConvertError. Оба исключения обрабатываются одинаково: выводится сообщение, после чего процедура обработки события Onclick завершает свою работу.
Наблюдение значений переменных
Наблюдение значений переменныхВо время отладки, в частности, при выполнении программы по шагам, довольно часто бывает полезно знать, чему равно значение той или иной переменной. Отладчик позволяет наблюдать значения переменных программы.
Для того чтобы во время выполнения программы по шагам иметь возможность контролировать значение переменной, нужно добавить имя этой переменной в список наблюдаемых элементов (Watch List). Для этого надо из меню Run выбрать команду Add Watch (Добавить наблюдаемый элемент) и в поле Expression появившегося диалогового окна Watch Properties (Рисунок 13.7) ввести имя переменной.
Окно редактора кода после добавления точки останова
Рисунок 13.5. Окно редактора кода после добавления точки останова
Если для точки останова задано условие, то программа приостанавливает свою работу только в том случае, если выражение, находящееся в поле Condition, истинно (его значение равно TRUE).
Кроме условия для точки останова, можно задать количество пропусков данной точки. Если во время добавления в программу точки останова в поле Pass count (Число пропусков) диалогового окна Add Source Breakpoint записать отличное от нуля число, то программа приостановит свою работу в этой точке только после того, как инструкция, находящаяся в строке, помеченной точкой останова, будет выполнена указанное число раз.
Отладчик
ОтладчикИнтегрированная среда разработки Delphi предоставляет программисту мощное средство поиска и устранения ошибок в программе — отладчик. Отладчик позволяет выполнять трассировку программы, наблюдать значения переменных, контролировать выводимые программой данные.
Предотвращение и обработка ошибок
Предотвращение и обработка ошибокКак было сказано выше, в программе во время ее работы могут возникать ошибки, причиной которых, как правило, являются действия пользователя. Например, пользователь может ввести неверные данные или, что бывает довольно часто, удалить нужный программе файл.
Нарушение в работе программы называется исключением. Обработку исключений (ошибок) берет на себя автоматически добавляемый в выполняемую программу код, который обеспечивает, в том числе, вывод информационного сообщения. Вместе с тем Delphi дает возможность программе самой выполнить обработку исключения.
Инструкция обработки исключения в общем виде выглядит так:
try
// здесь инструкции, выполнение которых может вызвать исключение
except // начало секции обработки исключений
on ТипИсключения1 do Обработка1;
on ТипИсключения2 do Обработка2;
on ТипИсключенияJ do ОбработкаJ;
else
// здесь инструкции обработки остальных исключений
end;
где:
Результат добавления имени переменной в список Watch List
Рисунок 13.8. Результат добавления имени переменной в список Watch List
В результате в список Watch List, содержимое которого отражается в диалоговом окне Watch List (Рисунок 13.8), будет добавлен новый элемент. Так как переменные программы существуют (и, следовательно, доступны) только во время выполнения программы, то после имени переменной выводится сообщение: process not accessible (процесс недоступен).
В качестве примера на Рисунок 13.9 приведен вид окна редактора кода и окна Watch List во время пошагового выполнения программы сортировки массива.
Сообщение об ошибке при запуске программы из Windows
Рисунок 13.2. Сообщение об ошибке при запуске программы из Windows
С алгоритмическими ошибками дело обстоит иначе. Компиляция программы, в которой есть алгоритмическая ошибка, завершается успешно. При пробных запусках программа ведет себя нормально, однако при анализе результата выясняется, что он неверный. Для того чтобы устранить алгоритмическую ошибку," приходится анализировать алгоритм, вручную "прокручивать" его выполнение.
Сообщение об ошибке при запуске программы из Delphi
Рисунок 13.1. Сообщение об ошибке при запуске программы из Delphi
Если программа запущена из Windows, то при возникновении ошибки на экране также появляется сообщение об ошибке, но тип ошибки (исключения) в сообщении не указывается (Рисунок 13.2). После щелчка на кнопке ОК программа, в которой проявилась ошибка, продолжает (если сможет) работу.
Типичные исключения
Таблица 13.1. Типичные исключения| Тип исключения |
Возникает |
||
| EZeroDivide |
При выполнении операции деления, если делитель равен нулю |
||
| EConvertError |
При выполнении преобразования, если преобразуемая величина не может быть приведена к требуемому виду. Наиболее часто возникает при преобразовании строки символов в число |
||
| Тип исключения |
Возникает |
||
| EFilerError |
При обращении к файлу. Наиболее частой причиной является отсутствие требуемого файла или, в случае использования сменного диска, отсутствие диска в накопителе |
||
Точки останова программы
Точки останова программыПри отладке широко используется метод, который называют методом точек останова. Суть метода заключается в том, что программист помечает некоторые инструкции программы (ставит точки останова), при достижении которых программа приостанавливает свою работу, и программист может начать трассировку или проконтролировать значения переменных.
Трассировка программы
Трассировка программыВо время работы программы ее инструкции выполняются одна за другой со скоростью работы процессора компьютера. При этом программист не может определить, какая инструкция выполняется в данный момент, и, следовательно, определить, соответствует ли реальный порядок выполнения инструкций разработанному им алгоритму.
В случае неправильной работы программы необходимо видеть реальный порядок выполнения инструкций. Это можно сделать, выполнив трассировку программы. Трассировка — это процесс выполнения программы по шагам (step-by-step), инструкция за инструкцией. Во время трассировки программист дает команду: выполнить очередную инструкцию программы.
Delphi обеспечивает два режима трассировки: без захода в процедуру (Step over) и с заходом в процедуру (Trace into). Режим трассировки без захода в процедуру выполняет трассировку только главной процедуры, при этом трассировка подпрограмм не выполняется, вся подпрограмма выполняется за один шаг. В режиме трассировки с заходом в процедуру выполняется трассировка всей программы, т. е. по шагам выполняется не только главная программа, но и все подпрограммы.
Для того чтобы начать трассировку, необходимо из меню Run выбрать команду Step over или Trace into. В результате в окне редактора кода будет выделена первая инструкция программы. Для того чтобы выполнить выделенную инструкцию, необходимо из меню Run выбрать команду Step over (нажать клавишу
Активизировать и выполнить трассировку можно при помощи функциональной клавиатуры. Команде Step over соответствует клавиша
В любой момент времени можно завершить трассировку и продолжить выполнение программы в реальном темпе. Для этого надо из меню Run выбрать команду Run.
При необходимости выполнить трассировку части программы следует установить курсор на инструкцию программы, с которой надо начать трассировку, и из меню Run выбрать команду Run to cursor или нажать клавишу
Во время трассировки можно наблюдать не только порядок выполнения инструкций программы, но и значения переменных. О том, как это сделать, рассказывается в одном из следующих разделов.
Удаление точки останова
Удаление точки остановаДля того чтобы удалить точку останова, нужно в диалоговом окне Breakpoint List щелкнуть правой кнопкой мыши в строке, содержащей информацию о точке, которую надо удалить, и в появившемся контекстном меню выбрать команду Delete.
Можно также в окне редактора кода щелкнуть мышью на красной точке, помечающей строку, в которой находится точка останова.
Отладка программы в Delphi
Диалоговое окно Сноски
Рисунок 14.1. Диалоговое окно Сноски
В результате в документ будет вставлена сноска #, и в нижней части окна документа появится окно ввода текста сноски, в котором рядом со значком сноски следует ввести идентификатор помечаемого раздела справки (Рисунок 14.2).
В качестве идентификатора можно использовать аббревиатуру заголовка раздела справки или сквозной номер раздела, поставив перед ним, например, буквы Ti (Topic Identifier). Однако лучше, чтобы идентификатор раздела справки начинался с префикса IDH_. В этом случае во время компиляции RTF-файла будет проверена корректность ссылок: компилятор выведет список идентификаторов, которые перечислены в разделе [MAP] файла проекта (см. ниже), но которых нет в RTF-файле.
Диалоговое окно Tool Properties
Рисунок 14.5. Диалоговое окно Tool Properties
После запуска программы Microsoft Help Workshop на экране появляется главное окно программы.
Для того чтобы приступить к созданию справочной системы, нужно из меню File выбрать команду New, затем в открывшемся диалоговом окне тип создаваемого файла — Help Project. В результате этих действий открывается окно Project File Name. В этом окне сначала надо выбрать папку, где находится программа, для которой создается справочная система, и где уже должен находиться файл документа справочной системы (RTF-файл). Затем в поле Имя файла нужно ввести имя файла проекта справочной системы. После щелчка на кнопке Сохранить открывается окно проекта справочной системы .
Используя окно проекта справочной системы, можно добавить необходимые компоненты в проект, задать характеристики окна справочной системы, выполнить компиляцию проекта и пробный запуск созданной справочной системы.
Для навигации по справочной информации можно использовать вкладку
Рисунок 14.7. Для навигации по справочной информации можно использовать вкладку
Добавление закладки
Рисунок 14.8. Добавление закладки
Имя закладки должно отражать суть предполагаемого перехода к закладке, содержимое помечаемого фрагмента текста. В имени закладки пробел использовать нельзя. Вместо пробела можно поставить символ подчеркивания. Заголовки, оформленные стилем Заголовок, помечать закладками не надо. Таким образом, если в создаваемой справочной системе предполагаются переходы только к заголовкам разделов справочной информации, закладки допускается не вставлять. После этого можно приступить к расстановке гиперссылок.
Чтобы вставить в документ ссылку на закладку или заголовок, который находится в этом же документе, надо выделить фрагмент текста (слово или фразу), который должен быть гиперссылкой, из меню Вставка выбрать команду Гиперссылка, в появившемся окне Добавление гиперссылки (Рисунок 14.9) сначала щелкнуть на кнопке Связать с местом в этом документе, затем — выбрать закладку или заголовок, к которому должен быть выполнен переход.
Доступ к справочной информации
Доступ к справочной информацииДля того чтобы во время работы программы пользователь, нажав клавишу
Файл документа справочной информации
Файл документа справочной информацииФайл документа справочной системы представляет собой RTF-файл определенной структуры. Создать RTF-файл справочной информации можно, например, при помощи Microsoft Word. Сначала нужно набрать текст разделов справки, оформив заголовки разделов одним из стилей Заголовок, например Заголовок1. При этом текст каждого раздела должен находиться на отдельной странице документа (заканчиваться символом "разрыв страницы").
После того, как текст разделов будет набран, нужно, используя сноски (табл. 14.1), пометить заголовки разделов справочной информации (сноски используются компилятором справочной системы в процессе преобразования RTF-файла в HLP-файл, файл справки).
Характеристики окна справочной системы
Характеристики окна справочной системыЧтобы задать характеристики главного окна справочной системы, надо в окне проекта нажать кнопку Windows и в поле Create a window named открывшегося окна Create a window, ввести слово main.
В результате щелчка на ОК появляется окно Window Properties, в поле Title bar text вкладки General которого нужно ввести заголовок главного окна создаваемой справочной системы.
Используя вкладку Position диалогового окна Window Properties, можно задать положение и размер окна справочной системы (Рисунок 14.13). На вкладке Position находится кнопка Auto-Sizer, при нажатии которой открывается окно Help Window Auto-Sizer (Рисунок 14.14), размер и положение которого определяется содержимым полей вкладки Position. При помощи мыши можно
менять размер и положение этого окна. После нажатия кнопки ОК координаты и размер окна Help Window Auto-Sizer будут записаны в поля вкладки Position.
Используя вкладку Color , можно задать цвет фона области заголовка раздела справки (Nonscrolling area color) и области текста справки (Topic area color). Для этого надо нажать соответствующую кнопку Change и в стандартном окне Цвет выбрать нужный цвет.
Использование HTML Help Workshop
Использование HTML Help WorkshopПодготовить HTML-файл можно и при помощи HTML-редактора, входящего в состав HTML Help Workshop. Однако для этого надо знать хотя бы основы HTML — языка гипертекстовой разметки (далее приведены краткие сведения об HTML, которых достаточно для того, чтобы создать вполне приличную справочную систему).
Чтобы создать HTML-файл, надо запустить HTML Help Workshop, из меню File выбрать команду New | HTML File и в появившемся окне HTML Title задать название раздела справки, текст которого будет находиться в создаваемом файле.
После щелчка на кнопке ОК становится доступным окно HTML-редактора, в котором находится шаблон HTML-документа. В этом окне, после строки , можно набирать текст.
Использование редактора Microsoft Word
Использование редактора Microsoft WordСначала нужно набрать текст разделов справки (каждый раздел в отдельном файле). Заголовки разделов и подразделов нужно оформить одним из стилей Заголовок. Заголовки разделов, как правило, оформляют стилем Заголовок1, подразделов — Заголовок2.
Следующее, что надо сделать, — вставить закладки в те точки документа, в которые предполагаются переходы из других частей документа. Чтобы вставить в документ закладку, нужно установить курсор в точку текста, в которой должна быть закладка, из меню Вставка выбрать команду Закладка и в поле Имя закладки диалогового окна Закладка (Рисунок 14.8) ввести имя закладки.
Компиляция проекта
Компиляция проектаПосле того, как будет подготовлен файл проекта, можно выполнить компиляцию, щелкнув на находящейся в окне проекта кнопке Save and Compile. Однако первый раз компиляцию проекта справочной системы лучше выполнить выбором из меню File команды Compile, в результате выполнения которой открывается диалоговое окно Compile a Help File (Рисунок 14.19).
В этом окне следует установить флажок Automatically display Help file in WinHelp when done (Автоматически показывать созданную справочную систему по завершении компиляции), а затем нажать кнопку Compile. По завершении компиляции на экране появляется окно с информационным сообщением о результатах компиляции и, если компиляция выполнена успешно, окно созданной справочной системы. Созданный компилятором файл справочной системы (HLP-файл) будет помещен в ту папку, в которой находится файл проекта.
Компиляция
КомпиляцияКомпиляция — это процесс преобразования исходной справочной информации в файл справочной системы (СНМ-файл).
Исходной информацией для HTML Help компилятора являются:
Чтобы выполнить компиляцию, надо из меню File выбрать команду Compile, в появившемся диалоговом окне Create a compiled file установить переключатель Automatically display compiled help file when done
(после компиляции показать созданный файл справки) и щелкнуть на кнопке Compile. В результате этого будет создан файл справки, и на экране появится окно справочной системы, в котором будет выведена информация главного раздела.
Описание класса THhореn
Листинг 14.1. Описание класса THhореnTHhopen = class(Telecontrol)
private
FIntf: _DHhopen;
function GetControlInterface: _DHhopen;
protected
procedure CreateControl;
procedure InitControlData;
override;
public
function OpenHelp(const HelpFile: WideString;
const HelpSection: WideString): Integer;
procedure CloseHelp;
property ControlInterface:_DHhopen
read GetControlInterface;
property DefaultInterface:_DHhopen
read GetControlInterface;
published
property isHelpOpened: WordBool index 1
read GetWordBoolProp
write SetWordBoolProp
stored False;
end;
Класс тньореп предоставляет два метода: OpenHelp и CloseHelp.
Метод OpenHeip обеспечивает вывод справочной информации, метод close-Help — закрывает окно справочной системы.
У метода openHeip два параметра — имя файла справочной информации и имя раздела, содержимое которого будет выведено. В качестве имени раздела надо использовать имя HTML-файла, который применялся программой HTML Help Workshop в процессе создания СНМ-файла. Следует обратить внимание на то, что оба параметра должны быть строками widechar.
Следующая программа, ее диалоговое окно приведено на Рисунок 14.10, а текст — в листинге 14.2, демонстрирует использование ActiveX-компонента Hhopen для вывода справочной информации. Компонент нпореп добавляется в форму обычным образом. Так как во время работы программы он не отображается, то его можно поместить в любое место формы.
Использование компонента Hhopen unit ushh_;
Листинг 14.2. Использование компонента Hhopen unit ushh_;interface
uses
Windows, Messages, SysUtils,
Classes, Graphics, Controls,
Forms, Dialogs, OleCtrls, HHOPENLibJTLB, StdCtrls;
type
TForm1 = class(TForm) Label1: TLabel;
Editl: TEdit; // файл справки
Edit2: TEdit; //раздел справки (имя HTML-файла)
Button1: TButton; // кнопка Справка
Hhopen1: THhopen; // ActiveX-компонент Hhopen
Label2: TLabel;
Label3: TLabel;
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
// щелчок на кнопке Справка
procedure TForm1.ButtonlClick(Sender: TObject);
var
HelpFile : string; // файл справки
HelpTopic : string; // раздел справки
pwHelpFile : PWideChar;
// файл справки (указатель на строку WideChar)
pwHelpTopic : PWideChar;
// раздел (указатель на строку WideChar)
begin
HelpFile := Edit1.Text;
HelpTopic := Edit2.Text;
// выделить память для строк WideChar
GetMemfpwHelpFile, Length(HelpFile) * 2) ;
GetMemfpwHelpTopic, Length(HelpTopic)*2);
// преобразовать Ansi-строку в WideString-строку
pwHelpFile := StringToWideChar
(HelpFile,pwHelpFile,MAX_PATH*2)
pwHelpTopic := StringToWideChar(HelpTopic,pwHelpTopic,32);
// вывести справочную информацию
Form1.Hhopen1.OpenHelp(pwHelpFile,pwHelpTopic);
end;
end.
Вывод справочной информации выполняет процедура обработки события Onciic на кнопке Справка. Так как параметры метода OpenHelp должны быть строками widechar, то сначала выполняется преобразование ANSI-строки В строку WideChar.
Назначение числовых значений идентификаторам разделов справки
Назначение числовых значений идентификаторам разделов справкиЧтобы программа, использующая справочную систему, могла получить доступ к конкретному разделу справочной информации, нужно определить числовые значения для идентификаторов разделов. Чтобы это сделать, надо в окне проекта справочной системы нажать кнопку Map, в результате чего откроется диалоговое окно Map. В этом окне нужно нажать кнопку Add и в поле Topic ID, открывшегося диалогового окна Add Map Entry , ввести идентификатор раздела справки, а в поле Mapped numeric value — соответствующее идентификатору числовое значение. В поле Comment можно ввести комментарий — название раздела справочной системы, которому соответствует идентификатор.
Оформление ссылки на другой раздел справки
Рисунок 14.3. Оформление ссылки на другой раздел справки
Помимо ссылки, обеспечивающей переход к другому разделу справки, в документ можно вставить ссылку на комментарий — текст, появляющийся в всплывающем окне. Во время работы справочной системы ссылки на комментарии выделяются цветом и подчеркиваются пунктирной линией. При подготовке документа справочной системы комментарии, как и разделы справки, располагают на отдельной странице, однако текст комментария не должен иметь заголовка. Сноска # должна быть поставлена перед текстом комментария. Ссылка на комментарий оформляется следующим образом: сначала надо подчеркнуть одинарной линией слово, выбор которого должен вызвать появление комментария, затем сразу после этого слова вставить идентификатор комментария, оформив его как скрытый текст.
Окно программы Использование ActiveX
Рисунок 14.10. Окно программы Использование ActiveX
Основы HTML
Основы HTMLHTML-документ представляет собой текст, в который помимо обычного текста включены специальные последовательности символов — теги. Тег начинается символом < и заканчивается символом >. Теги используются программами отображения HTML-документов для форматирования текста в окне просмотра (сами теги не отображаются).
Большинство тегов парные. Например, пара тегов <Н2> н2> сообщает программе отображения HTML-документа, что текст, который находится между этими тегами, является заголовком второго уровня и должен быть отображен соответствующим стилем.
В табл. 14.2 представлен минимальный набор тегов, используя которые можно подготовить HTML-файл с целью дальнейшего его преобразования в СНМ-файл справочной системы.
Подготовка справочной информации
Подготовка справочной информацииПодготовить HTML-файл можно при помощи любого редактора текста. Наиболее быстро это можно сделать, если редактор позволяет сохранить набранный текст в HTML-формате. Если использовать обычный редактор, например, входящий в состав Windows Блокнот, то в этом случае придется изучить основы языка HTML.
В простейшем случае вся справочная информация может быть помещена в один-единственный HTML-файл. Однако если для навигации по справочной системе предполагается использовать вкладку Содержание, в которой будут перечислены разделы справочной информации, то в этом случае информацию каждого раздела нужно поместить в отдельный HTML-файл. В качестве примера на Рисунок 14.7 приведено окно справочной системы программы Квадратное уравнение. Во вкладке Содержание три пункта. Это значит, что исходная справочная информация была представлена тремя HTML-файлами.
Создание файла справки
Создание файла справкиПосле того как созданы HTML-файлы справочной информации, в которые помещены все необходимые для навигации по справочной системе гиперссылки, можно приступить к непосредственному созданию справочной системы.
После запуска HTML Help Workshop надо из меню File выбрать команду New/Project и в окне New Project — Destination ввести имя файла проекта справочной системы. После щелчка на кнопке Далее в этом и следующем окне, окно HTML Help Workshop
Первое, что надо сделать, — сформировать раздел [FILES], который должен включать имена HTML-файлов, содержащих справочную информацию по разделам. Чтобы добавить в раздел [FILES] имя файла, надо щелкнуть на кнопке Add/Remove topic files, затем, в появившемся диалоговом окне Topic Files — на кнопке Add и в появившемся стандартном диалоговом окне Открыть выбрать HTML-файл раздела справки. Если справочная информация распределена по нескольким файлам, то операцию добавления нужно повторить несколько раз. После того как в диалоговом окне Topic Files будут перечислены все необходимые для создания справочной информации HTML-файлы, нужно щелкнуть на кнопке ОК. В результате этих действий в файле проекта появится раздел [FILES], в котором будут перечислены HTML-файлы, используемые для создания справочной системы .
Следующее, что надо сделать, — задать главный (стартовый) раздел и заголовок окна, в котором будет выводиться справочная информация. Текст заголовка и имя файла главного раздела вводятся соответственно в поля Title и Default file вкладки General диалогового окна Options, которое появляется в результате щелчка на кнопке Change project options.
Если для навигации по справочной системе предполагается использовать вкладку Содержание, то надо создать файл контекста. Чтобы это сделать, нужно щелкнуть на вкладке Contents, подтвердить создание нового файла контекста и задать имя файла контекста, в качестве которого можно использовать имя проекта. В результате станет доступной вкладка Contents, в которую нужно ввести содержание — названия разделов справочной системы.
Содержание справочной системы принято изображать в виде иерархического списка. Элементы верхнего уровня соответствуют разделам, а подчиненные им элементы — подразделам и темам.
Чтобы во вкладку Contents добавить элемент, соответствующий разделу справочной системы, нужно щелкнуть на кнопке Insert a heading, в поле Entry title появившегося диалогового окна Table of Contents Entry ввести название раздела и щелкнуть на кнопке Add. На экране появится окно Path or URL. В поле HTML titles этого окна будут перечислены названия разделов (заголовки HTML-файлов) справочной информации, которая находится во включенных в проект файлах (имена этих файлов указаны в разделе [FILES] вкладки Project). Если вместо названия раздела справочной информации будет указано имя файла, то это значит, что в этом файле нет тега
Если нужно изменить значок, соответствующий добавленному разделу, то следует щелкнуть на кнопке Edit selection и, используя список Image index вкладки Advanced окна Table of Contents, выбрать нужный значок (обычно рядом с названием раздела или подраздела изображена книжка).
Подраздел добавляется точно так же, как и раздел, но после того как подраздел будет добавлен, нужно щелкнуть на кнопке Move selection right. В результате чего уровень заголовка понизится, т. е. раздел станет подразделом.
Элементы содержания, соответствующие темам справочной информации, добавляются аналогичным образом, но процесс начинается щелчком на кнопке Insert a page.
Иногда возникает необходимость изменить порядок следования элементов списка содержания или уровень иерархии элемента списка. Сделать это можно при помощи командных кнопок, на которых изображены стрелки. Кнопки Move selection up и Move selection down перемещают выделенный элемент списка, соответственно, вверх и вниз. Кнопка Move selection right перемещает выделенный элемент вправо, т. е. делает его подчиненным предыдущему элементу списка. Кнопка Move selection left выводит элемент из подчиненности предыдущему элементу.
Создание справочной системы
Создание справочной системыСоздание проекта справочной системы
После того как создан файл справочной информации системы (RTF-файл), можно приступить к созданию справочной системы (HLP-файла). Для этого удобно воспользоваться программой Microsoft Help Workshop, которая поставляется вместе с Delphi и находится в файле Hcw.exe.
Запустить Microsoft Help Workshop можно из Windows или из Delphi, выбрав из меню Tools команду Help Workshop.
Если в меню Tools команды Help Workshop нет, то надо из этого же меню выбрать команду Configure Tools и в открывшемся диалоговом окне Tool Options (Рисунок 14.4) щелкнуть на кнопке Add. В результате этого откроется диалоговое окно Tool Properties (Рисунок 14.5), в поле Title которого надо ввести название программы — Help workshop, а в поле Program — полное (т. е. с указанием пути) имя исполняемого файла программы Microsoft Help
Workshop— C:\Program Files\Borland\Delphi7\Help\Tools\HCW.exe. Для ввода имени файла можно воспользоваться кнопкой Browse.
Свойство HelpFile должно содержать имя файла справки
Рисунок 14.6. Свойство HelpFile должно содержать имя файла справки
Файл справочной системы приложения лучше поместить в ту папку, в которой находится файл исполняемой программы.
Для каждого компонента формы, например поля ввода, можно задать свой раздел справки. Раздел справки, который появляется, если фокус находится на компоненте, и пользователь нажимает клавишу
Если в диалоговом окне есть кнопка Справка, то справочная информация выводится по-другому — для кнопки создается процедура обработки события onclick, которая обращением к функции winheip запускает программу Windows Help (файл Winhlp32.exe). При вызове функции winheip в качестве параметров указываются: идентификатор окна, которое запрашивает справочную информацию; имя файла справочной системы; константа, определяющая действие, которое должна выполнить программа Windows Help и уточняющий параметр.
Примечание
Идентификатор окна — это свойство Handle формы приложения. Свойство Handle доступно только во время работы программы, поэтому в списке свойств в окне Object Inspector его нет.
Если необходимо вывести конкретный раздел справки, то в качестве параметра, определяющего действие, используется константа HELP_CONTEXT. Уточняющий параметр в этом случае задает раздел справки, который будет выведен на экран.
Ниже, в качестве примера, приведена процедура обработки события Onclick для кнопки Справка (Button4) диалогового окна программы решения квадратного уравнения.
// щелчок на кнопке Справка
procedure TForm1.Button4Click(Sender: TObject);
begin
winhelp(Form1.Handle,'sqroot.hip',HELP_CONTEXT,1); end;
HTML Help Workshop
Современные программы выводят справочную информацию в Internet-стиле — окно, которое используется для вывода справки, напоминает окно Internet Explorer. И это не удивительно, так как для вывода справочной информации используются компоненты, составляющие основу Microsoft Internet Explorer. Система отображения справочной информации является частью операционной системы, поэтому никакие дополнительные средства для вывода справочной информации не нужны.
Физически справочная информация находится в файлах с расширением chm. СНМ-файл — это так называемый компилированный HTML-документ. СНМ-файл получается путем компиляции (объединения) файлов, составляющих HTML-документ, который, как правило, состоит из нескольких HTML-файлов.
Процесс преобразования HTML-документа в справочную систему называют компиляцией. Исходной информацией для компилятора справочной системы являются HTML-файлы, файлы иллюстраций и файл проекта. В результате компиляции получается СНМ-файл, содержащий всю справочную информацию.
Наиболее просто создать справочную систему можно при помощи программы Microsoft HTML Help Workshop.
Чтобы создать справочную систему, нужно:
Сноски используемые для разметки RTFфайла
Таблица 14.1. Сноски, используемые для разметки RTF-файла| Сноска |
Назначение |
||
| # $ к |
Задает идентификатор раздела справки, который может использоваться в других разделах для перехода к помеченному этой сноской разделу Задает имя раздела, которое будет использоваться для идентификации раздела справки в списке поиска и в списке просмотренных тем во время использования справочной системы Задает список ключевых слов, при выборе которых из списка диалога поиска осуществляется переход к разделу справки, заголовок которой помечен этой сноской |
||
HTMLтеги
Таблица 14.2. HTML-теги| Тег |
Пояснение |
||
| Задает название HTML-документа. Программы отображения HTML-документов, как правило, выводят название документа в заголовке окна, в котором документ отображается. Если название не задано, то в заголовке окна будет выведено название файла | |||
| |
Параметр BACKGROUND задает фоновый рисунок, BGCOLOR — цвет фона, TEXT — цвет символов НТМ L-документа |
||
| |
Задает основной шрифт, который используется для отображения текста: FACE — название шрифта, SIZE — размер в относительных единицах. По умолчанию значение параметра SIZE равно 3. Размер шрифта заголовков (см. тег <н>) берется от размера, заданного параметром SIZE |
||
| <Н1> Н1> |
Определяет текст, находящийся между тегами <Н1> и Н1> как заголовок уровня 1. Пара тегов <Н2>Н2> определяет заголовок второго уровня, а пара <нзх/нЗ> — третьего |
||
| |
Конец строки. Текст, находящийся после этого тега, будет выведен с начала новой строки |
||
| <в> в> |
Текст, находящийся внутри этой пары тегов, будет выделен полужирным |
||
| |
Текст, находящийся внутри этой пары тегов, будет выделен курсивом |
||
| <А NAME=" За кладка "> А> |
Помечает фрагмент документа закладкой. Имя закладки задает параметр NAME. Это имя используется для перехода к закладке |
||
| <А HREF="Файл.htm#Закладка"> А> |
Выделяет фрагмент документа как гиперссылку, при выборе которой происходит перемещение к закладке, имя которой указано в параметре HREF |
||
| |
Выводит иллюстрацию, имя файла которой указано в параметре SRC |
||
|
- -- > |
Комментарий. Текст, находящийся между дефисами, на экран не выводится |
||
Работая с HTML-редактором в программе HTML Help Workshop, в процессе набора HTML-текста можно увидеть, как будет выглядеть набираемый текст. Для этого надо из меню View выбрать команду In Browser или щелкнуть на командной кнопке, на которой изображен стандартный значок Internet Explorer.
<ТITLE>Kвадратное уравнениеТIТLЕ>
<Н2>Квадратное уравне-ниеН2>
А>Квадратное уравнение задается в общем виде следующим образом:
AX2+BX+C=0
где : А, В и С — коэффициенты при неизвестном X .
Квадратное уравнение имеет
<А HREF="sqroot_02.htm#Корни_уравнения">корни
А>( решение ), если <А HREF="sqroot_О3.htm#Дискриминант">дискриминант А>уравнения больше или равен нулю. Если дискриминант уравнения меньше нуля, то уравнение не имеет решения.
CM.
ДискриминантА><ВК>
KopHH уравненияА><ВК>
Включение в проект файла справочной информации (RTFфайла)
Включение в проект файла справочной информации (RTF-файла)Для того чтобы добавить в проект файл справочной информации, нужно щелкнуть на кнопке Files и в открывшемся диалоговом окне Topic Files -кнопку Add. В результате откроется стандартное окно Открытие файла, используя которое следует выбрать нужный RTF-файл. В результате этих действий в окне проекта появится раздел [FILES], в котором будет указано имя файла справочной информации. Если справочная информация распределена по нескольким файлам, то операцию добавления файла нужно повторить.
Вставка в документ сноски помечающей заголовок раздела справки
Рисунок 14.2. Вставка в документ сноски, помечающей заголовок раздела справки
Как правило, разделы справки содержат ссылки на другие разделы. В окне справочной системы понятия (слова), выбор которых вызывает переход к другому разделу справки, выделяются отличным от основного текста справки цветом и подчеркиваются.
Во время подготовки текста справочной информации, слово-ссылку, выбор которого должен обеспечить переход к другому разделу справки, следует подчеркнуть двойной линией и сразу за этим словом, без пробела, поместить идентификатор раздела справки, к которому должен быть выполнен переход. Вставленный идентификатор необходимо оформить как скрытый текст.
На Рисунок 14.3 приведен вид окна редактора текста во время подготовки файла справочной информации для программы решения квадратного уравнения. Слово "дискриминант" помечено как ссылка на другой раздел справки (здесь предполагается, что раздел справки, в котором находятся сведения о дискриминанте, помечен сноской #, имеющей идентификатор IDH_2).
Выбор точки документа для перехода по ссылке
Рисунок 14.9. Выбор точки документа для перехода по ссылке
Если нужно вставить в документ ссылку на раздел справки, который находится в другом файле, то в диалоговом окне Добавление гиперссылки нужно щелкнуть на кнопке Файл и в появившемся стандартном окне выбрать имя нужного HTML-файла.
После того как в документ будут помещены все необходимые гиперссылки, документ нужно сохранить в HTML-формате.
Вывод справочной информации
Вывод справочной информацииЧтобы вывести справочную информацию, которая находится в СНМ-файле, нужно воспользоваться ActiveX-компонентом (элементом управления) ньореп, который входит в состав Windows и представляет собой специальную динамическую библиотеку (файл Hhopen.ocx).
Первое, что следует сделать, — установить компонент Hhopen на одну из вкладок палитры компонентов. Для этого надо из меню Component выбрать команду Import ActiveX Control. На экране появится окно Import ActiveX, в котором будут перечислены все зарегистрированные в реестре Windows компоненты. В окне Import ActiveX, в списке зарегистрированных компонентов, нужно выбрать строку hhopen OLE Control module и щелкнуть на кнопке Install. В результате этого на экране появится диалоговое окно Install, в котором программист может выбрать пакет (packege — пакет, библиотека компонентов), в который будет добавлен устанавливаемый компонент. Компоненты, добавляемые программистом, "по умолчанию" добавляются в пакет dciusr. В результате щелчка на кнопке ОК выбранный компонент добавляется в пакет, и на экране появляется окно Package и запрос подтверждения процесса перекомпиляции пакета . По завершении процесса компиляции на экране появится окно, информирующее о том, что компонент добавлен в пакет и зарегистрирован . Значок компонента ньореп будет добавлен на вкладку ActiveX. В процессе компиляции будет создан файл представления компонента -- модуль HHOPENLib_TLIB.pas, который содержит описание методов, свойств и событий компонента.
Модуль представления можно увидеть, загрузив его в редактор кода из каталога \Delphi 7\Lib. Пролистав в окне редактора кода модуль HHOPENLib_TLIB.pas, который представляет собой интерфейс для доступа к элементу управления, можно найти описание класса тньореп (листинг 14.1).
Отладка программы в Delphi
Диалоговое окно программы тестирования
Рисунок 15.1. Диалоговое окно программы тестирования
Файл теста
Файл тестаТест представляет собой последовательность вопросов, на которые испытуемый должен ответить путем выбора правильного ответа из нескольких предложенных вариантов.
Файл теста состоит из трех разделов:
Вот пример заголовка файла теста:
Сейчас Вам будут предложены вопросы о знаменитых памятниках и архитектурных сооружениях Санкт-Петербурга.
Вы должны из предложенных нескольких вариантов ответа выбрать правильный.
За заголовком следует раздел оценок, в котором приводятся названия оценочных уровней и количество баллов, необходимое для достижения этих уровней. Название уровня должно располагаться в одной строке. Вот пример раздела оценок:
Отлично
100
Хорошо
85
Удовлетворительно
60
Плохо
50
За разделом оценок следует раздел вопросов теста.
Каждый вопрос начинается текстом вопроса, за которым может следовать имя файла иллюстрации, размещаемое на отдельной строке и начинающееся символом \. Имя файла иллюстрации является признаком конца текста вопроса. Если к вопросу нет иллюстрации, то вместо имени файла ставится точка.
После вопроса следуют альтернативные ответы. Текст альтернативного ответа может занимать несколько строк. В строке, следующей за текстом ответа, располагается оценка (количество баллов) за выбор этого ответа. Если альтернативный ответ не является последним для текущего ответа, то перед оценкой ставится запятая, если последний — то точка.
Вот пример вопроса:
Какую формулу следует записать в ячейку В5, чтобы вычислить сумму выплаты?
\tab1.bmp
=сумма(В2-В4)
,0
=сумма(В2:В4)
,2
=В2+ВЗ+В4
.1
В приведенном вопросе второй и третий ответы помечены как правильные (оценка за их выбор не равна нулю). При этом видно, что выбор второго альтернативного ответа дает более весомый вклад в общую сумму баллов.
Ниже, в качестве примера, приведен текст файла вопросов для контроля знания истории памятников и архитектурных сооружений Санкт-Петербурга.
Сейчас Вам будут предложены вопросы о знаменитых памятниках и архитектурных сооружениях Санкт-Петербурга. Вы должны из предложенных нескольких вариантов ответа выбрать правильный.
Вы прекрасно знаете историю Санкт-Петербурга! 8
Вы много знаете о Санкт-Петербурге, но на некоторые вопросы ответили неверно . 7
Вы недостаточно хорошо знаете историю Санкт-Петербурга. 6
Вы, наверное, только начали знакомиться с историей Санкт-Петербурга? 5
Архитектор Исаакиевского собора:
\isaak.bmp
Доменико Трезини
,0
Огюст Монферран
,1
Карл Росси
.0
Александровская колонна воздвигнута как памятник, посвященный:
\aleks.bmp
деяниям императора Александра 1
,0
подвигу народа в Отечественной войне 1812 года
.1
Архитектор Зимнего дворца:
\herm.bmp
Бартоломео Растрелли
,1
Огюст Монферран
,0
Карл Росси
.0
Памятник русской военной славы собор Божией Матери Казанской (Казанский собор) построен по проекту русского зодчего:
A. Н. Воронихина
,1
И. Е. Старова
,0
B. И. Баженова .0
Остров, на котором находится Ботанический сад, основанный императором
Петром I, называется:
\bot.bmp
Заячий
,0
Медицинский
,0
Аптекарский
.1
Невский проспект получил свое название:
по имени реки, на берегах которой расположен Санкт-Петербург
, 0
по имени близко расположенной Александро-Невской лавры
,1
в память о знаменитом полководце Александре Невском
.0
Создатель скульптурных групп Аничкова моста. "Укрощение коня человеком":
\klodt.bmp
П. Клодт
,1
Э. Фальконе
.0
Скульптор знаменитого монумента "Медный всадник":
Э. Фальконе
,1
П. Клодт
.0
Файл теста может быть подготовлен в текстовом редакторе Notepad или Microsoft Word. В случае использования Microsoft Word при сохранении текста следует указать, что надо сохранить только текст. Для этого в диалоговом окне Сохранить в списке Тип файла следует выбрать вариант Только текст (*.txt).
Форма приложения
Форма приложенияНа Рисунок 15.2 приведен вид стартовой формы Forml во время разработки программы. Эта форма будет использоваться как для вывода вопросов теста и ввода ответов пользователя, так и для вывода начальной информации о тесте и результатов тестирования.
Поле метки Label3 предназначено для вывода текста вопроса, начальной информации о тесте и результатов тестирования.
Поля Label 1, Label2, Label3 и Label 4 предназначены для вывода текста альтернативных ответов, а переключатели RadioButtoni, RadioButton2, RadioButton3 и RadioButton4 — для выбора ответа.
Командная кнопка Buttonl предназначена для подтверждения выбора альтернативного ответа и перехода к следующему вопросу теста.
Следует обратить внимание на недоступный (невидимый) во время работы переключатель RadioButton5. Перед выводом очередного вопроса он программно устанавливается в выбранное положение, что обеспечивает сброс (установку в невыбранное состояние) переключателей выбора ответа (RadioButton1i, RadioButton2, RadioButton3 И RadioButton4).
На форме отсутствуют поля вывода
Рисунок 15.7. Форма приложения Тест, версия 2
На форме отсутствуют поля вывода альтернативных ответов и переключатели выбора правильного ответа. Они будут созданы во время работы программы.
Объявление массива компонентов ничем не отличается от объявления обычного массива — указывается имя массива, диапазон изменения индекса и тип элементов массива. Ниже приведено объявление массивов компонентов формы разрабатываемой программы:
answer: array[1..N_ANSWERS] of TLabel;
// альтернативные ответы selector:
array[1..N_ANSWERS+1] of TRadioButton;
// кнопки выбора ответа
Однако, для того чтобы компонент появился в форме, одного объявления недостаточно. Компонент — это объект Delphi, и его объявление — это только указатель на область памяти, который без наличия объекта ни на что не указывает. Создается компонент применением метода Create к указателю на компонент, в нашем случае — к элементу массива.
Например, инструкции
answer[1] := TLabel.Create(self) ;
answer[1].Parent := Form1;
создают компонент Label и помещают его в форму.
После создания компонента программа должна выполнить его настройку, т. е. ту работу, которую во время создания формы приложения выполняет программист при помощи Object Inspector. Под настройкой понимается присваивание начальных значений тем свойствам компонента, предопределенные значения которых не отвечают предъявляемым требованиям.
Если компонент должен реагировать на некоторое событие, то. нужно написать процедуру обработки этого события и поместить объявление созданной процедуры в объявление типа формы. Например, объявление типа формы разрабатываемой программы должно выглядеть так:
type
TForm1 = class(TForm)
Label5: TLabel; // поле вывода вопроса
Image1: TImage; // область вывода иллюстрации
Panel1: TPanel;
Button1: TButton; // кнопка Ok, Дальше, Завершить
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ButtonlClick(Sender: TObject);
procedure SelectorClick(Sender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
В отличие от других, сгенерированных Delphi, строк объявления типа, строка procedure SelectorClick(Sender: TObject) вставлена В объявление вручную.
Примечание
При создании процедуры обработки события для обычного компонента (компонента, который добавлен в форму во время разработки формы программы) Delphi автоматически генерирует заготовку процедуры обработки события и ее объявление. Программист должен написать только инструкции процедуры.
В случае создания процедуры обработки события для компонента, который создается динамически, программист должен полностью написать текст процедуры и поместить ее объявление в объявление формы.
После того как будет написана процедура обработки события, нужно связать эту процедуру с конкретным компонентом. Делается это путем присвоения имени процедуры обработки свойству, имя которого совпадает с именем обрабатываемого события. Например, инструкция
selector[1].OnClick : = SelectorClick;
задает процедуру обработки события Onclick для компонента selector [i]. В листинге 15.2 приведен полный текст программы Тест, версия 2.
Форма приложения Test Значения свойств стартовой формы приведены в табл 15 1
Рисунок 15.2. Форма приложения Test Значения свойств стартовой формы приведены в табл. 15.1.
Форма приложения
Форма приложенияГлавная (стартовая) форма игры Сапер 2002 приведена на Рисунок 15.11.
Следует обратить внимание, что размер
Рисунок 15.11. Главная форма программы Сапер 2002
Следует обратить внимание, что размер формы не соответствует размеру игрового поля. Нужный размер формы будет установлен во время работы программы. Делает это процедура обработки события OnFormActivate, которая на основе информации о размере игрового поля (количестве клеток по вертикали и горизонтали) и клеток устанавливает значение свойств ClientHeight и ClientWidth, определяющих размер клиентской области главного окна программы.
Основное окно программы содержит компонент MainMenu1, который представляет собой главное меню программы. Значок компонента MainMenu находится на вкладке Standard (Рисунок 15.12).
с операционной системой Windows, хорошо
Игра Сапер 2002Всем, кто работает с операционной системой Windows, хорошо знакома игра Сапер. В этом разделе рассматривается аналогичная программа — игра Сапер 2002.
Пример окна программы в конце игры, после того как игрок открыл клетку, в которой находится мина, приведен на Рисунок 15.8.
Игра
ИграВо время игры программа воспринимает нажатия кнопок мыши и, в соответствии с правилами игры, открывает клетки или ставит в клетки флажки.
Основную работу выполняет процедура обработки события onMouseDown (ее текст приведен в листинге 15.6). Сначала процедура преобразует координаты точки, в которой игрок нажал кнопку мыши, в координаты клетки игрового поля. Затем делает необходимые изменения в массиве Pole и, если нажата правая кнопка, рисует в клетке флажок. Если нажата левая кнопка в клетке, в которой нет мины, то эта клетка открывается, на экран выводится ее содержимое. Если нажата левая кнопка в клетке, в которой есть мина, то вызывается процедура showPole, которая показывает все мины, в том числе и те, которые игрок не успел найти.
Информация о программе
Информация о программеПри выборе из меню ? команды О программе на экране должно появиться одноименное окно (Рисунок 15.15).
Клетке игрового поля соответствует элемент массива
Рисунок 15.9. Клетке игрового поля соответствует элемент массива
В начале игры каждый элемент массива, соответствующий клеткам игрового поля, может содержать число от 0 до 9. Ноль соответствует пустой клетке, рядом с которой нет мин. Клеткам, в которых нет мин, но рядом с которыми мины есть, соответствуют числа от 1 до 8. Элементы массива, соответствующие клеткам, в которых находятся мины, имеют значение 9.
Элементы массива, соответствующие границе поля, содержат -3.
В качестве примера на Рисунок 15.10 изображен массив, соответствующий состоянию поля в начале игры.
Компонент MainMenu
Рисунок 15.12. Компонент MainMenu
Значок компонента MainMenu можно поместить в любое место формы, так как во время работы программы он не виден. Пункты меню появляются в верхней части формы в результате настройки меню. Для настройки меню используется редактор меню, который запускается двойным щелчком левой кнопкой мыши на значке компонента или выбором из контекстного меню компонента команды Menu Designer. В начале работы над новым меню, сразу после добавления компонента к форме, в окне редактора находится один-единственный прямоугольник — заготовка пункта меню. Чтобы превратить эту заготовку в меню, нужно в окне Object Inspector в поле Caption ввести название меню.
Если перед какой-либо буквой в названии меню ввести знак &, то во время работы программы можно будет активизировать этот пункт меню путем нажатия комбинации клавиши <Аlt> и клавиши, соответствующей символу, перед которым стоит знак &. В названии меню эта буква будет подчеркнута.
Чтобы добавить в главное меню элемент, необходимо в окне редактора меню выбрать последний (пустой) элемент меню и ввести название нового пункта.
Чтобы добавить в меню команду, необходимо выбрать пункт меню, в который нужно добавить команду, переместить указатель активного элемента меню в конец списка команд меню и ввести название команды.
На Рисунок 15.13 приведено окно редактора меню, в котором находится меню программы Сапер 2002.
После того как будет сформирована структура меню, нужно, используя окно Object Inspector, выполнить настройку элементов меню (выбрать настраиваемый пункт меню можно в окне формы приложения или из списка объектов в верхней части окна Object Inspector). Каждый элемент меню (пункты и команды) — это объект типа TMenuitem. Свойства объектов TMenuitem (табл. 15.7) определяют вид меню во время работы программы.
Программа тестирования
Листинг 15.1. Программа тестированияunit test1_;
interface
uses
SysUtils, WinTypes, WinProcs, Messages,
Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
type
TForm1 = class(TForm) // вопрос
Label3: TLabel; // альтернативные ответы
Label1: TLabel; Label2: TLabel;
Label3: TLabel; Label4: TLabel;
// переключатели выбора ответа
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;
RadioButton4: TRadioButton;
Image1: TImage; // область вывода иллюстрации
Button1: TButton; // кнопка Ok, Дальше
RadioButtonS: TRadioButton; // "служебная" кнопка
Panel1: ТPanel;
procedure FormActivate(Sender: TObject);
procedure ButtonlClick(Sender: TObject};
procedure RadioButtonClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1; // форма
implementation
const
N_LEV=4; // четыре уровня оценки
N_ANS=4; // четыре варианта ответов
var
f:TextFile;
fn:string; // имя файла вопросов
1evel:array[1..N_LEV] of integer;
// сумма, соответствующая уровню
mes:array[1.,N_LEV] of string;
// сообщение, соответствующее уровню
score:array[1..N_ANS] of integer;
// балл за выбор ответа
summa:integer; // набрано очков
vopros:integer; // номер текущего вопроса
n_otv:integer; // число вариантов ответа
otv:integer; // номер выбранного ответа
// вывод начальной информации о тесте
procedure info(var f:TextFile;l:TLabel);
var
s,buf:string; begin
buf:='';
repeat
readln(f,s);
if s[l] <>
'.'
then buf := buf + s+ ' ';
until s[l] ='.'; l.caption:=buf;
end;
// прочитать информацию об оценках за тест
Procedure GetLevel(var f:TextFile);
var
i:integer; buf:string;
begin // заполняем значения глобальных массивов
i:=l;
repeat
readln(f,buf);
if buf[1] <>
'.' then begin
mes[i]:=buf; readln(f,level[i]);
i:=i+1;
end;
until buf[1]='.';
end;
// масштабирование иллюстрации
Procedure ScaleImage(Imagel:TImage);
var
w,h:integer; // максимально допустимые размеры картинки
scaleX:real; // коэф. масштабирования по X
scaleY:real; // коэф. масштабирования по Y
scale:real; // общий коэф. масштабирования
begin
// вычислить максимально допустимые размеры картинки
w:=Form1.ClientWidth-10;
h:=Form1.ClientHeight
- Form1.Panel1.Height -5
- Form1.Label5.Top
- Form1.Label5.Height - 5;
if Form1.Label1.Caption <>
''
then h:=h-Form1.Label1.Height-5;
if Form1.Label2.Caption <>
''
then h:=h-Form1.Label2.Height-5;
if Forml.Label3.Caption <>
''
then h:=h-Form1.Label3.Height-5;
if Forml.Label4.Caption <>
"
then h:=h-Form1.Label4.Height-5; // определить масштаб
if w>
Imagel.Picture.Bitmap.Width
then scaleX:=l
else scaleX:=w/Imagel.Picture.Bitmap.Width;
if h>
Imagel.Picture.Bitmap.Height
then scaleY:=l
else scaleY:=h/Image1.Picture.Bitmap.Height;
if ScaleY
then scale:=scaleY
else scale:=scaleX; // здесь масштаб определен
Image1.Top:=Form1.Label5.Top+Form1.Labels.Height+5;
Image1.Width:=Round(Image1.Picture.Bitmap.Width* scale);
Image1.Height:=Round(Image1.Picture.Bitmap.Height*scale);
end;
// вывод вопроса на экран
Procedure VoprosToScr(var f:TextFile;frm:TForm1;var vopros:integer)
var
i:integer;
code:integer;
s,buf:string;
ifn:string; // файл иллюстрации
begin
vopros:=vopros+l ;
str(vopros:3,s) ;
frm. caption: = 'Вопрос' + s;
//выведем текст вопроса
buf:='';
repeat
readln(f, s) ;
if (s[l] <>
'.') and (s[l] <>
'\')
then buf:=buf+s+' ';
until (s[l] ='.') or (s[l] = '\');
frm. labels.caption:=buf;
if s[1] <>
'\'
then Form1.Image1.Tag:=0 else
// к вопросу есть иллюстрация
begin
Form1.Image1.Tag:=1;
if n:=copy(s,2,length(s));
try
Form1.Image1.Picture.LoadFromFile(ifn)
except
on E:EFOpenError do
frm.tag:=0; end; // try end;
// читаем варианты ответов
i:=l;
repeat
buf: = ";
repeat // читаем текст варианта ответа
readln(f,s);
if (s[1]<>
'. ') and (s[l] о ', ')
then buf:=buf+s+' ';
until (s[l]=',')or(s[1]='.');
// прочитан альтернативный ответ
val(s[2],score[i],code);
case i of
1: frm.Label1.caption:=buf;
2: frm.Label2.caption:=buf;
3: frm.Label3.caption:=buf;
4: frm.Label4.caption:=buf;
end;
until s[l]='.';
// здесь прочитана иллюстрация и альтернативные ответы
// текст вопроса уже выведен
if Forml.Image1.Tag =1 // есть иллюстрация к вопросу then
begin
Scalelmage(Form1.Image1);
Form1.Image1.Visible:=TRUE;
end;
// вывод альтернативных ответов
if Form1.Label1.Caption <>
" then begin
if Forml.Image1.Tag =1
then
frm.Label1.top:=frm.Imagel.Top+frm.Image1.Height+5
else
frm.Label1.top:=frm.Label5.Top+frm.Labels.Height+5;
frm.RadioButton1.top:=frm.Label1.top;
frm.Labell.visible:=TRUE;
frm.RadioButton1.visible:=TRUE;
end;
if Forml.Label2.Caption <>
" then begin
frm.Label2.top:=frm.Label1.top+ frm.Label1.height+5;
frm.RadioButton2.top:=frm.Label2.top;
frm.Label2.visible:=TRUE;
frm.RadioButton2.visible:=TRUE;
end;
if Forml.Label3.Caption <>
'' then begin
frm.Label3.top:=frm.Label2.top+ frm.Label2.height+5;
frm.RadioButtonS.top:=frm.Label3.top;
frm.Label3.visible:=TRUE;
frm.RadioButtonS.visible:=TRUE;
end;
if Forml.Label4.Caption <>
'' then begin
frm.Label4.top:=frm.Label3.top+ frm.Label3.height+5;
frm.RadioButton4. top:=frm.Label4.top;
frm.Label4.visible:=TRUE;
fm.Rad±o8utton4.vis:tble:=TRUE]
end;
end;
Procedure ResetForm(frm:TForml);
begin
// сделать невидимыми все метки и переключатели
frm.Label1.Visible:=FALSE;
f rm.Label1.caption: ='';
frm.Label1.width:=frm.ClientWidth-frm.Label1.left-5;
frm.RadioButtonl.Visible:=FALSE;
frm.Label2.Visible:=FALSE;
frm.Label2.caption:='';
frm.Label2.width:=frm.ClientWidth-frm.Label2.left-5;
frm.RadioButton2.Visible:=FALSE;
frm.Label3.Visible:=FALSE;
frm.Label3.caption:='';
frm.Label3.width:=frm.ClientWidth-frm.Label3.left-5;
frm.RadioButton3.Visible:=FALSE;
frm.Label4.Visible:=FALSE;
frm.Label4.caption:='';
frm.Label4.width:=frm.ClientWidth-frm.Label4.left-5;
f rm.RadioButton4.Visible:=FALSE;
frm.Label5.width:=frm.ClientWidth-frm.Labels.left-5;
frm. Image1.Visible:=FALSE;
end;
// определение достигнутого уровня
procedure Itog(summa:integer;frmrTForml);
var
i:integer; buf:string;
begin
buf: = ";
str(summa:5,buf);
buf:='Результаты тестирования'+chr(13)
+'Всего баллов: '+buf; i:=1;
while (summa < level[i]) and (i
i:=i+l;
buf:=buf+chr(13)+mes[ i ] ; frm.Labels.caption:=buf;
end;
{$R *.DFM}
procedure TForm1.FormActivate(Sender: TObject);
begin
ResetForm(Form1);
if ParamCount = 0 then
begin
Labels.caption:= 'He задан файл вопросов теста.';
Button1.caption: ='Ok' ;
Button1.tag:=2; Button1.Enabled:=TRUE
end
else begin
fn := ParamStr(1);
assignfile(f,fn);
{$I-} reset(f);
{I+}
if IOResult=0 then begin
Info(f,Label5);
// прочитать и вывести информацию о тесте
GetLevel(f);
// прочитать информацию об уровнях оценок
end;
end;
end;
procedure TForml.ButtonlClick(Sender: TObject);
begin
case Button1.tag of 0: begin
Buttonl.caption:='Дальше';
Buttonl.tag:=1;
RadioButtonS.Checked:=TRUE; // вывод первого вопроса
Buttonl.Enabled:=False; ResetForm(Form1);
VoprosToScr(f,Forml,vopros}
end;
1: begin // вывод остальных вопросов
summa:=summa+score[otv];
RadioButtonS.Checked:=TRUE;
Button1.Enabled:=False;
ResetForm(Form1);
if not eof(f)
then VoprosToScr(f,Forml,vopros) else
begin
suima: =summa+score [otv] ;
closefile(f);
Buttonl.caption:='Ok';
Form1.caption: ='Результат';
Button1.tag:=2;
Button1.Enabled:=TRUE;
Itog(summa,Forml);
end;
end;
2: begin // завершение работы
Forml.Close;
end;
end;
end;
procedure TForm1.RadioButtonClick(Sender: TObject);
begin
if sender = RadioButtonl
then otv:=l
else if sender = RadioButtonl
then otv:=2
else if sender = RadioButton3
then otv:=3 else otv:=4;
Buttonl.enabled:=TRUE;
end;
end.
После запуска программы и вывода на экран стартовой формы происходит событие onActivate. Процедура FormActivate сначала вызывает процедуру ResetForm, которая, присваивая значение False свойству visible, делает невидимыми поля вывода альтернативных ответов и переключатели. Аналогично делается невидимой область иллюстрации. Кроме того, процедура устанавливает максимально возможную ширину полей меток альтернативных ответов.
После очистки формы проверяется, указан ли при запуске программы параметр — имя тестового файла.
Если параметр не указан (значение paramCount в этом случае равно нулю), то присвоением значения свойству caption метки Label5 выводится сообщение: Не задан файл вопросов теста И свойству Tag кнопки Button1 присваивается значение 2(Button1.Tag:=2;)
Если параметр задан, то открывается файл теста.
Программа тестирования получает имя файла теста как результат функции Paramstr(l). Реализация программы предполагает, что если имя файла теста задано без указания пути доступа к нему, то файл теста и файлы с иллюстрациями находятся в том же каталоге, что и программа тестирования. Если путь доступа указан, то файлы с иллюстрациями должны находиться в том же каталоге, что и файл теста. Такой подход позволяет сгруппировать все файлы одного теста в одном каталоге.
Открывается файл теста обычным образом. Сначала обращением к процедуре AssignFile имя файла связывается с файловой переменной, а затем вызывается инструкция открытия файла для чтения.
После успешного открытия файла вызывается процедура info, которая считывает из файла информацию о тесте и выводит ее присваиванием прочитанного текста свойству Caption поля метки Labels.
Затем вызывается процедура GetLevei, которая считывает из файла теста информацию об уровнях оценки. Эта процедура заполняет массивы level И mes.
После вывода информационного сообщения программа ждет, когда пользователь нажмет кнопку OK (Button1).
Командная кнопка Buttoni используется для:
После вывода информации о тесте значение свойства Tag кнопки Button: равно нулю. Поэтому в результате первого щелчка на кнопке Buttoni выполняется та часть программы, которая обеспечивает вывод первого вопроса, замену находящегося на кнопке текста ОК на текст Дальше, и устанавливает в выбранное состояние переключатель RadioButton5, который закрыт панелью и поэтому не виден пользователю. Кроме того, присваиванием значения False свойству Enabled кнопка Buttoni делается недоступной, тем самым блокируется переход к следующему вопросу до тех пор, пока не будет выбран один из ответов. Значению свойства Button1.Tag присваивается единица, тем самым выполняется подготовка к обработке следующего щелчка кнопки Button1.
После выбора ответа и нажатия кнопки Дальше (Buttoni) (в этом случае значение свойства Button1.Tag равно единице) к набранной сумме баллов добавляется количество баллов за выбранный ответ. Затем, если не достигнут конец файла, вызывается процедура вывода очередного вопроса. Если достигнут конец файла, то сначала закрывается файл теста, изменяется текст на кнопке Buttoni и значение Button1. Tag, а затем посредством процедуры Itog выводятся результаты тестирования.
Если значение Button1.Tag равно двум, то применением метода close к форме Form1 закрывается окно программы, в результате чего программа завершает работу.
Вывод вопроса и альтернативных ответов выполняет процедура VoprosToScr. Сначала процедура увеличивает счетчик вопросов vopros и присвоением значения свойству Caption формы выводит номер текущего вопроса в заголовок окна. Затем процедура читает строки из файла теста до тех пор, пока первым символом очередной прочитанной строки не будет точка или "обратная наклонная черта".
После вывода текста вопроса делается проверка: какой символ используется в качестве признака конца вопроса. Если обратная наклонная черта, что свидетельствует о том, что к вопросу есть иллюстрация, то свойству Form1.image1.Tag присваивается единица и из прочитанной строки выделяется имя файла иллюстрации.
Загрузка иллюстрации осуществляется применением метода LoadFromFile к свойству image1. Picture. Однако после загрузки иллюстрация на экране не появляется, так как значение свойства Image1. visible равно False.
После считывания иллюстрации процедура считывает вопросы. После обработки последнего вопроса, если была загружена иллюстрация, вызовом процедуры ScaleImage вычисляется и устанавливается размер области иллюстрации. После этого установкой значения свойства Imagel.Top задается положение верхней границы области иллюстрации, а присваиванием значения True свойству image1. visible иллюстрация делается видимой.
Так как количество символов в тексте вопроса и число альтернативных ответов от вопроса к вопросу могут меняться, и, следовательно, на экране они могут занимать разное количество строк, то каждый раз перед выводом текста очередного ответа устанавливается значение свойства тор как расстояние от нижней границы предыдущего альтернативного ответа. Для поля вывода первого альтернативного ответа (Label) значение тор вычисляется от нижней границы поля вопроса (Labels) или, если к вопросу есть иллюстрация, от нижней границы поля иллюстрации (imagei).
Выбор ответа пользователь осуществляет щелчком одного из переключателей. После вывода вопроса ни один из переключателей, соответствующих альтернативному ответу, не является выбранным. Выбран только переключатель RadioButtonS, который находится за панелью Panel1 и поэтому не виден пользователю.
Для обработки события onclick переключателей RadioButton1,
RadioButton2, RadioButton3 и RadioButton4
В Программе используется общая процедура— TForm1.RadioButtonciick. Эта процедура получает в качестве параметра объект, на котором произошло событие. Сравнивая полученное значение с именами объектов-кнопок выбора, процедура присваивает значение глобальной переменной otv, которая используется процедурой VoprosToScr для увеличения набранной суммы баллов. Кроме того, процедура TForm1.RadioButtonClick делает доступной кнопку перехода к следующему вопросу (Buttonl), которая после вывода очередного вопроса недоступна.
Процедура Itog, сравнивая набранную сумму баллов summa со значением элементов массива level, определяет, какого уровня достиг испытуемый, и выводит соответствующее сообщение присвоением значения свойству
Label5.Caption.
создадим пять меток для вывода
Листинг 15.2. Программа тестирования, версия 2unit test2_;
interface
uses
SysUtils, WinTypes, WinProcs,
Messages, Classes, Graphics,
Controls, Forms, Dialogs,
StdCtrls, ExtCtrls;
type
TForm1 = class(TForm)
Label5: TLabel; // поле вывода вопроса
Image1: TImage; // область вывода иллюстрации
Panel1: ТPanel; Button1: TButton;
// кнопка Ok, Дальше, Завершить
procedure FormActivate(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure ButtonlClick(Sender: TObject);
procedure SelectorClick(Sender: TObject);
private
{ Private declarations } public
{ Public declarations } end;
var
Form1: TForm1; // форма
implementation
const
N_ANSWERS=4; // четыре варианта ответов
N_LEVEL=4; // четыре уровня оценки
var
// динамически создаваемые компоненты
answer: array[1..N_ANSWERS] of TLabel;
// альтернативные ответы
selector: array[1..N_ANSWERS+1] of TRadioButton;
// кнопки выбора ответа
f:TextFile;
fn:string; // имя файла вопросов
level:array[1..N_LEVEL] of integer;
// сумма, соответствующая уровню
mes:array[1..N_LEVEL] of string;
// сообщение, соответствующее уровню
score:array[1..N_ANSWERS] of integer;
// очки за выбор ответа
summa:integer; // набрано очков
vopros:integer; // номер текущего вопроса
n_otv:integer; // число вариантов ответа
otv:integer; // номер выбранного ответа
// установка формы в исходное состояние
Procedure ResetForm(frm:TForm1);
var
i:integer; begin
for i:=1 to N_ANSWERS do begin
answer[i].width:=frm.ClientWidth-answer[i].left-5;
answer[i].Visible:=FALSE; Selector[i].Visible:=FALSE;
end;
frm. Label5.width:=frm.ClientWidth-frm.Label5.left-5;
frm. Image1.Visible:=False;
end;
// определение достигнутого уровня
procedure Itog(suirana:integer;frm:TForm1);
var
i:integer; buf:string;
begin buf: = ";
str(summa:5,buf);
buf:='Результаты тестирования'+chr(13)
+'Всего баллов: '+buf; i:=1;
while (summa < level[i]) and (i
i:=i+l;
buf:=buf+chr(13)+mes[i];
frm.Labels.caption:=buf;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
i: integer; begin
// создадим пять меток для вывода вопроса и альтернативных ответов
for i:=l to N_ANSWERS do
begin
answer[i]:=TLabel.Create(self);
answer[i].Parent:=Forml;
answer[i].Left:=36;
answer[i].Wordwrap:=True;
end;
// создадим переключатели для выбора ответа
for i:=l to N_ANSWERS+1 do
begin
selector[i]:=TRadioButton.Create(self);
selector[i].Parent:=self;
selector[i].Caption:='';
selector[i].Width:=17;
selector[i].Left:=16;
selector[i].Visible:=False;
selector[i].Enabled:=True;
selector[i].OnClick:=SelectorClick;
end;
ResetForm(Forml);
end;
// вывод начальной информации о тесте
procedure info(var f:TextFile;l:TLabel);
var
s,buf:string; begin
buf:=''; repeat
readln(f,s);
if s[l]<>
'.'
then buf:=buf+s+' ';
until s[l] ='.';
Form1.Labels.caption:=buf;
end;
// прочитать информацию об оценках за тест
Procedure GetLevel(var f:TextFile);
var
i:integer; buf:string;
begin // заполняем значения глобальных массивов i:=1;
repeat
readln(f,buf);
if buf[1] <>
'.' then
begin mes[i]:=buf; readln(f,level[i]);
i:=i+1;
end;
until buf[1]='.';
end;
// масштабирование иллюстрации
Procedure ScalePicture;
var
w,h:integer; // максимально допустимые размеры картинки
scaleX:real; // коэф. масштабирования по X
scaleY:real; // коэф. масштабирования по Y
scale:real; // общий коэф. масштабирования
i:integer; begin
// вычислить максимально допустимые размеры картинки
w:=Form1.ClientWidth-Form1.Labels.Left;
h:=Form1.ClientHeight
- Form1.Panel1.Height -5
- Form1.Label5.Top
- Forml.Label5.Height - 5;
for i:=1 to N_ANSWERS do
if answer[i].Caption <>
''
then h:=h-answer[i].Height-5;
// здесь определена максимально допустимая величина иллюстрации
// определить масштаб
if w>
Form1.Image1.Picture.Width
then scaleX:=1
else scaleX:=w/Forml.Image1.Picture.Width;
if h>
Forml.Image1.Picture.Height
then scaleY:=1
else scaleY:=h/Form1.Image1.Picture.Height;
if ScaleYOcaleX
then scale:=scaleY
else scale:=scaleX; // здесь масштаб определен
Form1.Image1.Top:=
Form1.Label5.Top+Forml.LabelS.Height+5;
Form1.Image1.Left:=Form1.Label5.Left;
Form1.Image1.Width:=
Round(Form1.Image1.Picture.Width*scale);
Form1.Image1.Height:=
Round(Form1.Image1.Picture.Height*scale)
Form1.Label5.Visible:=TRUE;
end;
// вывод вопроса на экран
Procedure VoprosToScr(var f:TextFile;
frm:TForm1;var vopros:integer),
var
i:integer; code:integer; s,buf:string;
ifn:string; // файл иллюстрации
begin
vopros:=vopros+1 ;
str(vopros:3,s);
frm. caption: ='Вопрос' + s;
// выведем текст вопроса
buf: = ";
repeat
readln(f, s) ;
if (s[l] <>
'.') and (s[l] <>
'\')
then buf:=buf+s+' ';
until (s[l] ='.'} or (s[l] = '\');
frm.Labels.caption:=buf;
if s[l] = '\'
then // к вопросу есть иллюстрация
begin
frm.Image1.Tag:=1; ifn:=copy(s,2,length(s));
try
frm.Image1.Picture.LoadFromFile(ifn);
except
on E:EFOpenError do
frm.tag:=0; end //
try
end
else frm. Image1.Tag: =0;
// читаем варианты, ответов
for i:=1 to N_ANSWERS do begin
answer[i].caption:='';
answer[i].Width:=frm.ClientWidth-Form1.Label5.Left-5;
end; i:=l;
repeat
buf: = " ;
repeat // читаем текст варианта ответа
readln(f,s);
if (s[l]<>
'.') and (s[1] <>
',')
then buf:=buf+s+' ';
until (s[1]=',')or(s[l]='.');
// прочитан альтернативный ответ
val (s[2],score[i],code);
answer[i].caption:=buf;
i:=i+l;
until s [1] = '.'; // здесь прочитана иллюстрация и альтернативные ответы
if Form1.Image1.Tag =1 // есть иллюстрация к вопросу?
then begin ScalePicture;
Forml.Image1.Visible:=TRUE;
end;
// вывод альтернативных ответов
i:=1;
while (answer[i].caption <>
") and (i <= N_ANSWERS) do
begin
if i = 1 then
if frm.Image1.Tag =1
then answer[1].top:=frm.Image1.Top+frm.Image1.Height+5
else answer[i].top:=frm.Label5.Top+frm.Label5.Height+5
else
answer [i] . top:=answer [i-1] .
top+ answer [i-1] . height+5;
selector[i] . top:=answer [i] .
top; selectorfi] ,visible:=TRUE;
answer [i] . visible : =TRUE; i:=i+l;
end;
end;
{$R *.DFM}
procedure TForml . FormActivate ( Sender : TOb j ect ) ;
begin
ResetForm ( Forml ) ;
if ParamCount = 0 then begin
Label3 . font . color : =clRed;
Label5. caption: = 'He задан файл вопросов теста.1;
Buttonl . caption : = ' Ok ' ; Buttonl.tag:=2;
Buttonl . Enabled : =TRUE
end else
begin
fn:=ParamStr (1) ;
assignf ile ( f , fn) ;
{$!-} reset (f) ;
if IOResult=0 then
begin
Inf <>
(f, Label3) ;
GetLevel(f) ;
end;
summa:=0;
end;
end;
procedure TForm1. ButtonlClick (Sender: TObject)
begin
case Button1.tag of
0: begin
Button1.caption:='Дальше';
Buttonl.tag:=1;
Selector[N_ANSWERS+1].Checked:=TRUE; // вывод первого вопроса
Buttonl.Enabled:=False;
ResetForm(Forml);
VoprosToScr(f,Forml,vopros)
end;
1: begin // вывод остальных вопросов
summa:=summa+score[otv];
Selector[N_ANSWERS+1].Checked:=TRUE;
Button1.Enabled:=False; ResetForm(Form1);
if not eof(f)
then VoprosToScr(f,Forml,vopros) else
begin
closefile(f);
Button1.caption:='Ok';
Forml.сарtiоn:='Результат';
Buttonl.tag:=2; Buttonl.Enabled:=TRUE;
Itog(summa,Form1);
end;
end;
2: begin // завершение работы
Form1.Close;
end;
end;
end;
// щелчок на кнопке выбора ответа
procedure TForml.SelectorClick(Sender: TObject);
var
i: integer;
begin
while selector[i].Checked = FALSE do
i:=i+l;
otv:=i;
Buttonl.enabled:=TRUE;
end;
end.
По сравнению с первым вариантом программа Тест, версия 2 обладает существенным преимуществом. Для ее модернизации, например для увеличения количества альтернативных ответов, достаточно изменить только описание именованной константы N_ANSWERS.
Процедура NewGame
Листинг 15.3. Процедура NewGame// новая игра — генерирует новое поле
procedure NewGame ();
row,col : integer; // координаты клетки (индексы массива)
n : integer; // количество поставленных мин
k : integer; // кол-во мин в соседних клетках
begin
// Очистим эл-ты массива, соответствующие клеткам
// игрового поля
for row :=1 to MR do
for col :=1 to MC do Pole[row,col] := 0;
// расставим мины
Randomize О; // инициализация ГСЧ
n := 0; // кол-во мин
repeat
row := Random(MR) + 1;
col := Random(MC) + 1;
if (Pole[row,col] <>
9) then begin
Pole[row,col] := 9; n := n+1;
end;
until (n = NM);
// для каждой клетки вычислим // кол-во мин в соседних клетках
for row := 1 to MR do
for col := 1 to MC do
if (Pole[row,col] <>
9) then
begin k :=0 ;
if Pole[row-l,col-l] = 9 then k = k + 1;
if Pole[row-1,col] =' 9 then k = k + 1;
if Pole[row-1,col+1] = 9 then k = k + 1;
if Pole[row,col-1] = 9 then k = k + 1;
if Pole[row,col+1] = 9 then k = k + 1;
if Pole[row+1,col-1] = 9 then k = k + 1;
if Pole[row+1,col] = 9 then k = k + 1;
if Pole[row+l,col+l] = 9 then k := k + 1;
Pole[row,col] := k;
end;
status := 0; // начало игры
nMin := 0; // нет обнаруженных мин
nFlag := 0; // нет поставленных флагов
end;
После того как процедура NewGame расставит мины, процедура showPoie (ее текст приведен в листинге 15.4) выводит изображение игрового поля.
Процедура ShowPole
Листинг 15.4. Процедура ShowPole// Показывает поле
Procedure ShowPoie(Canvas : TCanvas; status : integer);
var
row,col : integer;
begin
for row := 1 to MR do
for col := 1 to MC do
Kletka(Canvas, row, col, status);
end;
Процедура showPoie выводит изображение поля последовательно, клетка за клеткой. Вывод изображения отдельной клетки выполняет процедура Kletka, ее текст приведен в листинге 15.5. Процедура Kletka используется для вывода изображения поля в начале игры, во время игры и в ее конце. В начале игры (значение параметра status = 0) процедура выводит только контур клетки, во время игры — количество мин в соседних клетках или флажок, а в конце отображает исходное состояние клетки и действия пользователя. Информацию о фазе игры процедура Kletka получает через параметр status.
Процедура Kletka
Листинг 15.5. Процедура Kletka// выводит на экран изображение клетки
Procedure Kletka(Canvas : TCanvas;
row, col, status : integer);
var
x,y : integer; // координаты области вывода
begin
x := (col-1)* W + I; у := (row-1)* H + 1;
if status = 0 then begin
Canvas.Brush.Color := clLtGray;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
exit;
end;
if Pole[row,col] < 100 then
begin
Canvas.Brush.Color := clLtGray; // неоткрытые — серые
Canvas.Rectangle(x-1,y-l,x+W,y+H);
// если игра завершена (status = 2), то показать мины
if (status = 2) and (Pole[row,col] = 9)
then Mina(Canvas, x, y) ; exit; end;
// открытая клетка
Canvas.Brush.Color := clWhite; // открытые белые
Canvas.Rectangle(x-1,y-l,x+W,y+H);
if (Pole[row,col] = 100)
then exit; // клетка открыта, но она пустая
if (Pole[row,col] >
= 101)
and (Pole[row,col] <= 108)
then begin // в соседних клетках есть мины
Canvas.Font.Size := 14;
Canvas.Font.Color := clBlue;
Canvas.TextOut(x+3,y+2,IntToStr(Pole[row,col] -100));
exit;
end;
if (Pole[row,col] >
= 200)
then Flag(Canvas, x, y);
if (Pole[row,col] = 109)
then // на этой мине подорвались!
begin
Canvas.Brush.Color := clRed;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
end;
if ((Pole[row,col] mod 10) = 9)
and (status = 2) then
Mina(Canvas, x, y);
end;
Обработка события OnMouseDown на поверхности игрового поля
Листинг 15.6. Обработка события OnMouseDown на поверхности игрового поля// нажатие кнопки мыши на игровом поле
procedure TForm1.Form1MouseDown(Sender: TObject;
Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
row, col : integer;
begin
if status = 2 // игра завершена
then exit;
if status = 0 then // первый щелчок
status := 1;
// преобразуем координаты мыши в индексы
// клетки поля
row := Trunc(y/H) + 1;
col := Trunc(x/W) + 1;
if Button = mbLeft then
begin
if Pole[row,col] = 9 then
begin // открыта клетка, в которой есть мина
Pole[row,col] := Pole[row,col] + 100;
status := 2; // игра закончена
ShowPole(Form1.Canvas, status);
end else
if Pole[row,col] < 9 then
Open(row,col);
end else
if Button = mbRight then
if Pole[row,col] >
200 then begin
// уберем флаг и закроем клетку
nFlag := nFlag — 1;
Pole[row,col] := Pole[row,col]-200;
// уберем флаг
x := (col-D* W + 1; у := (row-1)* H + 1;
Canvas.Brush.Color := clLtGray;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
end else
begin // поставить в клетку флаг
nFlag := nFlag + 1; if Pole[row,col] = 9
then nMin := nMin + 1;
Pole[row,col]:=Pole[row,col]+200;
// поставили флаг
if (nMin = NM) and (nFlag = NM) then begin
status := 2;
// игра закончена
ShowPole(Form1.Canvas, status);
end
else Kletka(Form1.Canvas, row, col, status);
end;
end;
Вывод справочной информации
Листинг 15.7. Вывод справочной информации// выбор из меню ? команды Справка
procedure TForm1.N3Click(Sender: TObject);
HelpFile : string; // файл справки
HelpTopic : string; // раздел справки
pwHelpFile : PWideChar;
// файл справки (указатель на строку WideChar)
pwHelpTopic : PWideChar;
// раздел (указатель на строку WideChar)
begin
HelpFile := 'saper.chm';
HelpTopic := 'saper_02.htm';
// выделить память для
WideChar-строк GetMem(pwHelpFile, Length(HelpFile) * 2);
GetMem(pwHelpTopic, Length(HelpTopic)*2);
// преобразовать ANSI-строку в WideString-строку
pwHelpFile := StringToWideChar(HelpFile,
pwHelpFile, MAX_PATH*2);
pwHelpTopic := StringToWideChar(HelpTopic,
pwHelpTopic,32);
// вывести справочную информацию
Form1.Hhopen1.OpenHelp(pwHelpFile,
pwHelpTopic);
end;
Вывод окна О программе
Листинг 15.8. Вывод окна О программе// выбор из меню ? команды О программе
procedure TForm1.N4Click(Sender: TObject);
begin
AboutForm.Top :=
Trunc(Forml.Top + Forml.Height/2 - AboutForm.Height/2);
AboutForm.Left :=
Trunc (Form1.Left +Form1 .Width/2
- AboutForm. Width/2 }; AboutForm. ShowModal;
end;
Примечание
Модальный диалог перехватывает все события, адресованные другим окнам приложения. Пока модальный диалог находится на экране, другие окна приложения не реагируют на действия пользователя. Для продолжения работы с приложением нужно закрыть модальный диалог. В большинстве программ в том числе и в Delphi, информация о программе реализована как модальный диалог.
Если не предпринимать никаких усилий, то окно О программе появится в той точке экрана, в которой находилась форма во время ее разработки Вместе с тем, можно "привязать" это окно к главному окну программы так. чтобы оно появлялось в центре главного окна. Привязка осуществляется на основании информации о текущем положении главного окна программы (свойства тор и Left) и размере окна О программе. Окно О программе должно быть удалено с экрана в результате щелчка на кнопке Ok. Процедура обработки этого события приведена ниже.
procedure TAboutForm.ButtonlClick (Sender: TObject) ;
begin
ModalResult := mrOk;
end;
Модуль главного окна программы Сапер
Листинг 15.9. Модуль главного окна программы Сапер 2002unit saper_1;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms, Dialogs,
Menus, StdCtrls, OleCtrls, HHOPENLib_TLB;
type
TForm1 = class(TForm)
MainMenu1: TMainMenu;
N1: TMenuItem;
N2: TMenuItem;
N3: TMenuItem;
N4: TMenuItem;
Hhopen1: THhopen;
procedure Form1Create(Sender: TObject);
procedure Form1Paint(Sender: TObject);
procedure Form1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
procedure N1Click(Sender: TObject);
procedure N4Click(Sender: TObject);
procedure N3Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
uses saper_2;
{$R *.DFM}
const
MR = 10; // кол-во клеток по вертикали
MC = 10; // кол-во клеток по горизонтали
NM = 10; // кол-во мин
W = 40; // ширина клетки поля
H = 40; // высота клетки поля
var
Pole: array[0..MR+1, 0.. MC+1] of integer; // минное поле
// значение элемента массива:
// 0..8 - количество мин в соседних клетках
// 9 - в клетке мина
// 100..109 - клетка открыта
// 200..209 - в клетку поставлен флаг
nMin : integer; // кол-во найденных мин
nFlag : integer; // кол-во поставленных флагов
status : integer; // 0 - начало игры; 1- игра; 2 -результат
Procedure NewGame();
forward;
// генерирует новое поле
Procedure ShowPole(Canvas : TCanvas; status : integer);
forward;// Показывает поле
Procedure Kletka(Canvas : TCanvas; row, col, status : integer);
forward; // выводит содержимое клетки
Procedure Open( row, col : integer);
forward;// открывает текущую и все соседние клетки, в которых нет мин
Procedure Mina(Canvas : TCanvas; x, y : integer);
forward; // Рисует мину
Procedure Flag( Canvas : TCanvas; x, y : integer);
forward;// Рисует флаг
// выводит на экран содержимое клетки
Procedure Kletka(Canvas : TCanvas; row, col, status : integer);
var
x,y : integer; // координаты области вывода
begin
x := (col-1)* W + 1;
y := (row-1)* H + 1;
if status = 0 then
begin
Canvas.Brush.Color := clLtGray;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
exit;
end;
if Pole[row,col] < 100 then
begin
Canvas.Brush.Color := clLtGray; // не открытые - серые
Canvas.Rectangle(x-1,y-1,x+W,y+H);
// если игра завершена (status = 2), то показать мины
if (status = 2) and (Pole[row,col] = 9)
then Mina(Canvas, x, y);
exit;
end;
// открываем клетку
Canvas.Brush.Color := clWhite; // открытые белые
Canvas.Rectangle(x-1,y-1,x+W,y+H);
if ( Pole[row,col] = 100 )
then exit; // клетка открыта, но она пустая
if ( Pole[row,col] >
= 101) and (Pole[row,col] <= 108 ) then
begin
Canvas.Font.Size := 14;
Canvas.Font.Color := clBlue;
Canvas.TextOut(x+3,y+2,IntToStr(Pole[row,col] -100 ));
exit;
end;
if ( Pole[row,col] >
= 200 ) then
Flag(Canvas, x, y);
if (Pole[row,col] = 109 ) then // на этой мине подорвались!
begin
Canvas.Brush.Color := clRed;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
end;
if ( (Pole[row,col] mod 10) = 9) and (status = 2) then
Mina(Canvas, x, y);
end;
// Показывает поле
Procedure ShowPole(Canvas : TCanvas; status : integer);
var
row,col : integer;
begin
for row := 1 to MR do
for col := 1 to MC do
Kletka(Canvas, row, col, status);
end;
// рекурсивная функция открывает текущую и все соседние
// клетки, в которых нет мин
Procedure Open( row, col : integer);
begin
if Pole[row,col] = 0 then
begin
Pole[row,col] := 100;
Kletka(Form1.Canvas, row,col, 1);
Open(row,col-1);
Open(row-1,col);
Open(row,col+1);
Open(row+1,col);
//примыкающие диагонально
Open(row-1,col-1);
Open(row-1,col+1);
Open(row+1,col-1);
Open(row+1,col+1);
end
else
if (Pole[row,col] < 100) and ( Pole[row,col] <>
-3 ) then
begin
Pole[row,col] := Pole[row,col] + 100;
Kletka(Form1.Canvas, row, col, 1);
end;
end;
// новая игра - генерирует новое поле
procedure NewGame();
var
row,col : integer; // координаты клетки
n : integer; // количество поставленных мин
k : integer; // кол-во мин в соседних клетках
begin
// Очистим эл-ты массива, соответствующие клеткам
// игрового поля.
for row :=1 to MR do
for col :=1 to MC do
Pole[row,col] := 0;
// расставим мины
Randomize();
// инициализация ГСЧ
n := 0; // кол-во мин
repeat
row := Random(MR) + 1;
col := Random(MC) + 1;
if ( Pole[row,col] <>
9) then
begin
Pole[row,col] := 9;
n := n+1;
end;
until ( n = NM );
// для каждой клетки вычислим
// кол-во мин в соседних клетках
for row := 1 to MR do
for col := 1 to MC do
if ( Pole[row,col] <>
9 ) then
begin
k :=0 ;
if Pole[row-1,col-1] = 9 then k := k + 1;
if Pole[row-1,col] = 9 then k := k + 1;
if Pole[row-1,col+1] = 9 then k := k + 1;
if Pole[row,col-1] = 9 then k := k + 1;
if Pole[row,col+1] = 9 then k := k + 1;
if Pole[row+1,col-1] = 9 then k := k + 1;
if Pole[row+1,col] = 9 then k := k + 1;
if Pole[row+1,col+1] = 9 then k := k + 1;
Pole[row,col] := k;
end;
status := 0; // начало игры
nMin := 0; // нет обнаруженных мин
nFlag := 0; // нет флагов
end;
// Рисует мину
Procedure Mina(Canvas : TCanvas; x, y : integer);
begin
with Canvas do
begin
Brush.Color := clGreen;
Pen.Color := clBlack;
Rectangle(x+16,y+26,x+24,y+30);
Rectangle(x+8,y+30,x+16,y+34);
Rectangle(x+24,y+30,x+32,y+34);
Pie(x+6,y+28,x+34,y+44,x+34,y+36,x+6,y+36);
MoveTo(x+12,y+32);
LineTo(x+26,y+32);
MoveTo(x+8,y+36);
LineTo(x+32,y+36);
MoveTo(x+20,y+22);
LineTo(x+20,y+26);
MoveTo(x+8, y+30);
LineTo(x+6,y+28);
MoveTo(x+32,y+30);
LineTo(x+34,y+28);
end;
end;
// Рисует флаг
Procedure Flag( Canvas : TCanvas; x, y : integer);
var
p : array [0..3] of TPoint; // координаты флажка и нижней точки древка
m : array [0..4] of TPoint; // буква М
begin
// зададим координаты точек флажка
p[0].x:=x+4; p[0].y:=y+4;
p[1].x:=x+30; p[1].y:=y+12;
p[2].x:=x+4; p[2].y:=y+20;
p[3].x:=x+4; p[3].y:=y+36; // нижняя точка древка
m[0].x:=x+8; m[0].y:=y+14;
m[1].x:=x+8; m[1].y:=y+8;
m[2].x:=x+10; m[2].y:=y+10;
m[3].x:=x+12; m[3].y:=y+8;
m[4].x:=x+12; m[4].y:=y+14;
with Canvas do
begin
// установим цвет кисти и карандаша
Brush.Color := clRed;
Pen.Color := clRed;
Polygon(p);
// флажок
// древко
Pen.Color := clBlack;
MoveTo(p[0].x, p[0].y);
LineTo(p[3].x, p[3].y);
// буква М
Pen.Color := clWhite;
Polyline(m);
Pen.Color := clBlack;
end;
end;
// выбор из меню ? команды О программе
procedure TForm1.N4Click(Sender: TObject);
begin
AboutForm.Top := Trunc(Form1.Top + Form1.Height/2 - AboutForm.Height/2);
AboutForm.Left := Trunc(Form1.Left +Form1.Width/2 - AboutForm.Width/2);
AboutForm.ShowModal;
end;
procedure TForm1.Form1Create(Sender: TObject);
var
row,col : integer;
begin
// В неотображаемые эл-ты массива, которые соответствуют
// клеткам по границе игрового поля запишем число -3.
// Это значение используется функцией Open для завершения
// рекурсивного процесса открытия соседних пустых клеток.
for row :=0 to MR+1 do
for col :=0 to MC+1 do
Pole[row,col] := -3;
NewGame();
// "разбросать" мины
Form1.ClientHeight := H*MR + 1;
Form1.ClientWidth := W*MC + 1;
end;
// нажатие кнопки мыши на игровом поле
procedure TForm1.Form1MouseDown(Sender: TObject; Button: TMouseButton;
Shift: TShiftState; X, Y: Integer);
var
row, col : integer;
begin
if status = 2 // игра завершена
then exit;
if status = 0 then // первый щелчок
status := 1;
// преобразуем координаты мыши в индексы
// клетки поля
row := Trunc(y/H) + 1;
col := Trunc(x/W) + 1;
if Button = mbLeft then
begin
if Pole[row,col] = 9 then
begin // открыта клетка, в которой есть мина
Pole[row,col] := Pole[row,col] + 100;
status := 2; // игра закончена
ShowPole(Form1.Canvas, status);
end
else if Pole[row,col] < 9 then
Open(row,col);
end
else
if Button = mbRight then
if Pole[row,col] >
200 then
begin
// уберем флаг и закроем клетку
nFlag := nFlag - 1;
Pole[row,col] := Pole[row,col] - 200; // уберем флаг
x := (col-1)* W + 1;
y := (row-1)* H + 1;
Canvas.Brush.Color := clLtGray;
Canvas.Rectangle(x-1,y-1,x+W,y+H);
end
else
begin // поставить в клетку флаг
nFlag := nFlag + 1;
if Pole[row,col] = 9
then nMin := nMin + 1;
Pole[row,col] := Pole[row,col]+ 200; // поставили флаг
if (nMin = NM) and (nFlag = NM) then
begin
status := 2; // игра закончена
ShowPole(Form1.Canvas, status);
end
else Kletka(Form1.Canvas, row, col, status);
end;
end;
// Выбор меню Новая игра
procedure TForm1.N1Click(Sender: TObject);
begin
NewGame();
ShowPole(Form1.Canvas,status);
end;
// выбор из меню ? команды Справка
procedure TForm1.N3Click(Sender: TObject);
var
HelpFile : string; // файл справки
HelpTopic : string; // раздел справки
pwHelpFile : PWideChar; // файл справки (указатель на WideChar строку)
pwHelpTopic : PWideChar; // раздел (указатель на WideChar строку)
begin
HelpFile := 'saper.chm';
HelpTopic := 'saper_02.htm';
// выделить память для WideChar строк
GetMem(pwHelpFile, Length(HelpFile) * 2);
GetMem(pwHelpTopic, Length(HelpTopic)*2);
// преобразовать Ansi строку в WideString строку
pwHelpFile := StringToWideChar(HelpFile,pwHelpFile,MAX_PATH*2);
pwHelpTopic := StringToWideChar(HelpTopic,pwHelpTopic,32);
// вывести справочную информацию
Form1.Hhopen1.OpenHelp(pwHelpFile,pwHelpTopic);
end;
procedure TForm1.Form1Paint(Sender: TObject);
begin
ShowPole(Form1.Canvas, status);
end;
end.
Полный текст программы Сапер 2002
Полный текст программы Сапер 2002 представлен ниже. В листинге 15.9 приведен модуль, соответствующий главной форме, В листинге 15.10 -форме О программе.Массив в начале игры
Рисунок 15.10. Массив в начале игры
В процессе игры состояние игрового поля меняется (игрок открывает клетки и ставит флажки) и, соответственно, меняются значения элементов массива. Если игрок поставил в клетку флажок, то значение соответствующего элемента массива увеличивается на 100. Например, если флажок поставлен правильно в клетку, в которой есть мина, то значение соответствующего элемента массива станет 109. Если флажок поставлен ошибочно, например, в пустую клетку, элемент массива будет содержать число 100. Если игрок открыл клетку, то значение элемента массива увеличивается на 200. Такой способ кодирования позволяет сохранить информацию о исходном состоянии клетки.
Начало игры
Начало игрыВ начале игры нужно расставить мины, затем для каждой клетки поля подсчитать, сколько мин находится в соседних клетках. Процедура NewGame (ее текст приведен в листинге 15.3) решает эту задачу.
Настройка программы тестирования
Рисунок 15.5. Настройка программы тестирования
Примечание
Текст, находящийся в поле Объект вкладки Ярлык диалогового окна Свойства, называется командной строкой.
Программа может получить параметр, указанный в командной строке запуска программы, как значение функции ParamStr^), где л — номер параметра. Количество параметров командной строки находится в глобальной переменной ParamCount. Для приведенного выше примера командной строки запуска программы тестирования значение переменной ParamCount равно 1, а функции ParamStr (1) — peterb.txt.
Ниже приведен фрагмент программы, обеспечивающий прием параметра из командной строки:
if ParamCount = 0 then begin
ShowMessage('Ошибка! Не задан файл вопросов теста.');
goto bye; // аварийное завершение программы
end;
FileName := ParamStr(1); // имя файла — параметр командной строки
При запуске программы, использующей параметры командной строки, из среды разработки параметры нужно ввести в поле Parameters диалогового окна Run Parameters (Рисунок 15.6), которое открывается в результате выбора из меню Run команды Parameters.
Окно О программе
Рисунок 15.15. Окно О программе
Чтобы программа во время своей работы могла вывести на экран окно, отличное от главного (стартового), нужно создать это окно. Делается это выбором из меню File команды New form. В результате выполнения команды New form в проект добавляется новая форма и соответствующим ей модуль.
Вид формы AboutForm после добавления необходимых компонентов приведен на Рисунок 15.16, значения ее свойств — в табл. 15.8.
Окно справочной информации
Рисунок 15.14. Окно справочной информации
Процесс создания СНМ-файла подробно описан в гл. 14. Процедура, обеспечивающая вывод справочной информации, приведена в листинге 15.7.
Примечание
Перед непосредственным созданием процедуры, обеспечивающей вывод справочной информации, в главную форму необходимо добавить компонент HhOpen.
Правила
ПравилаИгровое поле состоит из клеток, в каждой из которых может быть мина. Задача игрока — найти все мины и пометить их флажками.
Используя кнопки мыши, игрок может открыть клетку или поставить в нее флажок, указав тем самым, что в клетке находится мина. Клетка открывается щелчком левой кнопки мыши, флажок ставится щелчком правой. Если в клетке, которую открыл -игрок, есть мина, то происходит взрыв (сапер ошибся, а он, как известно, ошибается только один раз) и игра заканчивается. Если в клетке мины нет, то в этой клетке появляется число, соответствующее количеству мин, находящихся в соседних клетках. Анализируя информацию о количестве мин в клетках, соседних с уже открытыми, игрок может обнаружить и пометить флажками все мины. Ограничений на количество клеток, помеченных флажками, нет. Однако для завершения игры (выигрыша) флажки должны быть установлены только в тех клетках, в которых есть мины. Ошибочно установленный флажок можно убрать, щелкнув правой кнопкой мыши в клетке, в которой он находится.
Представление данных
Представление данныхВ программе игровое поле представлено массивом N+2 на M+2, где N xM — размер игрового поля. Элементы массива с номерами строк от 1 до N и номерами столбцов от 1 до М соответствуют клеткам игрового поля (Рисунок 15.9), первые и последние столбцы и строки соответствуют границе игрового поля.
Справочная информация
Справочная информацияПри выборе из меню ? команды Справка появляется справочная информация — правила игры (Рисунок 15.14).
Структура меню программы
Рисунок 15.13. Структура меню программы Сапер 2002
Свойство
СвойствоЗначения свойств стартовой формы
Таблица 15.1. Значения свойств стартовой формы| Свойство |
Значение Пояснение |
||
| Caption |
|
||
| Height |
362 |
||
| Width |
562 |
||
| Color |
clWhite |
||
| Font . Name |
Arial Cyr |
||
| Borderlcons . biSystemMenu |
True Есть кнопка системного меню |
||
| Borderlcons . biMinimize" |
False Нет кнопки Свернуть окно |
||
| Borderlcons . biMaximize |
False Нет кнопки Развернуть окно |
||
| BorderStyle |
bsSingle Тонкая граница окна, нельзя изменить размер окна |
||
ствие значения этих свойств на вид окна проявляется только во время работы программы. Значение свойства Borderstyle также проявляет себя только во время работы программы.
В табл. 15.2—15.5 приведены значения свойств компонентов формы.
Значения свойств компонентов Label1
Таблица 15.2. Значения свойств компонентов Label1 -Label5| Свойство |
Компонент |
||||||
| |
Label1 |
Label2 |
Label3 |
Label 4 |
Label5 |
||
| Left |
32 |
32 |
32 |
32 |
32 |
||
| Тор |
64 |
96 |
128 |
160 |
8 |
||
| AutoSize |
True |
True |
True |
True |
True |
||
| Wordwrap |
True |
True |
True |
True |
True |
||
Значения свойств компонентов RadioButton1
Таблица 15.3. Значения свойств компонентов RadioButton1 —RadioButton5| Свойство |
Компонент |
||||||
| |
Radio- Button1 |
Radio- Button2 |
Radio- Button3 |
Radio- Button4 |
Radio- Button5 |
||
| Caption |
— |
- |
— |
— |
— |
||
| Left |
8 |
8 |
8 |
8 |
8 |
||
| Top |
64 |
96 |
128 |
160 |
174 |
||
| Visible |
True |
True |
True |
True |
False |
||
Значения свойств кнопки
Таблица 15.4. Значения свойств кнопки Button1| Свойство |
Значение |
||
| Name |
Buttonl |
||
| Caption |
Ok |
||
| Left |
13 |
||
| Top |
273 |
||
| Height |
28 |
||
| Width |
82 |
||
Значения свойств панели
Таблица 15.5. Значения свойств панели Panel1Свойства компонента image
Таблица 15.6. Свойства компонента image| Свойство |
Определяет |
||
| Name |
Имя компонента |
||
| Picture |
Свойство, являющееся объектом типа Tbitmap. Определяет выводимую картинку |
||
| Left |
Расстояние от левого края формы до левой границы области картинки |
||
| Top |
Расстояние от верхней границы формы до верхней границы области картинки |
||
| Height |
Высоту картинки |
||
| Width |
Ширину картинки |
||
| Stretch | Признак автоматического сжатия или растяжения картинки таким образом, чтобы она была видна полностью в области, размер которой задан свойствами width и Height | ||
| AutoSize |
Признак автоматического изменения размера компонента в соответствии с реальным размером картинки. Если значение свойства AutoSize равно True, то при изменении значения свойства picture автоматически меняется размер области вывода иллюстрации так, чтобы была видна вся картинка. Если значение свойства AutoSize равно False, а размер картинки превышает размер области, то отображается только часть картинки |
||
Например, для разрабатываемого приложения инструкция вывода иллюстрации, находящейся в файле Isaak.bmp (изображение Исаакиевского собора), может быть такой:
Image1.Picture.LoadFromFile('isaak.bmp');
Очевидно, что размер области формы, которая может использоваться для вывода иллюстрации, зависит от длины (количества слов) вопроса, длины и количества альтернативных ответов. Чем длиннее вопрос и ответы, тем больше места в поле формы они занимают, и тем меньше места остается для иллюстрации.
При проектировании формы можно задать жесткие ограничения на размер областей, предназначенных для вопроса и альтернативных ответов, и жестко задать предельный размер иллюстрации. Однако можно поступить иначе. После прочтения из файла очередного вопроса вычислить, сколько места займут тексты вопроса и ответов и сколько места можно выделить для вывода иллюстрации (Рисунок 15.4).
Свойства объекта TMenuItem
Таблица 15.7. Свойства объекта TMenuItem| Свойство |
Определяет |
||
| Name |
Имя элемента меню. Используется для доступа к свойствам |
||
| Caption |
Название меню или команды |
||
| Bitmap |
Значок, который отображается слева от названия элемента меню |
||
| Enabled |
Признак доступности элемента меню. Если значение свойства равно False, то элемент меню недоступен, при этом название меню отображается серым цветом |
||
Значения свойств формы О программе
Таблица 15.8. Значения свойств формы О программе| Свойство |
Значение |
||
| Name |
AboutForm |
||
| Caption |
0 программе |
||
| BorderStyle |
BsSingle |
||
| Borderlcons . biSystemMenu |
False |
||
| Borderlcons .biMininize |
False |
||
| Borderlcons . biMaximize |
False |
||
Непосредственно вывод окна выполняет метод showModai, который выводит окно как модальный диалог.
Текст программы
Текст программыПосле создания формы в окно редактора кода, в секцию implementation следует поместить описание глобальных констант (раздел const) и переменных (раздел var). Затем можно приступить к созданию процедур обработки событий.
Их в программе три: обработка события onActivate для стартовой формы, обработка события Onclick для командной кнопки Buttoni и процедура обработки события onclick — одна, общая для переключателей выбора ответа.
В листинге 15.1 приведен полный текст программы.
Требования к программе
Требования к программеВ результате анализа различных тестов были сформулированы следующие требования к программе:
Усовершенствование программы
Усовершенствование программыОчевидно, что приведенный выше текст программы был бы намного проше и изящней, если бы поля вывода альтернативных ответов и переключатели выбора ответов были бы объединены в массивы. Тогда программа могла бы обращаться к полям и переключателям не по имени, а по индексу.
Delphi позволяет объединить компоненты в массив, однако создаваться такие компоненты должны не во время создания формы приложения, а динамически — во время работы программы.
На Рисунок 15.7 приведен вид формы усовершенствованного приложения.
Вычисление размера области вывода иллюстрации
Рисунок 15.4. Вычисление размера области вывода иллюстрации
Если реальный размер иллюстрации превышает размер области, выделенной для ее вывода, то необходимо вычислить коэффициент масштабирования и установить максимально возможные, пропорциональные ширине и высоте иллюстрации, значения свойств width и Height области вывода иллюстрации.
Реальные размеры иллюстрации, загруженной в область image 1, можно получить из свойств Image1.Picture.Bitmap.Width И Image1.Picture.Bitmap.Height.
Вывод иллюстрации
Вывод иллюстрацииДля вывода иллюстрации в форму добавлен компонент image, значок которого (Рисунок 15.3) находится на вкладке Additional палитры компонентов. В табл. 15.7 приведены свойства компонента image.
Загрузка файла теста
Загрузка файла тестаПередать имя файла теста программе тестирования можно через параметр командной строки путем настройки свойств значка, изображающего программу тестирования на рабочем столе или в папке.
Например, для настройки программы тестирования, значок запуска которой находится на рабочем столе, на работу с файлом теста Peterb.txt необходимо щелкнуть правой кнопкой мыши на значке программы, из появившегося контекстного меню выбрать команду Свойства и в поле Объект, после имени файла программы (Testl.exe), ввести имя файла теста (Peterb.txt), заключив его в двойные кавычки (Рисунок 15.5).
Отладка программы в Delphi
Диалоговое окно Confirm
Рисунок 16.12. Диалоговое окно Confirm
В результате открывается окно редактора пакета Package (Рисунок 16.13), в котором в списке Contains (Содержимое) перечислены компоненты пакета.
Диалоговое окно Install Component
Рисунок 16.4. Диалоговое окно Install Component
В поле Unit file name нужно ввести имя файла модуля. Для этого удобно воспользоваться кнопкой Browse.
Поле Search path (Путь поиска) должно содержать разделенные точкой с запятой имена каталогов, в которых Delphi во время установки компонента будет искать необходимые файлы, в частности файл ресурсов компонента. Если имя файла модуля было введено в поле Unit file name выбором файла из списка, полученного при помощи кнопки Browse, то Delphi автоматически добавляет в поле Search path имена необходимых каталогов.
Примечание
Файл ресурса компонента должен находиться в одном из каталогов, перечисленных в поле Search path. Если его там нет, то компоненту будет назначен значок его родительского класса.
Поле Package file name должно содержать имя пакета, в который будет установлен компонент. По умолчанию компоненты, создаваемые программистом, добавляются в пакет Dclusr70.dpk.
Поле Package description содержит название пакета. Для пакета Dclusr70.dpk
ЭТО текст: Borland User's Components.
После заполнения перечисленных полей и нажатия кнопки ОК начинается процесс установки. Сначала на экране появляется окно Confirm (Рисунок 16.5), в котором Delphi просит подтвердить обновление пакета.
Диалоговое окно New Component
Рисунок 16.1. Диалоговое окно New Component
Поле Ancestor type должно содержать базовый тип для создаваемого компонента. Базовый тип компонента можно задать непосредственным вводом имени типа или выбором из раскрывающегося списка. Для разрабатываемого компонента базовым компонентом является стандартный компонент Edit (поле ввода-редактирования). Поэтому базовым типом для типа разрабатываемого компонента является тип TEdit.
В поле Class Name необходимо ввести имя класса разрабатываемого компонента, например TNkEdit. Вспомните, что в Delphi имена типов должны начинаться буквой т.
В поле Palette Page нужно ввести имя вкладки палитры компонентов, на которую после создания компонента будет добавлен его значок. Название вкладки палитры компонентов можно выбрать из раскрывающегося списка. Если в поле Palette Page ввести имя еще не существующей вкладки палитры компонентов, то непосредственно перед добавлением компонента вкладка с указанным именем будет создана.
В поле Unit, file name находится автоматически сформированное имя файла модуля создаваемого компонента. Delphi присваивает модулю компонента имя, которое совпадает с именем типа компонента, но без буквы T. Щелкнув на кнопке с тремя точками, можно выбрать каталог, в котором должен быть сохранен модуль компонента.
После нажатия кнопки ОК к текущему проекту добавляется сформированный Delphi-модуль, представляющий собой заготовку (шаблон) модуля компонента. Текст этого модуля приведен в листинге 16.1.
Диалоговое окно Palette Properties
Рисунок 16.16. Диалоговое окно Palette Properties
Сначала в списке Pages необходимо выделить нужную вкладку палитры компонентов. Затем, если надо изменить порядок следования вкладок палитры компонентов, следует воспользоваться кнопками Move Up и Move Down и путем перемещения выбранного имени по списку Pages добиться нужного порядка следования вкладок.
Если надо изменить порядок следования значков компонентов на вкладке, то в списке Components следует выбрать нужный значок компонента и кнопками Move Up и Move Down переместить значок на новое место.
При необходимости изменить имя вкладки палитры следует в списке Pages выбрать имя нужной вкладки, нажать кнопку Rename и в поле Page name открывшегося диалогового окна Rename page (Рисунок 16.17) ввести новое имя.
Форма приложения Поездка на дачу (поля вводаредактирования компонента NkEdit)
Рисунок 16.9. Форма приложения Поездка на дачу (поля ввода-редактирования компонента NkEdit)
Внешне форма разрабатываемого приложения почти ничем не отличается от формы приложения Поездка на дачу, рассмотренного в гл. 6. Однако если выбранным компонентом будет поле ввода, то в окне Object Inspector указано, что текущим компонентом является компонент класса TNkEdit, a в списке свойств можно увидеть новое (по сравнению со списком свойств стандартного компонента Edit) свойство — Numb (Рисунок 16.10).
Форма приложения Тест компонента NkEdit
Рисунок 16.2. Форма приложения Тест компонента NkEdit
Форма содержит две метки и командную кнопку. Первая метка предназначена для вывода информационного сообщения, вторая метка (на рисунке она выделена) используется для вывода числа, введенного в поле редактирования. Самого поля редактирования компонента NkEdit в форме нет. Этот компонент будет создан динамически во время работы программы, но для него оставлено место над полем метки.
После создания формы в модуль приложения, автоматически сформированный Delphi, необходимо внести следующие дополнения:
1. В список используемых модулей (раздел uses) добавить имя модуля тестируемого компонента (NkEdit).
2. В раздел объявления переменных (var) добавить инструкцию объявления компонента. Здесь следует вспомнить, что компонент является объектом, поэтому объявление компонента в разделе переменных не обеспечивает создание компонента, а только генерирует указатель на компонент, следовательно необходима инструкция вызова конструктора объекта, которая действительно создает компонент (объект).
3. Для формы приложения создать процедуру обработки события oncreate, которая вызовом конструктора тестируемого компонента создаст компонент и установит значения его свойств.
В листинге 16.3 приведен модуль приложения тестирования компонента NkEdit.
Информационное сообщение о том что компонент больше недоступен
Рисунок 16.15. Информационное сообщение о том, что компонент больше недоступен
После перекомпиляции пакета необходимо закрыть окно редактора пакета и в открывшемся окне подтвердить сохранение изменений в пакете, из которого был удален компонент.
Шаблон модуля компонента
Листинг 16.1. Шаблон модуля компонентаunit NkEdit; interface
uses
Windows, Messages, SysUtils, Classes, Controls, StdCtrls;
type
TEdit1 = class(TEdit)
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
end;
procedure Register;
implementation
procedure Register;
begin
RegisterComponents('Samples', [TNkEdit]);
end;
end.
В объявлении нового класса указан только тип родительского класса. В раздел реализации помещена процедура Register, которая используется во время установки созданного программистом компонента на указанную вкладку палитры компонентов Delphi для регистрации нового класса.
В сформированное Delphi объявление класса нового компонента нужно внести дополнения: объявить свойство, поле данных этого свойства, функцию доступа к полю данных, процедуру установки значения поля данных, конструктор и деструктор. Если на некоторые события компонент должен реагировать не так, как базовый, то в объявление класса нужно поместить описание соответствующих процедур обработки событий.
В листинге 16.2 приведен текст модуля компонента NkEdit после внесения всех необходимых изменений.
Модуль компонента NkEdit
Листинг 16.2. Модуль компонента NkEditunit NkEdit;
interface
uses
Windows, Messages, SysUtils,
Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TNkEdit = class(TEdit)
private
FNumb: single; // число, находящееся в поле редактирования
// Это описание функции доступа
// и процедуры установки поля FNumb
function GetNumb: single;
procedure SetNumb(value:single);
protected
procedure KeyPress(var Key: Char);
override;
public
published
constructor Create(AOwner:TComponent);
override; property Numb : single
// свойство компонента
read GetNumb write SetNumb;
end;
procedure Register;
implementation
// процедура регистрации компонента
procedure Register;
begin
RegisterComponents('Samples',[TNkEdit]);
end;
// конструктор компонента
constructor TNkEdit.Create(AOwner:TComponent);
begin
// don't forget to call the ancestors' constructor
inherited Create(AOwner);
end;
// функция доступа к полю FNumb
function TNkEdit.GetNumb:single;
begin
try // поле Text может быть пустым Result:=StrToFloat(text);
except
on EConvertError do begin
Result:=0; text: =' ' ;
end;
end;
end;
// процедура записи в поле FNumb
procedure TNkEdit.SetNumb(Value:single);
begin
FNumb:=Value;
Text:=FloatToStr(value);
end;
// процедура обработки события KeyPress
procedure TNkEdit.KeyPress(var key:char) ;
begin
case key of
'0'.. '9', #8, #13: ;
'-': if Length(text)<>
0 then key:=#0;
else
if not ((key = DecimalSeparator) and
(Pos(DecimalSeparator,text)=0))
then key:= #0;
end;
inherited KeyPress(key);
// вызов процедуры обработки события
// OnKeyPress родительского класса
end;
end.
В описание класса TNkEdit добавлено объявление свойства Numb, которое представляет собой число, находящееся в поле редактирования. Для хранения Значения свойства Numb используется поле FNumb. Функция GetNumb необходима для доступа к полю FNumb, а процедура setNumb — для установки значения свойства.
Конструктор класса TNkEdit сначала вызывает конструктор родительского класса (TEdit), присваивает значение свойству Text, затем устанавливает значение свойства Numb.
Реакция компонента NkEdit на нажатие клавиши клавиатуры определяется процедурой обработки события TNkEdit.KeyPress, которая замещает соответствующую процедуру базового класса. В качестве параметра процедура TNkEdit.KeyPress получает код нажатой клавиши. Перед вызовом процедуры обработки события OnKeyPress родительского класса код нажатой клавиши проверяется на допустимость. Если нажата недопустимая для компонента NkEdit клавиша, то код символа заменяется на ноль. Допустимыми для компонента NkEdit являются цифровые клавиши, разделитель целой и дробной частей числа (в зависимости от настройки Windows: точка или запятая), "минус",
(позволяет удалить ошибочно введенный символ) и
.
Здесь следует вспомнить, что в тексте программы дробная часть числовой константы отделяется от целой части точкой. Во время работы программы при вводе исходных данных пользователь должен использовать тот символ, который задан в настройке Windows. В качестве разделителя обычно применяют запятую (это для России стандартная настройка) или точку. Приведенная процедура обработки события OnKeyPress учитывает, что настройка Windows может меняться, и поэтому введенный пользователем символ сравнивается не с константой, а со значением глобальной переменной
DecimalSeparator, которая содержит символ-разделитель, используемый в Windows в данный момент.
После ввода текста модуля компонента модуль нужно откомпилировать и сохранить.
Тест компонента NkEdit
Листинг 16.3. Тест компонента NkEditunit tstNkEdit_; interface
uses
Windows, Messages, SysUtils,
Variants, Classes, Graphics,
Controls,Forms, Dialogs, StdCtrls,
NkEdit; // ссылка на модуль компонента
type
TForm1 = class(TForm)
Label1: TLabel;
Label2: TLabel;
Buttonl: TButton;
procedure FormCreate(Sender: TObject);
procedure ButtonlClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
myEdit: TnkEdit; // компонент NkEdit
implementation
{$R *.dfm)
procedure TForm1.FormCreate(Sender: TObject);
begin
// создадим компонент и поместим его на форму
myEdit := TNkEdit.Create(self);
myEdit.Parent := self;
myEdit.Left := 8;
myEdit.Top := 64;
end;
procedure TForm1.ButtonlClick(Sender: TObject);
begin
label2. Caption := FloatToStr (myEdit .Numb) ;
end;
end.
Тестируемый компонент создается процедурой обработки события Formcre-ate (Создание формы) посредством вызова конструктора компонента, которому в качестве параметра передается значение self, показывающее, что владельцем компонента является форма приложения.
После создания компонента обязательно должен быть выполнен важный шаг: свойству Parent необходимо присвоить значение. В данном случае тестируемый компонент находится в форме приложения, поэтому свойству Parent присваивается значение self.
На Рисунок 16.3 приведено окно программы Тест компонента NkEdit во время ее работы, после ввода числа в поле редактирования и щелчка на кнопке Тест.
Приложение "Поездка на дачу" тест компонента
Листинг 16.4. Приложение "Поездка на дачу" тест компонентаunit fazenda ;
interface
uses
Windows, Messages, SysUtils,
Variants, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls,
NkEdit; // ссылка на модуль компонента
type
TForm1 = class(TForm)
NkEdit 1: TNkEdit; //расстояние
NkEdit2: TNkEdit; // цена литра бензина
NkEditS: TNkEdit; // потребление бензина на 100 км
CheckBox1: TCheckBox; // True — поездка туда и обратно
Button1: TButton; Label4: TLabel;
Label1: TLabel; Label2: TLabel;
Label3: TLabel;
// кнопка Вычислить
// поле вывода результата расчета
procedure ButtonlClick(Sender: TObject);
procedure NkEditlKeyPress
(Sender: TObject; var Key: Char);
procedure NkEdit2KeyPress
(Sender: TObject; var Key: Char);
procedure NkEditSKeyPress
(Sender: TObject; var Key: Char);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
// нажатие клавиши в поле Расстояние
procedure TForm1.NkEdit1KeyPress
(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then NkEdit2.SetFocus; // переместить курсор в поле Цена
end;
// нажатие клавиши в поле Цена
procedure TForm1.NkEdit2KeyPress
(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then NkEdit3.SetFocus;
// переместить курсор в поле Потребление
end;
// нажатие клавиши в поле Потребление
procedure TForm1.NkEdit3KeyPress
(Sender: TObject; var Key: Char);
begin
if Key = Char(VK_RETURN)
then Buttonl.SetFocus; //
// сделать активной кнопку Вычислить
end;
// щелчок на кнопке Вычислить
procedure TForml.ButtonlClick(Sender: TObject);
var
rast : real; // расстояние
cena : real; // цена
potr : real; // потребление на 100 км
summ : real; // сумма
mes: string; begin
rast := StrToFloat(NkEdit1.Text);
cena := StrToFloat(NkEdit2.Text);
potr := StrToFloat(NkEdit3.Text) ;
summ := rast / 100 * potr * cena;
if CheckBoxl.Checked then sunnm := summ * 2;
mes := 'Поездка на дачу';
if CheckBoxl.Checked then mes := mes + ' и обратно';
mes := mes + 'обойдется в '
+ FloatToStrF(summ,ffGeneral,4,2) + ' руб.';
Label4.Caption := mes;
end;
end.
Настройка палитры компонентов
Настройка палитры компонентовDelphi позволяет менять порядок следования вкладок палитры компонентов, названия вкладок, а также порядок следования значков компонентов на вкладках. Настройка палитры компонентов выполняется в диалоговом окне Palette Properties, которое открывается выбором из меню Component команды Configure Palette (Рисунок 16.16).
Окно редактора пакета компонентов
Рисунок 16.7. Окно редактора пакета компонентов
На этом процесс установки компонента заканчивается. В результате на вкладке палитры компонентов, имя которой было задано при создании модуля компонента, появляется значок установленного компонента (Рисунок 16.8).
Окно редактора пакета
Рисунок 16.13. Окно редактора пакета
Для того чтобы удалить компонент из пакета, необходимо нажать кнопку Remove. В открывшемся диалоговом окне Remove From Project (Рисунок 16.14) следует выбрать удаляемый компонент и нажать кнопку ОК.
Ошибки при установке компонента
Ошибки при установке компонентаВо время работы над новым компонентом наиболее частой ошибкой является попытка установить (переустановить) компонент, который уже находится в одном из пакетов (обычно такое желание возникает после внесения изменений в модуль компонента).
В этом случае Delphi выводит сообщение: The package already contains unit named... (Пакет уже содержит модуль, который называется...) и процесс установки завершается. Для того чтобы преодолеть эту ошибочную ситуацию и установить компонент в нужный пакет или установить в пакет обновленную версию компонента, необходимо сначала удалить компонент из пакета, а затем установить его снова.
Ресурсы компонента
Ресурсы компонентаФайл ресурсов компонента можно создать при помощи утилиты Image Editor, которая запускается выбором из меню Tools команды Image Editor.
Для того чтобы создать новый файл ресурса компонента, нужно из меню File выбрать команду New и из появившегося списка выбрать тип создаваемого файла — Component Resource File.
В результате открывается окно файла ресурсов Untitledl.dcr, а в меню диалогового окна Image Editor появляется новый пункт — Resource. Теперь нужно из меню Resource выбрать команду New/Bitmap и в открывшемся окне Bitmap Properties установить характеристики битового образа значка компонента: Size — 24x24 пиксела, Colors — 16.
В результате этих действий в создаваемый файл ресурсов компонента будет добавлен новый ресурс — битовый образ с именем Bitmap1 Двойной щелчок на имени ресурса (Bitmapl) раскрывает окно редактора битового образа, в котором можно нарисовать нужную картинку.
Изображение в окне графического редактора можно увеличить. Для этого необходимо выбрать команду Zoom In меню View.
Следует обратить внимание, что цвет правой нижней точки рисунка определяет "прозрачный" цвет. Элементы значка компонента, закрашенные этим цветом, на палитре компонентов Delphi не видны.
Перед тем, как сохранить файл ресурсов компонента, битовому образу надо присвоить имя. Имя должно совпадать с именем класса компонента. Чтобы задать имя битового образа, необходимо щелкнуть правой кнопкой мыши на имени битового образа (Bitmap1), выбрать в появившемся контекстном меню команду Rename и ввести новое имя.
Созданный файл ресурсов компонента нужно сохранить в том каталоге, в котором находится файл модуля компонента. Для этого надо из меню File выбрать команду Save.
Внимание!
Имя файла ресурсов компонента (Edit.dcr) должно совпадать с именем модуля компонента (Edit.pas), а имя битового образа (Edit) — с именем класса компонента (Edit).
Сообщение о неуспешной установке компонента
Рисунок 16.6. Сообщение о неуспешной установке компонента
После установки компонента в пакет открывается диалоговое окно Package (Редактор пакета компонентов) (Рисунок 16.70), в котором перечислены компоненты, находящиеся в пакете.
Создание модуля компонента
Создание модуля компонентаПеред началом работы по созданию нового компонента нужно создать отдельный каталог для модуля и других файлов компонента. После этого можно приступить к созданию модуля компонента.
Для того чтобы создать модуль компонента, необходимо из меню Component выбрать команду New Component и в поля открывшегося диалогового окна New Component (Рисунок 16.1) ввести информацию о создаваемом компоненте.
Свойство компонента NkEdit отражено в окне Object Inspector
Рисунок 16.10. Свойство компонента NkEdit отражено в окне Object Inspector
В листинге 16.4 приведен модуль приложения Поездка на дачу. Очевидно, что текст программы значительно меньше первоначального варианта, в котором для ввода данных использовался компонент Edit.
Тестирование компонента Поле ввода — компонент NkEdit
Рисунок 16.3. Тестирование компонента. Поле ввода — компонент NkEdit
Тестирование компонента
Тестирование компонентаПосле того как компонент будет добавлен в пакет, необходимо проверить поведение компонента во время разработки приложения, использующего этот компонент (работоспособность компонента была проверена раньше, когда он добавлялся в форму приложения динамически, во время работы программы).
Можно считать, что компонент работает правильно, если во время разработки приложения удалось поместить этот компонент в форму разрабатываемого приложения и, используя окно Object Inspector, установить, значения свойств компонента, причем как новых, так и унаследованных от родительского класса.
Работоспособность компонента NkEdit можно проверить, использовав его, например, в приложении Поездка на дачу, вид формы которого приведен на Рисунок 16.9.
Тестирование модуля компонента
Тестирование модуля компонентаПеред добавлением нового компонента в палитру компонентов необходимо всесторонне его проверить. Для этого надо создать приложение, использующее компонент и убедиться, что компонент работает так, как надо.
Во время создания формы приложения нельзя добавить в форму компонент, значка которого нет в палитре компонентов. Однако такой компонент может быть добавлен в форму динамически, т. е. во время работы приложения.
Создается тестовое приложение обычным образом: сначала создается форма приложения, а затем — модуль приложения.
Вид формы приложения тестирования компонента NkEdit- приведен на Рисунок 16.2.
Удаление компонента
Удаление компонентаИногда возникает необходимость удалить компонент из пакета. Сделать это можно при помощи редактора пакета компонентов.
Для того чтобы запустить редактор пакета компонентов, надо из меню Component выбрать команду Install Packages, в открывшемся диалоговом окне Project Options (Рисунок 16.11) из списка Design packages выбрать нужный пакет и нажать кнопку Edit.
Установка компонента
Установка компонентаДля того чтобы значок компонента появился в палитре компонентов, компонент должен быть добавлен в один из пакетов (Packages) компонентов
Delphi. Пакет компонентов — это файл с расширением dpk (Delphi Package File). Например, компоненты, созданные программистом, находятся в пакете Dclusr70.dpk.
Во время добавления компонента в пакет Delphi использует модуль компонента и файл ресурсов компонента, в котором должен находиться битовый образ значка компонента. Имя файла ресурсов компонента должно обязательно совпадать с именем файла модуля компонента. Файл ресурсов имеет расширение dcr (Dynamic Component Resource). Битовый образ, находящийся внутри файла ресурсов, должен иметь имя, совпадающее с именем класса компонента.
Установка
УстановкаПосле создания файла ресурсов компонента, в котором находится битовый образ значка компонента, можно приступить к установке компонента. Для этого надо из меню Component выбрать команду Install Component и заполнить поля открывшегося окна Install Component (Рисунок 16.5).
Вкладка Samples после установки компонента NkEdit
Рисунок 16.8. Вкладка Samples после установки компонента NkEdit
Выбор базового класса
Выбор базового классаПриступая к разработке нового компонента, следует четко сформулировать назначение компонента. Затем необходимо определить, какой из компонентов Delphi наиболее близок по своему назначению, виду и функциональным возможностям к компоненту, который разрабатывается. Именно этот компонент следует выбрать в качестве базового.
Выбор компонента удаляемого из пакета
Рисунок 16.14. Выбор компонента, удаляемого из пакета
После удаления компонента из пакета нужно обязательно выполнить перекомпиляцию пакета. Для этого необходимо в окне редактора пакета нажать кнопку Compile. После перекомпиляции пакета Delphi информирует о том, что удаленный компонент больше не зарегистрирован (Рисунок 16.15).
Выбор пакета для редактирования
Рисунок 16.11. Выбор пакета для редактирования
В открывшемся окне Confirm (Рисунок 16.12) в ответ на запрос: cancel this dialog box and open... (Закрыть этот диалог и открыть пакет...) надо нажать кнопку Yes.
Запрос подтверждения обновления пакета в процессе установки компонента
Рисунок 16.5. Запрос подтверждения обновления пакета в процессе установки компонента
После нажатия кнопки Yes процесс установки продолжается. Если он завершается успешно, то на экране появляется информационное сообщение (Рисунок 16.6) о том, что в результате обновления пакета палитра компонентов обновлена, т. е. в нее добавлен значок компонента, и новый компонент зарегистрирован.
Отладка программы в Delphi
Диалоговое окно New Database Alias
Рисунок 17.3. Диалоговое окно New Database Alias
После выбора драйвера и щелчка на кнопке ОК в список псевдонимов будет добавлен новый элемент (Рисунок 17.4).
Динамически создаваемые псевдонимы
Динамически создаваемые псевдонимыИспользование псевдонима для доступа к базе данных обеспечивает независимость программы от размещения данных в системе, позволяет размещать программу работы с данными и базу данных на разных дисках компьютера, в том числе и на сетевом. Вместе с тем, для простых баз данных типичным решением является размещение базы данных в отдельном подкаталоге того каталога, в котором находится программа работы с базой данных. Таким образом, программа работы с базой данных всегда "знает", где находятся данные. При таком подходе можно отказаться от создания псевдонима при помощи BDE Administrator и возложить задачу создания псевдонима на программу работы с базой данных. Причем, псевдоним будет создаваться автоматически во время запуска программы и уничтожаться во время завершения ее работы. Очевидно, что такой подход облегчает администрирование базы данных.
В качестве иллюстрации сказанного в листинге 17.3 приведен вариант программы работы с базой данных "Школа", которая для доступа к базе данных использует динамически создаваемый псевдоним.
Доступ к базе данных (таблице)
Доступ к базе данных (таблице)Доступ к базе данных обеспечивают компоненты Database, Table, Query и DataSource, значки которых находятся на вкладках Data Access и BDE палитры компонентов (Рисунок 17.6).
После этого программу можно откомпилировать
Рисунок 17.16. Форма после настройки компонента DBGrid1
После этого программу можно откомпилировать и запустить. Следует обратить внимание, что для того чтобы после запуска программы в окне появилась информация или, если база данных пустая, можно было вводить новую информацию, свойство Active таблицы-источника данных должно иметь значение True.
Работа с базой данных, представленной в виде таблицы, во многом похожа на работу с электронной таблицей Microsoft Excel. Используя клавиши перемещения курсора вверх и вниз, а также клавиши листания текста страницами (
Форма приложения Архитектурные памятники СанктПетербурга
Рисунок 17.9. Форма приложения Архитектурные памятники Санкт-Петербурга
Создается форма следующим образом. Сначала в пустую форму надо добавить компоненты Tаblе и Datasource и установить значения их свойств (табл. 17.10). Значения свойств следует устанавливать в том порядке, в котором они следуют в таблице.
Форма приложения База данных Школа
Рисунок 17.19. Форма приложения База данных Школа
Форма приложения после добавления компонента DBGrid
Рисунок 17.14. Форма приложения после добавления компонента DBGrid
Компонент DBGrid обеспечивает представление базы данных в виде таблицы. Свойства компонента DBGridl определяют вид таблицы и действия, которые могут быть выполнены над данными во время работы программы. В табл. 17.15 перечислены некоторые свойства компонента DBGrid.
файлы данных) находятся на одном
|
Локальная база данных Данные локальной базы данных ( файлы данных) находятся на одном (локальном) устройстве, в качестве которого может выступать диск компьютера или сетевой диск (диск другого компьютера, работающего в сети). Для обеспечения разделения данных (доступа к данным) между несколькими пользователями, в качестве которых выступают программы, работающие на одном или нескольких компьютерах, в локальных базах данных применяется метод, получивший название блокировка файлов. Суть этого метода заключается в том, что пока данные используются одним пользователем, другой пользователь не может работать с этими данными, т. е. данные для него закрыты, заблокированы. Paradox, dBase, FoxPro и Access — это локальные базы данных. |
Классификация баз данных
Классификация баз данныхВ зависимости от расположения программы, использующей данные, и самих данных, а также способа разделения данных между несколькими пользователями различают локальные и удаленные базы данных.
Компонент DBNavigator
Рисунок 17.11. Компонент DBNavigator
Табл. 17.12 содержит описания действий, которые выполняются в результате щелчка на соответствующей кнопке компонента DBNavigator.
Свойства компонента DBNavigator перечислены в табл. 17.13.
Компонент
КомпонентDBGrid1. Columns [1]
Name
Имя
| Компонент |
FieldName |
Title . Caption |
||
| DBGrid1. Columns [2] DBGrid1 . Columns [ 3 ] |
Class Adr |
Класс Адрес,телефон |
||
Окончательный вид формы приложения приведен на Рисунок 17.16.
Компоненты просмотра и редактирования полей базы данных
Рисунок 17.8. Компоненты просмотра и редактирования полей базы данных
Компоненты вкладок Data Access и BDE обеспечивают доступ к данным
Рисунок 17.6. Компоненты вкладок Data Access и BDE обеспечивают доступ к данным
Компонент Database представляет базу данных как единое целое, т. е. совокупность таблиц, а компонент Table — одну из таблиц базы данных. Компонент DataSource (источник данных) обеспечивает связь компонента отображения-редактирования данных (например, компонента DBGrid) и источника данных, в качестве которого может выступать таблица (компонент Tаblе) или результат выполнения SQL-запроса к таблице (компонент SQL). Компонент DataSource позволяет оперативно выбирать источник данных, использовать один и тот же компонент, например, DBGrid для отображения данных из таблицы или результата выполнения SQL-запроса к этой таблице. Механизм взаимодействия компонентов отображения-редактирования данных с данными через компонент DataSource иллюстрирует Рисунок 17.7.
База данных "Архитектурные памятники СанктПетербурга"
Листинг 17.1. База данных "Архитектурные памятники Санкт-Петербурга"unit peter_;
interface
uses
Windows, Messages, SysUtils,
Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls,
DBCtrls, Mask, Db, DBTables,
jpeg; // чтобы можно было выводить JPG-иллюстрации;
type
TForml = class(TForm)
Tablel: TTable; . // база данных — таблица
DataSourcel: TDataSource; // источник данных для полей
// редактирования-просмотра
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
DBEditl: TDBEdit;
DBEdit2: TDBEdit;
DBMemo1: TDBMemo;
Image1: ТImage;
DBEdit3: TDBEdit;
DBNavigatorl: TDBNavigator;
Label4: TLabel;
procedure TablelAfterScroll(DataSet: TDataSet);
procedure DBEdit3KeyPress(Sender: TObject; var Key: Char);
procedure DBNavigatorlClick(Sender: TObject; Button: TNavigateBtn)
procedure TablelBeforeOpen(DataSet: TDataSet);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Forml: TForml;
BmpPath: string; // Путь к файлам иллюстраций. Иллюстрации
// находятся в подкаталоге Data каталога программы.
implementation
($R *.DFM}
// выводит фотографию в поле Imagel
procedure ShowFoto(foto: string);
begin
try
Forml.Imagel.Picture.LoadFromFile(BmpPath+foto);
Forml.Imagel.Visible:=True;
except
on EFOpenError do
begin
MessageDlg('Файл иллюстрации '+foto+' не найден.',
mtlnformation, [mbOk], 0) ;
end;
end;
end;
// переход к другой записи (следующей, предыдущей,
// первой или последней)
procedure TForm1.TablelAfterScroll(DataSet: TDataSet);
begin.
if form1.DBEdit3.Visible then
begin
form1.DBEditS.Visible := False;
form1.Label4.Visible:=False;
end;
if Forml.DBEditS.Text <>
"
then ShowFoto(Form1.DBEditS.Text)
else form1.Imagel.Visible:=False;
end;
// нажатие клавиши в поле Фото
procedure TForml.DBEdit3KeyPress(Sender: TObject; var Key: Char);
begin
if (key = #13) then
if Forml.DBEdit3.Text <>
''
then ShowFoto(Forml.DBEdit3.Text) // показать иллюстрацию
else forml,Imagel.Visible:=False;
end;
// щелчок на компоненте Навигатор
procedure TForml.DBNavigatorlClick(Sender: TObject; Button:
TNavigateBtn);
begin
case Button of
nblnsert: begin
Imagel.Visible:=False;// скрыть область вывода иллюстрации
DBEdit3.Visible:=True; // показать поле Фото
Label4.Visible:=True; // показать метку Фото
end;
nbEdit: begin // редактирование записи
DBEdit3.Visible:=True; // показать поле Фото
Label4.Visible:=True; // показать метку Фото
end;
end;
end;
// перед открытием таблицы
procedure TForml.TablelBeforeOpen(DataSet: TDataSet);
begin
BmpPath:=ExtractFilePath(ParamStr(0))+'data\';
end;
end.
end.
Вызов процедуры вывода фотографии (showFoto) во время просмотра базы данных выполняет процедура TForm1.Table1AfterScroll, которая обеспечивает обработку события AfterScrool для компонента Table1. Событие AfterScrool происходит всякий раз после перехода к другой (следующей, предыдущей, первой, последней) записи таблицы как результат щелчка пользователя на соответствующей кнопке компонента DBNavigator. Процедура TForml.Table1AfterScroll анализирует содержимое поля (photo) Form1.DBEdit3.Text и, если оно не пустое, что свидетельствует о наличии ссылки на файл фотографии, выводит иллюстрацию.
При просмотре базы данных поле имени файла иллюстрации (DBEdits) и его заголовок (Label4) на форме не отображаются. Если пользователь нажимает одну из кнопок компонента DBNavigator, то как результат обработки события onclick вызывается процедура TForm1.DBNavigatorlciick, которая при щелчке кнопки Добавить или Редактировать делает доступным поле DBEdits, тем самым позволяя пользователю ввести или изменить имя файла иллюстрации.
Процедура TForm1.DBEdit3KeyPress обрабатывает событие OnKeyPress для компонента DBEdits. Если пользователь ввел в поле Edits (photo) имя файла иллюстрации и нажал клавишу
(ее код равен 13), то процедура TForm1.DBEdit3KeyPress выводит иллюстрацию путем вызова процедуры ShowFoto.
База данных "Школа"
Листинг 17.2. База данных "Школа"unit school2_;
interface
uses
Windows, Messages, SysUtils, Classes,
Graphics, Controls, Forms,
Dialogs,Grids, DBGrids, Db,
DBTables, ExtCtrls, DBCtrls, StdCtrls;
type
TForm1 = class(TForm)
Table1: TTable; // таблица (вся база данных)
Query1: TQuery; // запрос (записи БД, удовлетворяющие критерию выбора)
DataSource1: TDataSource; // источник данных - таблица или запрос
DBGrid1: TDBGrid; // таблица для отображения БД или результата выполнения запроса
DBNavigator1: TDBNavigator;
DBText1: TDBText;
Button1: TButton; // кнопка запрос
Button2: TButton; // кнопка Все записи
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
// щелчок на кнопке Запрос
procedure TForm1.Button1Click(Sender: TObject);
var
fam: string[30];
begin
fam:=InputBox('Выборка информации из БД',
'Укажите фамилию и щелкните на OK.', '');
if fam <>
'' // пользователь ввел фамилию
then
begin
with form1.Query1 do begin
Close; // закрыть файл-результат выполнения предыдущего запроса
SQL.Clear; // удалить текст предыдущего запроса
// записываем новый запрос в свойство SQL
SQL.Add('SELECT Fam, Name, Class');
SQL.Add('FROM ":Школа:school.db"');
SQL.Add('WHERE');
SQL.Add('(Fam = "'+ fam + '")');
SQL.Add('ORDER BY Name, Fam');
Open; // активизируем выполнение запроса
end;
{ *** другой вариант изменения критерия запроса
begin
Query1.Close;
Query1.SQL[3]:='(Fam="'+ fam + '")';
Query1.Open;
DataSource1.DataSet:=Query1;
end;
}
if Query1.RecordCount <>
0 then
DataSource1.DataSet:=Query1 // отобразить рез-т выполнения запроса
else begin
ShowMessage('В БД нет записей, удовлетворяющих критерию запроса.');
DataSource1.DataSet:=Table1;
end;
end;
end;
// щелчок на кнопке Все записи
procedure TForm1.Button2Click(Sender: TObject);
begin
DataSource1.DataSet:=Table1; // источник данных - таблица
end;
// активизация формы
procedure TForm1.FormActivate(Sender: TObject);
begin
DataSource1.DataSet := Table1;
Table1.Active := True;
end;
end.
Процедура TForm1.Button1Click запускается щелчком кнопки Запрос. Она принимает от пользователя строку (фамилии) и записью (добавлением) строк в свойство SQL формирует текст запроса. Затем эта процедура вызовом метода Open активизирует выполнение запроса.
Следует обратить внимание на то, что перед изменением свойства SQL-запрос должен быть закрыт при помощи метода close (здесь надо вспомнить, что результат выполнения запроса — это файл данных (таблица), который создается в результате выполнения запроса).
Процедура TForm1.Button2Click, которая запускается щелчком кнопки Все записи, устанавливает в качестве источника данных для компонента DataSourcel компонент Table1, тем самым обеспечивая переход в режим просмотра всей базы данных.
Если запрос записан в свойство SQL во время разработки формы приложения, то во время работы программы критерий запроса можно изменить простой заменой соответствующей строки текста запроса.
Например, для запроса
SELECT DISTINCT Fam, Name, Class FROM ":Школа:school.db" WHERE
(Class= '10а') ORDER BY Name, Fam
инструкция замены критерия запроса может быть такой:
forml.Query1.SQL[3]:='(Fam="' + fam+ '")'
Следует обратить внимание на то, что свойство SQL является структурой типа TStrings, в которой строки нумеруются с нуля.
База данных "Школа" (псевдоним БД создается динамически)
Листинг 17.3. База данных "Школа" (псевдоним БД создается динамически)unit school3_;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, Grids, DBGrids, Db, DBTables, ExtCtrls, DBCtrls, StdCtrls;
type
TForm1 = class(TForm)
Table1: TTable; // таблица (вся база данных)
Query1: TQuery; // запрос (записи БД, удовлетворяющие критерию выбора)
DataSource1: TDataSource; // источник данных - таблица или запрос
DBGrid1: TDBGrid; // таблица для отображения БД или результата выполнения запроса
DBNavigator1: TDBNavigator;
DBText1: TDBText;
Button1: TButton; // кнопка запрос
Button2: TButton; // кнопка Все записи
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.DFM}
// щелчок на кнопке Запрос
procedure TForm1.Button1Click(Sender: TObject);
var
fam: string[30];
begin
fam:=InputBox('Выборка информации из БД',
'Укажите фамилию и щелкните на OK.', '');
if fam <>
'' // пользователь ввел фамилию
then
begin
with form1.Query1 do begin
Close; // закрыть файл-результат выполнения предыдущего запроса
SQL.Clear; // удалить текст предыдущего запроса
// записываем новый запрос в свойство SQL
SQL.Add('SELECT Fam, Name, Class');
SQL.Add('FROM ":Школа:school.db"');
SQL.Add('WHERE');
SQL.Add('(Fam = "'+ fam + '")');
SQL.Add('ORDER BY Name, Fam');
Open; // активизируем выполнение запроса
end;
if Query1.RecordCount <>
0 then
DataSource1.DataSet:=Query1 // отобразить рез-т выполнения запроса
else begin
ShowMessage('В БД нет записей, удовлетворяющих критерию запроса.');
DataSource1.DataSet:=Table1;
end;
end;
end;
// щелчок на кнопке Все записи
procedure TForm1.Button2Click(Sender: TObject);
begin
DataSource1.DataSet:=Table1; // источник данных - таблица
end;
// активизация формы
procedure TForm1.FormActivate(Sender: TObject);
begin
with Session do
begin
ConfigMode := cmSession;
try
{ Если файл данных находиться в том же каталоге,
что и выполняемый файл программы, то в программе
путь к файлу данных может быть получен из командной
строки при помощи функции ExtractFilePath(ParamStr(0)).
В приведенном примере файл данных находиться в подкаталоге
DATA каталога программы. }
// создадим временный псевдоним для базы данны
AddStandardAlias( 'Школа',
ExtractFilePath(ParamStr(0))+'DATA\',
'PARADOX');
Table1.Active:=True; // откроем базу данных
finally
ConfigMode := cmAll;
end;
end;
end;
end.
В рассматриваемом варианте программы предполагается, что база данных содержится в подкаталоге DATA того каталога, в котором находится выполняемый файл программы. Создает псевдоним процедура TForm1.FormActivate. Непосредственное создание псевдонима выполняет процедура AddstandardAlias, которой в качестве параметра передается имя псевдонима и соответствующее ему имя каталога. Так как во время разработки программы нельзя знать, в каком каталоге будет размещена программа работы с базой данных и, следовательно, подкаталог базы данных -DATA, имя каталога определяется во время работы программы путем обращения к функциям ParamStr(0) и ExtractFilePatch. Значение первой -полное имя выполняемого файла программы, второй — путь к этому файлу. Таким образом, процедуре AddstandardAiias передается полное имя каталога базы данных.
Модель базы данных в Delphi
Модель базы данных в DelphiКаждая таблица физически хранится в отдельном файле. Однако отождествлять базу данных и таблицу нельзя, так как довольно часто поля одной записи распределены по нескольким таблицам и, следовательно, находятся в разных файлах.
В простейшем случае источником информации для программы, работающей с базой данных, может быть вся таблица. Однако, как правило, пользователя интересует не вся информация, находящаяся в базе данных, а только какая-то ее часть. Он выбирает и просматривает только некоторые, удовлетворяющие его запросу записи. Поэтому в модель базы данных помимо таблицы, представляющей собой всю базу данных, было введено понятие запроса, являющегося выборкой, т. е. группой записей базы данных.
Окно BDE Administrator
Рисунок 17.2. Окно BDE Administrator
В левой части окна, на вкладке Databases, перечислены псевдонимы, зарегистрированные на данном компьютере. Для того чтобы создать новый псевдоним, необходимо из меню Object выбрать команду New. Затем в открывшемся диалоговом окне New Database Alias (Новый псевдоним базы данных) из списка Database Driver Name, в котором перечислены зарегистрированные в системе драйверы доступа к базам данных, нужно выбрать драйвер для создаваемой базы данных (Рисунок 17.3), т. е. фактически выбрать тип создаваемой базы данных.
При создании псевдонима по умолчанию предлагается драйвер STANDARD (default driver), который обеспечивает доступ к таблицам в формате Paradox.
Окончательный вид формы приложения Архитектурные памятники СанктПетербурга
Рисунок 17.12. Окончательный вид формы приложения Архитектурные памятники Санкт-Петербурга
В принципе, после добавления в форму компонента DBNavigator простейшая программа управления базой данных готова. Эта программа обеспечивает просмотр, редактирование, добавление новых и удаление ненужных записей.
Теперь рассмотрим, что надо сделать, чтобы в поле imagei появилось изображение памятника, информация о котором выведена в форме. Разрабатываемое приложение предполагает, что изображения (фотографии) архитектурных памятников находятся в файлах в том же каталоге, что и таблица базы данных. Во время добавления информации в базу данных пользователь вводит в поле Photo имя файла фотографии, а во время просмотра фотография автоматически появляется в поле image 1.
В листинге 17.1 приведен текст модуля программы Архитектурные памятники Санкт-Петербурга.
Памятник
ПамятникПеренос программы управления базой данных на другой компьютер
Перенос программы управления базой данных на другой компьютерДовольно часто возникает необходимость переноса созданной программы управления базой данных на другой компьютер, например, для того чтобы продемонстрировать ее своим друзьям или знакомым. В отличие от процесса переноса обычной программы, когда, как правило, достаточно скопировать только выполняемый файл (ЕХЕ-файл), при переносе программы управления базой данных необходимо выполнить перенос BDE.
Здесь следует вспомнить, что BDE представляет собой набор программ, библиотек и драйверов, обеспечивающих работу прикладной программы с базой данных. Выполнить перенос BDE на другой компьютер вручную практически невозможно.
Поэтому Borland рекомендует создавать установочную программу, которая выполнит копирование всех необходимых файлов, в том числе и компонентов BDE. В качестве средства создания установочной программы Borland настоятельно рекомендует использовать утилиту InstallShield Express, которая входит в состав всех наборов Delphi. Поставляемая с Delphi версия этой утилиты специально адаптирована к задаче переноса и настройки BDE.
Можно попытаться установить BDE вручную. Ниже перечислены файлы (их имена определены опытным путем), необходимые для работы с базой данных Paradox:
Поле
ПолеПредставление БД в виде таблицы
Рисунок 17.1. Представление БД в виде таблицыПример запроса к базе данных "Школа"
Рисунок 17.18. Пример запроса к базе данных "Школа"
Свойство SQL представляет собой список строк. Поэтому чтобы сформировать запрос во время работы программы, нужно, используя метод Add, добавить строки (SQL-инструкции) в список SQL.
Ниже приведен фрагмент кода, который формирует запрос на поиск информации о конкретном человеке (критерий выбора — содержимое поля Fam должно совпадать со значением переменной fam).
with forml.Queryl do begin
Close; // закрыть файл — результат выполнения
// предыдущего запроса
SQL.Clear; // удалить текст предыдущего запроса
// записываем новый запрос в свойство SQL
SQL.Add('SELECT Fam, Name, Class1);
SQL.Add('FROM ":Школа:school.db"');
SQL.Add('WHERE');
SQL.Add('(Fam = '" + fam + '")');
SQL.Add('ORDER BY Name, Fam');
Open; // активизируем выполнение запроса
end;
Следующая программа, ее текст приведен в листинге 17.2, а диалоговое окно — на Рисунок 17.19, демонстрирует возможность изменения запроса, точнее, критерия запроса, во время работы программы. Программа обеспечивает вывод как всего списка учеников, так и его части. Например, посредством выполнения запроса выводится информация только о конкретном ученике.
Для просмотра базы данных и результата выполнения запроса используется компонент DBGrid1, который через компонент DataSourcel взаимодействует с компонентом Table1 (при просмотре всей базы данных) или с компонентом Query (при просмотре результата выполнения запроса).
Программа управления базой данных
Программа управления базой данныхПроцесс создания программы управления базой данных рассмотрим на примере создания базы данных "Архитектурные памятники Санкт-Петербурга".
Перед тем как приступить непосредственно к разработке приложения управления базой данных, необходимо, используя утилиту Database Desktop, создать файл данных (таблицу) и добавить в нее несколько записей. В табл. 17.3 перечислены поля таблицы monuments (monuments — монументы, памятники). В таблицу monuments можно внести информацию о памятниках Санкт-Петербурга (табл. 17.4).
Просмотр базы данных
Просмотр базы данныхПользователь может просматривать базу данных в режиме формы или в режиме таблицы. В режиме формы можно видеть только одну запись, а в режиме таблицы -- несколько записей одновременно. Довольно часто эти два режима комбинируют. Краткая информация (содержимое некоторых ключевых полей) выводится в табличной форме, а при необходимости видеть содержимое всех полей записи выполняется переключение в режим формы.
Компоненты, обеспечивающие просмотр и редактирование содержимого полей базы данных, находятся на вкладке Data Controls (Рисунок 17.8).
Псевдоним базы данных
Псевдоним базы данныхРазрабатывая программу работы с базой данных, программист не может знать, на каком диске и в каком каталоге будут находиться файлы базы данных во время ее использования. Например, пользователь может поместить базу данных в один из каталогов дисков С:, D: или на сетевой диск. Поэтому возникает проблема передачи в программу информации о месте нахождения файлов базы данных.
В Delphi проблема передачи в программу информации о месте нахождения файлов базы данных решается путем использования псевдонима базы данных. Псевдоним (Alias) — это короткое имя, поставленное в соответствие реальному, полному имени каталога базы данных. Например, псевдонимом каталога C:\data\spetersburg может быть имя Peterburg. Программа работы с базой данных для доступа к данным использует не реальное имя, а псевдоним.
Для доступа к информации программа, обеспечивающая работу с базой данных, подключает библиотеку Borland Database Engine (BDE), которая, в свою очередь, использует конфигурационный файл, содержащий информацию о всех зарегистрированных в системе псевдонимах.
Псевдоним базы данных может быть создан (зарегистрирован) при помощи утилиты BDE Administrator. Эта же утилита позволяет изменить каталог, связанный с псевдонимом.
Редактор колонок
Рисунок 17.15. Редактор колонок
Для того чтобы в компонент DBGrid добавить колонку, обеспечивающую просмотр содержимого поля записи файла данных, необходимо нажать кнопку Add New, находящуюся на панели инструментов в верхней части окна (это единственная доступная после запуска редактора кнопка), выделить добавленный элемент и, используя Object Inspector, установить значения свойств этой колонки (табл. 17.16). Свойство columns компонента DBGrid представляет собой массив компонентов типа TCoiumn. Каждой колонке соответствует элемент массива. Устанавливая значения свойств компонентов column, программист задает вид колонок компонента DBGrid, тем самым определяет вид всей таблицы.
Регистрация нового псевдонима
Рисунок 17.4. Регистрация нового псевдонима
После этого нужно изменить автоматически созданное администратором имя псевдонима и задать путь к файлам базы данных, для которой создается псевдоним.
Имя псевдонима можно изменить обычным для Windows способом: щелкнуть правой кнопкой мыши на имени псевдонима (на вкладке Databases), в появившемся контекстном меню выбрать команду Rename (Переименовать) и в открывшемся диалоговом окне ввести новое имя.
Путь к файлам базы данных можно ввести на вкладке Definition в поле Path с клавиатуры или воспользоваться стандартным диалоговым окном Select Directory (Выбор каталога), которое открывается щелчком на кнопке с тремя точками, находящейся в конце поля Path.
В качестве примера на Рисунок 17.5 приведен вид, окна BDE Administrator после создания псевдонима Peterburg для базы данных "Архитектурные памятники Санкт-Петербурга".
Для того чтобы созданный псевдоним был зарегистрирован в файле конфигурации (Idapi.cfg), необходимо в меню Object выбрать команду Apply (Применить). В открывшемся диалоговом окне Confirm следует подтвердить необходимость сохранения изменений в файле конфигурации.
Режим формы
Режим формыДля того чтобы обеспечить просмотр базы данных в режиме формы, в форму приложения нужно добавить компоненты, обеспечивающие просмотр и, если нужно, редактирование содержимого полей записи, причем по одному компоненту для каждого поля.
Компонент DBText позволяет только просматривать содержимое поля, а компоненты DBEdit и DBMеmо — просматривать и редактировать. В табл. 17.9 перечислены некоторые свойства этих компонентов. Свойства перечислены в том порядке, в котором следует устанавливать их значения после добавления в форму приложения.
Режим таблицы
Режим таблицыПрограмма работы с базой данных "Архитектурные памятники Санкт-Петербурга" выводит информацию в режиме формы, в каждый момент времени пользователь может видеть только одну запись. Такой режим работы с базой данных не всегда удобен. Если необходимо видеть одновременно несколько записей базы данных, то нужно обеспечить просмотр данных в режиме таблицы.
Процесс создания приложения, обеспечивающего просмотр базы данных в режиме таблицы, рассмотрим на примере программы работы с базой данных "Школа".
Пусть база данных "Школа" (псевдоним школа), представляет собой таблицу, которая находится в файле School.db. Записи таблицы school состоят из полей: Name (Имя), Fam (Фамилия), class (Класс), Adr (Адрес) и N (Личный номер). Поля Name, Fam, class и Adr являются полями символьного типа (тип А), а поле N — числовое, с автоувеличением.
Примечание
Псевдоним Школа следует создать при помощи BDE Administrator, а таблицу (файл school.db) — при помощи Database Desktop.
Сначала в форму разрабатываемого приложения нужно добавить компоненты Table и DataSource, которые обеспечивают доступ к файлу данных, и установить значения их свойств (табл. 17.14).
Создание базы данных
Создание базы данныхБаза данных — это набор файлов (таблиц), в которых находится информация. Как правило, база данных состоит из нескольких таблиц, которые размещают в одном каталоге. Каталог для новой базы данных создается обычным образом, например, при помощи Проводника. Таблицу можно создать, воспользовавшись входящей в состав Delphi утилитой Borland Database Desktop или организовав SQL-запрос к серверу базы данных.
Так как для доступа к файлам (таблицам) базы данных библиотека BDE использует не имя каталога, в котором находятся файлы, а его псевдоним, то перед тем, как приступить к созданию таблиц новой базы данных, необходимо создать псевдоним для этой базы данных.
Таким образом, процесс создания базы данных может быть представлен как последовательность следующих шагов:
1. Создание каталога.
2. Создание псевдонима.
3. Создание таблиц.
Создание каталога
Создание каталогаКаталог (папка) для файлов базы данных создается обычным образом, например, при помощи Проводника. Обычно файлы локальной базы данных помещают в отдельном подкаталоге каталога программы работы с базой данных.
Примечание
Для дальнейшей работы с рассматриваемой в качестве примера базой данных "Архитектурные памятники Санкт-Петербурга" следует в каталоге \ Проекты создать каталог Петербург и в нем — подкаталог Data.
Создание псевдонима
Создание псевдонимаПсевдоним базы данных создается при помощи входящей в Delphi утилиты BDE Administrator, которая запускается из Windows выбором из меню Программы | Borland Delphi 7 команды BDE Administrator.
Вид диалогового окна BDE Administrator после запуска приведен на Рисунок 17.2
Создание таблицы
Создание таблицыВажным моментом при создании базы данных является распределение информации между полями записи. Очевидно, что информация может быть распределена между полями различным образом.
Например, сведения об исторических памятниках Санкт-Петербурга могут быть организованы в виде записей, состоящих из полей "Памятник" и "Историческая справка" или из полей "Памятник", "Архитектор", "Год" и "Историческая справка".
В первом варианте поле "Памятник" будет содержать название памятника, например Эрмитаж, а поле "Историческая справка" - - всю остальную информацию. При этом пользователь сможет найти информацию об интересующем его памятнике только по названию. При втором варианте организации записи пользователь сможет найти информацию о памятниках, архитектором которых является конкретный зодчий, или о памятниках, возведенных в данный исторический период.
Можно сформулировать следующее правило: если предполагается, что во время использования базы данных будет выполняться выборка информации по некоторому критерию, то информацию, обеспечивающую возможность этой выборки, следует поместить в отдельное поле.
После того как определены поля записи, необходимо выполнить распределение полей по таблицам. В простой базе данных все поля можно разместить в одной таблице. В сложной базе данных поля распределяют по нескольким таблицам, и вводом некоторой дополнительной информации, однозначно идентифицирующей каждую запись, обеспечивается связь между таблицами.
Примечание
Базы данных, состоящие из нескольких, связанных между собой таблиц, называются реляционными. В реляционных базах данных, для того чтобы избежать дублирования информации в таблицах, к основной информации добавляется некоторая служебная информация, которая однозначно идентифицирует запись. Подробное рассмотрение организации реляционных баз данных в задачу этой книги не входит. Читатель может самостоятельно ознакомиться с вопросами организации реляционных баз данных, обратившись к литературе.
После того как определена структура записей базы данных, можно приступить непосредственно к созданию таблицы. Таблицы создаются при помощи входящей в состав Delphi утилиты Database Desktop.
Утилита Database Desktop позволяет выполнять все необходимые при работе с базами данных действия. Она обеспечивает создание, просмотр и модификацию таблиц баз данных различных форматов (Paradox, dBASE, Microsoft Access). Кроме того, утилита позволяет выполнять выборку информации путем создания запросов.
Для того чтобы создать новую таблицу, нужно выбором из меню Tools команды Database Desktop запустить Database Desktop. Затем в появившемся окне утилиты Database Desktop надо из меню File выбрать команду New и в появившемся списке выбрать тип создаваемого файла — Table. Затем в открывшемся диалоговом окне Create Table следует выбрать тип создаваемой таблицы (значением по умолчанию является тип Paradox 7).
В результате открывается диалоговое окно Create Paradox 7 Table, в котором можно определить структуру записей таблицы.
Для каждого поля таблицы необходимо задать имя, тип и, если нужно, размер поля. Имя поля используется для доступа к данным. В качестве имени поля, которое вводится в колонку Field Name, можно использовать последовательность из букв латинского алфавита и цифр длиной не более 25 символов.
Тип поля определяет тип данных, которые могут быть помещены в поле. Тип задается вводом в колонку Туре символьной константы. Типы полей и соответствующие им константы приведены в табл. 17.1.
Структура базы данных
Структура базы данныхБаза данных — это набор однородной, как правило, упорядоченной по некоторому критерию, информации. База данных может быть представлена в "бумажном" или в компьютерном виде.
Типичным примером "бумажной" базы данных является каталог библиотеки — набор бумажных карточек, содержащих информацию о книгах. Информация в этой базе однородная (содержит сведения только о книгах) и упорядоченная (карточки расставлены, например, в соответствии с алфавитным порядком фамилий авторов). Другими примерами "бумажной" базы данных являются телефонный справочник и расписание движения поездов.
Компьютерная база данных представляет собой файл (или набор связанных файлов), содержащий информацию.
База данных состоит из записей. Каждая запись содержит информацию об одном экземпляре. Например, каждая запись базы данных "Архитектурные памятники Санкт-Петербурга" содержит информацию только об одном экземпляре — историческом памятнике.
Записи состоят из полей. Каждое поле содержит информацию об одной характеристике экземпляра. Например, запись базы данных "Архитектурные памятники Санкт-Петербурга" состоит из следующих полей: "Памятник", "Архитектор" и "Историческая справка", где "Памятник", "Архитектор" и "Историческая справка" — это имена полей. Содержимое этих полей характеризует конкретный памятник.
Следует обратить внимание, что каждая запись состоит из одинаковых полей. Некоторые поля могут быть не заполнены, однако они все равно присутствуют в записи.
На бумаге базу данных удобно представить в виде таблицы (Рисунок 17.1). Каждая строка таблицы соответствует записи, а ячейка таблицы — полю. При этом заголовок столбца таблицы — это имя поля, а номер строки таблицы — номер записи.
Информацию компьютерных баз данных обычно выводят на экран в виде таблиц. Поэтому в литературе довольно часто вместо словосочетания "файл данных" используется словосочетание "таблица данных" или просто "таблица".
| |
Свойство
СвойствоВ табл. 17.7 и 17.8 приведены значения свойств компонентов Table и DataSource для разрабатываемого приложения.
Тип поля определяет тип информации которая может в нем находиться
Таблица 17.1. Тип поля определяет тип информации, которая может в нем находиться| Тип |
Константа |
Содержимое поля |
||
| Alpha |
A |
Строка символов. Максимальная длина строки определяется характеристикой Size, значения которой находятся в диапазоне 1—255 |
||
| Number |
N |
Число из диапазона 10-307— 10308 с 15-ю значащими цифрами |
||
| Money |
$ |
Число в денежном формате. Цифры числа делятся на группы при помощи разделителя групп разрядов. Также выводится знак денежной единицы |
||
| Short |
S |
Целое число из диапазона -32767—32767 |
||
| Long Integer |
I |
Целое число из диапазона -2 147 483 648-2 147 483 647 |
||
| Date |
D |
Дата |
||
| Time |
Т |
Время с полуночи, выраженное в миллисекундах |
||
| Time stamp |
@ |
Время и дата |
||
| Memo |
M |
Строка символов произвольной длины. Поле типа Memo используется для хранения текстовой информации, которая не может быть сохранена в поле типа Alpha. Размер поля (1—240) определяет, сколько символов хранится в таблице. Остальные символы хранятся в файле, имя которого совпадает с именем файла таблицы, а расширение файла — mb |
||
| Formatted Memo |
F |
Строка символов произвольной длины (как у типа Memo). Имеется возможность указать тип и размер шрифта, способ оформления и цвет символов |
||
| Graphic |
G |
Графика |
||
| Logical |
L |
Логическое значение "истина" (True) или "ЛОЖЬ" (False) |
||
| Auto-increment |
+ |
Целое число. При добавлении к таблице очередной записи в поле записывается число на единицу большее, чем находится в соответствующем поле последней добавленной записи |
||
Значения свойств компонентов Tablel И DataSourcel
Таблица 17.10. Значения свойств компонентов Tablel И DataSourcel| Свойство |
Значение |
Комментарий |
||
| Tablel . DatabaseName |
Peterburg |
Псевдоним базы данных (создается утилитой BDE Administrator) |
||
| Tablel . TableName |
monuments . db |
Так как значению свойства Active
Таблица 17.11. Значения свойств компонентов DBEdit1 -DBEdit3 и DBMemo1| Свойство |
Компонент |
|||||
| DBEdit1 |
DBEdit2 |
DBEdit3 |
DBMemo1 |
|||
| DataSource |
DataSource1 |
DataSource1 |
DataSource1 |
DataSource1 |
||
| DataFieid |
Monument |
Architect |
Photo |
Note |
||
Кроме компонентов просмотра-редактирования полей базы данных, в форму нужно добавить компонент image, который используется для просмотра иллюстраций, и четыре компонента Label для вывода пояснительного текста. свойству Visible компонентов Image1, Label4 и DBEdit3 следует присвоить значение False.
Теперь, если откомпилировать и запустить программу, на экране появится форма, в полях которой будет находиться содержимое первой записи файла данных.
Для того чтобы иметь возможность просматривать другие записи файла данных, в форму приложения нужно добавить компонент DBNavigator, значок которого находится на вкладке Data Controls (Рисунок 17.10). Компонент DBNavigator (Рисунок 17.11) представляет собой набор кнопок, при щелчках на которых во время работы программы происходит перемещение указателя текущей записи к следующей, предыдущей, первой или последней записи базы данных, а также добавление к файлу данных новой записи, удаление текущей записи.
Кнопки компонента DBNavigator
Таблица 17.12. Кнопки компонента DBNavigator| Кнопка |
Обозначение |
Действие |
|||
Свойства компонента DBNavigator
Таблица 17.13. Свойства компонента DBNavigator
| Свойство |
Определяет |
||
| VisibleButton3 | Видимые командные кнопки | ||
| Name DataSource |
Имя компонента. Используется для доступа к свойствам компонента Имя компонента, являющегося источником данных. В качестве источника данных может выступать база данных (компонент Database), таблица (компонент Table) или результат выполнения запроса (компонент Query) |
||
На Рисунок 17.12 приведен вид формы приложения Архитектурные памятники Санкт-Петербурга после добавления компонента DBNavigator. Свойству DataSource компонента DBNavigator1 следует присвоить значение Table1.
в форму приложения надо добавить
Таблица 17.14. Значения свойств компонентов Table1 и DataSource1| Свойство |
Значение |
||
| Tablel . DatabaseName Tablel . TableName Tablel. Active DataSourcel . Dataset |
Школа school . db True Tablel |
||
Свойства компонента DBGrid
Таблица 17.15. Свойства компонента DBGrid| Свойство |
Определяет |
||
| Name |
Имя компонента |
||
| DataSource |
Источник отображаемых в таблице данных |
||
| Columns |
Отображаемую в таблице информацию |
||
| Options . dgTitles |
Разрешает вывод строки заголовка столбцов |
||
| Options . dgIndicator |
Разрешает вывод колонки индикатора. Во время работы с базой данных текущая запись помечается в колонке индикатора треугольником, новая запись — звездочкой, редактируемая — специальным значком |
||
| Options . dgColumnResize |
Разрешает менять во время работы программы ширину колонок таблицы |
||
| Options . dgColLines |
Разрешает выводить линии, разделяющие колонки таблицы |
||
| Options . dgRowLines |
Разрешает выводить линии, разделяющие строки таблицы |
||
Свойства компонента column
Таблица 17.16. Свойства компонента column| Свойство |
Определяет |
||
| FieldName |
Поле записи, содержимое которого выводится в колонке |
||
| Width |
Ширину колонки в пикселах |
||
| Font |
Шрифт, используемый для вывода текста в ячейках колонки |
||
| Color |
Цвет фона колонки |
||
| Alignment |
Способ выравнивания текста в ячейках колонки. Текст может быть выровнен по левому краю (taLeftJustify), по центру (taCenter) или по правому краю (taRight Justify) |
||
| Title. Caption |
Заголовок колонки. Значением по умолчанию является имя поля записи |
||
| Title .Alignment |
Способ выравнивания заголовка колонки. Заголовок может быть выровнен по левому краю (taLeftJustify), по центру (taCenter) или по правому краю (taRight Justify) |
||
| Title. Color |
Цвет фона заголовка колонки |
||
| Title. Font |
Шрифт заголовка колонки |
||
Значения свойств компонента
Таблица 17.17. Значения свойств компонента DBGrid1Свойства компонента Query
Таблица 17.18. Свойства компонента Query| Свойство |
Определяет |
||
| Name SQL Active |
Имя компонента. Используется компонентом Datasource для связи результата выполнения запроса (набора записей) с компонентом, обеспечивающим просмотр записей, например DBGrid Записанный на языке SQL запрос к базе данных (к таблице) При присвоении свойству значения True активизирует выполнение запроса |
||
В общем виде запрос на выборку из таблицы данных выглядит так:
SELECT Список-Полей FROM
Специальные символы используемые при записи шаблонов
Таблица 17.2. Специальные символы, используемые при записи шаблонов| Символ шаблона |
Допустимый при вводе символ |
||
| * & @ *. |
Цифра Любая буква (прописная или строчная) Любая буква (автоматически преобразуется в прописную) Любая буква (автоматически преобразуется в строчную) Любой символ Любой символ (если введена буква, то она автоматически преобразуется в прописную) Символ, следующий за символом "точка с запятой", интерпретируется как обычный символ, а не символ шаблона Любое количество повторяющихся, определяемых следующим за "звездочкой" символом шаблона |
||
Шаблоны позволяют не только контролировать правильность вводимых в поле данных путем блокирования ввода неверных символов, но и обеспечивают автоматизацию ввода данных. Это достигается путем указания в шаблоне в квадратных или фигурных скобках списка допустимых значений содержимого поля.
Например, если для поля Address задать шаблон {Санкт-Петербург, Москва, Воронеж}*@ или [Санкт-Петербург, Москва, Воронеж]*@, то во время ввода данных в это поле название соответствующего города будет появляться сразу после ввода одной из букв: с, м или в. Отличие фигурных скобок от квадратных и, следовательно, этих шаблонов друг от друга состоит в том, что в первом шаблоне содержимое поля обязательно должно начинаться с названия одного из перечисленных в списке городов, а во втором — город может называться по-другому, однако его название придется вводить полностью.
После того как будет определена структура таблицы, таблицу следует сохранить. Для этого необходимо нажать кнопку Save As. В результате открывается окно Save Table As. В этом окне из списка Alias нужно выбрать псевдоним базы данных, частью которой является созданная таблица, а в поле Имя файла ввести имя файла, в котором нужно сохранить созданную таблицу.
Если перед тем как нажать кнопку Сохранить установить флажок Display table, то в результате нажатия кнопки Сохранить открывается диалоговое окно Table , в котором можно ввести данные в только что созданную таблицу.
Если таблица базы данных недоступна, то для того чтобы ввести данные в таблицу, таблицу нужно открыть. Для этого надо из меню File выбрать команду Open | Table, затем в появившемся диалоговом окне Open table в списке Alias выбрать псевдоним нужной базы данных и таблицу. Следует обратить внимание, что таблица будет открыта в режиме просмотра, в котором изменить содержимое таблицы нельзя. Для того чтобы в таблицу можно было вводить данные, нужно активизировать режим редактирования таблицы, для чего необходимо из меню Table выбрать команду Edit Data.
Данные в поля записи вводятся с клавиатуры обычным образом. Для перехода к следующему полю нужно нажать клавишу
Если во время заполнения таблицы необходимо внести изменения в какое-то уже заполненное поле, то следует выбрать это поле, воспользовавшись клавишами перемещения курсора, нажать клавишу
Если при вводе данных в таблицу буквы русского алфавита отображаются неверно, то надо изменить шрифт, используемый для отображения данных. Для этого необходимо в меню Edit выбрать команду Preferences и в появившемся диалоговом окне, во вкладке General, щелкнуть на кнопке Change. В результате этих действий откроется диалоговое окно Change Font, в котором нужно выбрать русифицированный шрифт. Следует обратить внимание, что в Windows 2000 (Windows XP) используются шрифты типа Open Type, в то время как программа Database Desktop ориентирована на работу со шрифтами TrueType. Поэтому в списке шрифтов нужно выбрать русифицированный шрифт именно TrueType. После этого надо завершить работу с Database Desktop, так как внесенные в конфигурацию изменения будут действительны только после перезапуска утилиты.
Памятники СанктПетербурга
Таблица 17.4. Памятники Санкт-Петербурга| Памятник |
Архитектор |
Историческая справка |
Иллюстрация |
||
| Адмиралтейство |
А. Д. Захаров |
Здание Адмиралтейства таким, как оно выглядит сейчас, стало после перестройки в 1806—1823 годах. Автор проекта — гениальный русский зодчий А. Д. Захаров. Высота шпиля: 72 метра |
admiral.bmp |
||
| Александровская колонна |
Огюст Монферран |
Памятник победы России над войсками Наполеона в Отечественной войне 1812 года. Открыта 30 августа 1 834 года. Высота: 47,5 метра; вес гранитного ствола: 600 тонн |
aleks.bmp |
||
| Зимний дворец |
Ф. Б. Растрелли |
Зимний дворец много раз менял свой облик. Последний раз он перестраивался по проекту Растрелли. Строительство дворца продолжалось более семи лет (1754— 1 762 годы) |
herm.bmp |
||
| Памятник |
Архитектор |
Историческая справка |
Иллюстрация |
||
| Исаакиевский собор |
Огюст Монферран |
Исаакиевский собор, четвертый по счету, стали возводить в 1818 году. Строился собор 40 лет и был окончен в 1 858 году. Автор проекта— Огюст Монферран |
isaak.bmp |
||
| Ростральные |
Тома де Томон |
32-метровые ростральные ко- |
rostr.bmp |
||
| колонны |
|
лонны, органично вошедшие в архитектурный ансамбль Стрелки Васильевского острова, были сооружены в 1810 году. Они напоминают о существовавшем в древнем Риме обычае: украшать триумфальные колонны рострами захваченных кораблей |
|
||
На прилагаемой к книге дискете есть файлы, содержащие изображения исторических памятников Санкт-Петербурга.
Теперь можно приступить к разработке приложения. Методика разработки приложения работы с базой данных ничем не отличается от методики создания обычной программы: к форме добавляются необходимые компоненты, устанавливаются значения свойств компонентов, разрабатываются необходимые процедуры обработки событий.
Приложение работы с базой данных должно содержать компоненты, обеспечивающие доступ к данным, возможность просмотра и редактирования содержимого полей. Компоненты доступа к данным находятся на вкладке Data Access палитры компонентов, а компоненты отображения данных — на вкладке Data Controls.
Свойства компонента Table
Таблица 17.5. Свойства компонента Table| Свойство |
Определяет |
||
| Name Database NameTable Name Table Type Active |
Имя компонента. Используется для доступа к свойствам компонента Имя базы данных, частью которой является таблица (файл данных), для доступа к которой используется компонент. В качестве значения свойства следует использовать псевдоним базы данных Имя файла данных (таблицы данных), для доступа к которому используется компонент Тип таблицы. |
Значения свойств компонента Table
Таблица 17.7. Значения свойств компонента Table| Свойство |
Значение |
||
| Name |
Table1 |
||
| DatabaseName |
Peterburg |
||
| TableName |
monuments . db |
||
| Active |
True |
||
Значения свойств компонента DataSource
Таблица 17.8. Значения свойств компонента DataSource| Свойство |
Значение |
||
| Name DataSet |
DataSourcel Table1 |
||
Свойства компонентов DBText DBEdit и DBMеmо
Таблица 17.9. Свойства компонентов DBText, DBEdit и DBMеmо| Свойство |
Определяет |
||
| Name DataSource DataField |
Имя компонента. Используется для доступа к свойствам компонента Компонент-источник данных Поле базы данных, для отображения или редактирования которого используется компонент |
||
Таблица базы данных (создается утилитой Database Desktop)
Таблица базы данных (создается утилитой Database Desktop)компонент овмето — для просмотра и редактирования поля Note. Значения свойств компонентов просмотра-редактирования полей базы данных приведены в табл. 17.11.
Таблица может быть набором данных
Таблица может быть набором данных в формате Paradox ("Paradox), dBase (ttDBase), FoxPro ("FoxPro) или представлять собой форматированный текстовый файл (ttASCII).Признак активизации файла данных (таблицы). В результате присваивания свойству значения True происходит открытие файла таблицы
Таблица WHERE (Критерий) ORDER BY СписокПолей
Таблица WHERE (Критерий) ORDER BY СписокПолейгде:
SELECT Fam, Name FROM ':Школа:school.db' WHERE
(Class = '10a') ORDER BY Name, Fam
обеспечивает выборку из базы данных "Школа" (из таблицы School.db) записей, у которых в поле class находится текст 10а, т. е. формирует упорядоченный по алфавиту список учеников 10-а класса.
Другой пример. Запрос
SELECT Fam, Name FROM ":Школа:school.db" WHERE
(Fam > 'K') and (Fam < 'Л') ORDER BY Name, Fam
обеспечивает выбор информации об учениках, фамилии которых начинаются на букву К.
Запрос может быть сформирован и записан в свойство SQL во время разработки формы или во время работы программы.
Для записи запроса в свойство SQL во время разработки формы используется редактор списка строк (Рисунок 17.18), окно которого открывается в результате щелчка на кнопке с тремя точками в строке свойства SQL окна Object Inspector.
Тип
ТипОдно или несколько полей можно пометить как ключевые. Ключевое поле определяет логический порядок следования записей в таблице. Например, если символьное (тип Alpha) поле Fam (Фамилия) пометить как ключевое, то при выводе таблицы записи будут упорядочены в соответствии с алфавитным порядком фамилий. Если поле Fam не помечать как ключевое, то записи будут выведены в том порядке, в котором они были введены в таблицу. Следует обратить внимание на то, что в таблице не может быть двух записей с одинаковым содержимым ключевых полей. Поэтому в рассматриваемом примере ключевыми полями должны быть поля Fam (Фамилия) и Name (Имя). Тогда в таблицу можно будет ввести информацию об однофамильцах. Однако по-прежнему нельзя будет ввести однофамильцев, у которых совпадают имена. Поэтому в качестве ключевого поля обычно выбирают поле, которое содержит уникальную информацию. Для таблицы, содержащей список людей, в качестве ключевого можно выбрать поле Pasp (Паспорт).
Для того чтобы пометить поле как ключевое, необходимо выполнить двойной щелчок в колонке Key. Следует обратить внимание на то, что ключевые поля должны быть сгруппированы в верхней части таблицы.
Если данные, для хранения которых предназначено поле, должны обязательно присутствовать в записи, то следует установить флажок Required Field. Например, очевидно, что поле Fam (Фамилия) обязательно должно быть заполнено, в то время как поле Tel (Телефон) может оставаться пустым.
Если значение, записываемое в поле, должно находиться в определенном диапазоне, то вводом значений в поля Minimum value (Минимальное значение) и Maximum value (Максимальное значение) можно задать границы диапазона.
Поле Default value позволяет задать значение по умолчанию, которое будет автоматически записываться в поле при добавлении к таблице новой записи.
Поле Picture позволяет задать шаблон, используя который можно контролировать правильность вводимой в поле информации. Шаблон представляет собой последовательность обычных и специальных символов. Специальные символы перечислены в табл. 17.2.
Во время ввода информации в позицию поля, которой соответствует специальный символ, будут появляться только символы, допустимые для данного символа шаблона. Например, если в позиции шаблона стоит символ #, то в соответствующую этому символу позицию можно ввести только цифру. Если в позиции шаблона стоит обычный символ, то во время ввода информации в данной позиции будет автоматически появляться указанный символ.
Например, пусть поле Tel типа А (строка символов) предназначено для хранения номера телефона, и программа, работающая с базой данных, предполагает, что номер телефона должен быть представлен в обычном виде, т. е. в виде последовательности сгруппированных, разделенных дефисами цифр. В этом случае в поле Picture следует записать шаблон: ###-##-##. При вводе информации в поле Tel будут появляться только цифры (нажатия клавиш с другими символами игнорируются), причем после ввода третьей и пятой цифр в поле будут автоматически добавлены дефисы.
Удаленная база данных
Удаленная база данныхДанные (файлы) удаленной базы данных находятся на удаленном компьютере. (Следует обратить внимание, что каталоги удаленного компьютера не могут рассматриваться как сетевые диски.)
Программа работы с удаленной базой данных состоит из двух частей: клиентской и серверной. Клиентская часть программы, работающая на компьютере пользователя, обеспечивает взаимодействие с серверной программой: посредством запросов, передаваемых на удаленный компьютер, предоставляет доступ к данным.
Серверная часть программы, работающая на удаленном компьютере, принимает запросы, выполняет их и пересылает данные клиентской программе. Запросы представляют собой команды, представленные на языке SQL (Structured Query Language) — языке структурированных запросов.
Программа, работающая на удаленном сервере, проектируется таким образом, чтобы обеспечить одновременный доступ к информации нескольким пользователям. При этом для обеспечения доступа к данным вместо механизма блокировки файлов используют механизм транзакций.
Транзакция — это некоторая последовательность действий, которая должна быть обязательно выполнена над данными перед тем, как они будут переданы. В случае обнаружения ошибки во время выполнения любого из действий вся последовательность действий, составляющая транзакцию, повторяется снова. Таким образом, механизм транзакций обеспечивает защиту от аппаратных сбоев. Он также обеспечивает возможность многопользовательского доступа к данным.
Разработка программы работы с удаленной базы данных — сложная и трудоемкая задача. Ее решение предполагает наличие у разработчика глубоких знаний и большого опыта разработки программного обеспечения. Поэтому в данной книге задача разработки удаленных баз данных не рассматривается.
Выбор информации из базы данных
Выбор информации из базы данныхПри работе с базой данных пользователя, как правило, интересует не все ее содержимое, а некоторая конкретная информация. Найти нужные сведения можно последовательным просмотром записей. Однако такой способ поиска неудобен и малоэффективен.
Большинство систем управления базами данных позволяют произвести выборку нужной информации путем выполнения запросов. Пользователь в соответствии с определенными правилами формулирует запрос, указывая, каким критериям должна удовлетворять интересующая его информация, а система выводит записи, удовлетворяющие запросу.
Для выборки из базы данных записей, удовлетворяющих некоторому критерию, предназначен компонент Query (Рисунок 17.17).
Взаимодействие компонентов отображения и доступа к данным
Рисунок 17.7. Взаимодействие компонентов отображения и доступа к данным
В простейшем случае, когда база данных представляет собой одну-единственную таблицу, приложение работы с базой данных должно содержать один компонент Table и один компонент DataSource.
В табл. 17.5 перечислены свойства компонента Table, а в табл. 17.6 — свойства компонента DataSource. Свойства перечислены в том порядке, в котором следует устанавливать их значения после добавления компонентов в форму приложения.
Значок компонента DBNavigator находится на вкладке Data Controls
Рисунок 17.10. Значок компонента DBNavigator находится на вкладке Data Controls
Значок компонента Query
Рисунок 17.17. Значок компонента Query
Компонент Query похож на компонент Table, но, в отличие от последнего, он представляет не всю базу данных (все записи), а только ее часть — записи, удовлетворяющие критерию запроса.
В табл. 17.18 перечислены некоторые свойства компонента Query.
Отладка программы в Delphi
Активизация создантя образа установочного CDROM
Рисунок 18.18. Активизация создантя образа установочного CD-ROM
/B> В левой части окна проекта
Рисунок 18.2. В левой части окна проекта перечислены этапы и команды процесса создания инсталляционной программы
Команды настройки объединены в группы, название и последовательность которых отражает суть процесса создания инсталляционной программы. Заголовки групп пронумерованы. Настройка программы установки выполняется путем последовательного выбора команд. В результате выбора команды в правой части главного окна появляется список параметров. Команды, которые были выполнены, помечаются галочками.
Ярлык создан теперь можно выполнить его настройку
Рисунок 18.12. Ярлык создан, теперь можно выполнить его настройку
Команда Setup Types позволяет задать возможные варианты установки программы
Рисунок 18.5. Команда Setup Types позволяет задать возможные варианты установки программы
Команды группы Configure the Target System
Рисунок 18.9. Команды группы Configure the Target System
Команда Shortcuts/Folders позволяет указать, куда нужно поместить ярлык, обеспечивающий запуск устанавливаемой программы. В результате выбора этой команды в правой части окна открывается иерархический список, в котором перечислены меню и папки, куда можно поместить ярлык программы. В этом списке необходимо выбрать меню, в которое должен быть помещен ярлык, щелкнуть правой кнопкой мыши и в появившемся списке выбрать команду New Shortcut (Рисунок 18.10).
Команды группы Customize the Setup Appearance
Рисунок 18.13. Команды группы Customize the Setup Appearance
Команды группы Define Setup Requirements and Actions
Рисунок 18.15. Команды группы Define Setup Requirements and Actions
В результате выбора команды Requirements на экране появляется таблица (Рисунок 18.16), в которую надо ввести значения параметров, характеризующих систему: версию операционной системы (OS Version), тип процессора (Processor), объем оперативной памяти (RAM), разрешение экрана (Screen Resolution) и цветовую палитру (Color Depth). Значения характеристик задаются путем выбора из раскрывающегося списка, значок которого появляется в результате щелчка в поле значения параметра.
Команды группы Organize Your Setup
Рисунок 18.3. Команды группы Organize Your Setup
Значения большинства параметров, за исключением тех, которые идентифицируют устанавливаемую программу и ее разработчика, можно оставить без изменения. Параметры, значения которых нужно изменить, приведены в табл. 18.2.
Команды группы Prepare for Release
Рисунок 18.17. Команды группы Prepare for Release
Для того чтобы активизировать процесс создания образа установочного диска (CD-ROM), нужно выбрать команду Build Your Release, щелкнуть правой кнопкой мыши на значке носителя, на который предполагается поместить программу установки, и из появившегося контекстного меню выбрать команду Build (Рисунок 18.18).
В результате этих действий на диске компьютера в папке проекта будет создан образ установочного диска. Если в качестве носителя выбран CD-ROM, то образ будет помещен в подкаталог \Express\Cd_rom\DiskImages\Disk1.
Команды группы Specify Application Data
Рисунок 18.6. Команды группы Specify Application Data
В результате выбора команды Files правая часть окна будет разделена на области (Рисунок 18.7). В области Source computer's files можно выбрать файлы, которые необходимо перенести на компьютер пользователя. В области Destination computer's folders надо выбрать папку, в которую эти файлы должны быть помещены. Для того чтобы указать, какие файлы нужно установить на компьютер пользователя, следует просто "перетащить" требуемые файлы из области Source computer's files в область Destination computer's files. Если в группе Features несколько элементов, то надо определить файлы для каждого элемента.
Конфигурирование системы пользователя
Конфигурирование системы пользователяКоманды группы Configure the Target System (Рисунок 18.9) позволяют задать, какие изменения нужно внести в систему пользователя, чтобы настроить систему на работу с устанавливаемой программой.
Начало работы над новым проектом
Рисунок 18.1. Начало работы над новым проектом
После щелчка на кнопке ОК открывается окно проекта создания инсталляционной программы (Рисунок 18.2). В левой части окна перечислены этапы процесса создания и команды, при помощи которых задаются параметры создаваемой инсталляционной программы.
Настройка диалогов
Настройка диалоговДля взаимодействия с пользователем программа установки использует стандартные диалоговые окна. Разрабатывая программу инсталляции, программист может задать, какие диалоги увидит пользователь в процессе инсталляции программы.
Чтобы задать диалоговые окна, которые будут появляться на экране монитора во время работы инсталляционной программы, надо в группе Customize the Setup Appearance (Рисунок 18.13) выбрать команду Dialogs и в открывшемся списке Dialogs (Рисунок 18.14) отметить диалоги, которые нужно включить в программу установки.
Несколько элементов в группе Features обеспечивают возможность многовариантной установки
Рисунок 18.4. Несколько элементов в группе Features обеспечивают возможность многовариантной установки
Команда Setup Types позволяет задать, будет ли пользователю во время установки программы предоставлена возможность выбрать (в диалоговом окне Setup Type) вариант установки. Установка может быть обычной (Typical), минимальной (Minimal) или выборочной (Custom). Если устанавливаемая программа сложная, состоит из нескольких независимых компонентов, то эта возможность обычно предоставляется.
Для программы Сапер 2002 предполагается только один вариант установки — Typical. Поэтому флажки Minimal и Custom нужно сбросить (Рисунок 18.5).
Новый проект
Новый проектПосле того как будет составлен список файлов, нужно запустить InstallShield Express, из меню File выбрать команду New и в поле Project Name and Location ввести имя файла проекта (Рисунок 18.1).
Параметры характеризующие систему
Рисунок 18.16. Параметры, характеризующие систему
Если программа не предъявляет особых требований к конфигурации системы, то команды группы Define Setup Requirements and Actions можно пропустить.
Программа InstallShield Express
Программа InstallShield ExpressОдним из популярных инструментов создания инсталляционных программ является пакет InstallShield Express. Borland настоятельно рекомендует использовать именно эту программу, поэтому она есть на установочном диске Borland Delphi 7 Studio.
Процесс установки программы InstallShield Express обычный. Для того чтобы его активизировать, нужно запустить программу установки Delphi (вставить установочный CD-ROM в дисковод) и в открывшемся диалоговом окне Delphi Setup Launcher выбрать команду InstallShield Express — Borland Limited Edition. В результате этого будет запущен мастер установки. По завершении процесса установки в меню Пуск | Программы | InstallShield появляется команда Express, выбор которой запускает InstallShield Express.
Процесс создания инсталляционного диска (CD-ROM) при помощи InstallShield Express рассмотрим на примере.
Пусть нужно создать инсталляционный диск для программы Сапер 2002. Перед тем как непосредственно приступить к созданию установочной программы в InstallShield Express, нужно выполнить подготовительную работу — составить список файлов, которые должны быть установлены на компьютер пользователя; используя редактор текста, подготовить RTF-файлы лицензионного соглашения (EULA — End User Licensia Agreement) и краткой справки (Readme-файл). Список файлов программы Сапер 2002, которые должны быть перенесены на компьютер пользователя, приведен в табл. 18.1.
Псевдоним
Псевдоним[Windows Folder]
[SystemFolder]
[ProgramFilesFolder]
[PersonalFolder]
Каталог Windows, например C:\Winnt
Системный каталог Windows, например C:\Winnt\System32
Каталог программ, например C:\Program Files
Папка Мои документы на рабочем столе (расположение папки зависит от версии ОС и способа входа в систему)
В простейшем случае группа Features состоит из одного элемента Always Install. Чтобы добавить элемент в группу Features, нужно щелкнуть правой кнопкой мыши на слове Features, из появившегося контекстного меню выбрать команду New Feature Ins и ввести имя новой группы, например Help Files and Samples. После этого в поле Description следует ввести краткую характеристику элемента, а в поле Comments — комментарий (Рисунок 18.4).
Выбор файлов которые нужно перенести на компьютер пользователя
Рисунок 18.7. Выбор файлов, которые нужно перенести на компьютер пользователя
Команда Object/Merge Modules позволяет задать, какие объекты, например динамические библиотеки или пакеты компонентов, должны быть помещены на компьютер пользователя и, следовательно, на установочную дискету. Объекты, которые нужно поместить на установочную дискету, выбираются в списке InstallShield Objects/Merge Modules (Рисунок 18.8).
Системные требования
Системные требованияЕсли устанавливаемая программа предъявляет определенные требования к ресурсам системы, то, используя команды группы Define Setup Requirements and Actions (Рисунок 18.15), эти требования можно задать.
Создание образа установочного диска
Создание образа установочного дискаКоманды группы Prepare for Release (Рисунок 18.17) позволяют создать образ установочного диска (CD-ROM) и проверить, как работает программа установки.
Структура
СтруктураКоманды группы Organize Your Setup (Рисунок 18.3) позволяют задать структуру программы установки.
Файлы программы Сапер 2002 которые нужно установить на компьютер пользователя
Таблица 18.1. Файлы программы Сапер 2002, которые нужно установить на компьютер пользователя| Файл |
Назначение |
Куда устанавливать |
||
| Saper.exe Saper.chm Readme.rtf Eula.rtf |
Программа Файл справочной информации Краткая справка о программе Лицензионное соглашение |
Program Files\Saper 2002 Program Files\Saper 2002 Program Files\Saper 2002 Program Files\Saper 2002 |
||
Параметры команды General Information
Таблица 18.2. Параметры команды General Information| Параметр |
Определяет |
Значение |
||
| Product Name |
Название устанавливаемой программы |
Saper 2002 |
||
| Product Version |
Версия устанавливаемой программы |
1.01.0001 |
||
| INSTALLDIR |
Каталог компьютера пользователя, в который будет установлена программа |
[ProgramFiiesFolder] Saper 2002 |
||
Другие псевдонимы, которые используются в программе InstallShield Express, приведены в табл. 18.3
Некоторые псевдонимы каталогов Windows
Таблица 18.3. Некоторые псевдонимы каталогов WindowsДиалоговые окна процесса установки
Таблица 18.4. Диалоговые окна процесса установки| Диалоговое окно |
Назначение |
||
| Splash Bitmap |
Вывод иллюстрации, которая может служить в качестве информации об устанавливаемой программе. Размер иллюстрации — 465x281 пиксел, формат — BMP |
||
| Install Welcome |
Вывод информационного сообщения на фоне иллюстрации (размер 499x312 пикселов) |
||
| License Agreement |
Вывод находящегося в RFT-файле лицензионного сообщения. Позволяет прервать процесс установки программы в случае несогласия пользователя с предлагаемыми условиями |
||
| Readme |
Вывод краткой информации об устанавливаемой программе |
||
| Customer Information |
Запрашивает информацию о пользователе (имя, название организации) и, возможно, серийный номер устанавливаемой копии |
||
| Destination Folder |
Предоставляет пользователю возможность изменить предопределенный каталог, в который устанавливается программа |
||
| Database Folder |
Предоставляет пользователю возможность изменить предопределенный каталог, предназначенный для баз данных |
||
| Setup Type |
Предоставляет пользователю возможность выбрать тип установки программы (Typical — обычная установка, Minimal — минимальная установка, Custom — выборочная установка) |
||
| Custom Setup |
Предоставляет пользователю возможность выбрать устанавливаемые компоненты при выборочной (Custom) установке |
||
| Setup Complete Success | Информирует пользователя о завершении процесса установки. Позволяет задать программу, которая должна быть запущена после завершения установки (как правило, это сама установленная программа), а также возможность вывода содержимого Readme-срайла. | ||
| Setup Progress |
Показывает процент выполненной работы во время установки программы | ||
| Ready to Install |
Вывод информации, введенной пользователем на предыдущих шагах, с целью ее проверки перед началом непосредственной установки программы |
||
В простейшем случае программа инсталляции может ограничиться выводом следующих диалогов:
В списке Dialogs нужно отметить
Рисунок 18.14. В списке Dialogs нужно отметить диалоги, которые должны появиться в процессе установки программы на компьютер пользователя
В таблице Properties (справа от списка диалогов) перечислены свойства выбранного диалога. Программист может изменить значение этих свойств и, тем самым, выполнить настройку диалога. Например, для диалога Readme нужно задать имя файла (свойство Readme File), в котором находится краткая справка об устанавливаемой программе.
Для большинства диалогов можно определить баннер (свойство Banner Bitmap) — иллюстрацию, которая отображается в верхней части окна диалога. Формат файла баннера — BMP, размер — 499x58 пикселов.
В табл. 18.4 перечислены диалоговые окна, которые могут появиться во время работы инсталляционной программы.
В списке Shortcuts нужно выбрать меню в которое должен быть помещен ярлык запуска программы
Рисунок 18.10. В списке Shortcuts нужно выбрать меню, в которое должен быть помещен ярлык запуска программы
Затем, в диалоговом окне Browse for Shortcut Target, нужно выбрать файл программы (Рисунок 18.11), щелкнуть на кнопке Open и ввести имя ярлыка. После этого можно выполнить окончательную настройку ярлыка, например, в поле Arguments ввести параметры командной строки, а в поле Working Directory — рабочий каталог (Рисунок 18.12).
Выбор файла для которого создается ярлык
Рисунок 18.11. Выбор файла, для которого создается ярлык
Выбор объектов которые должны быть установлены на компьютер пользователя
Рисунок 18.8. Выбор объектов, которые должны быть установлены на компьютер пользователя
Выбор устанавливаемых компонентов
Выбор устанавливаемых компонентовКоманды группы Specify Application Data (Рисунок 18.6) позволяют определить компоненты программы, которые должны быть установлены на компьютер пользователя. Если в проекте определены несколько групп компонентов (см. команду Features), то нужно определить компоненты для каждой группы.
Программирование: Языки - Технологии - Разработка
- Программирование
- Технологии программирования
- Разработка программ
- Работа с данными
- Методы программирования
- IDE интерфейс
- Графический интерфейс
- Программирование интерфейсов
- Отладка программ
- Тестирование программ
- Программирование на Delphi
- Программирование в ActionScript
- Assembler
- Basic
- Pascal
- Perl
- VBA
- VRML
- XML
- Ada
- Lisp
- Python
- UML
- Форт
- Языки программирования