Консультация № 178204
04.05.2010, 20:46
0.00 руб.
0 2 1
огромная просьба! помогите с решением задач из лабораторной, в делфи я полный ноль! Текст лабораторной в приложении, а задания вот:
1. Сохранение данных блокнота.
a) Модифицируйте код приложения так, чтобы вопрос «Сохранить изменения?» появлялся только, если данные блокнота были изменены.
b) После щелчка по системной кнопке закрытия формы (крестик в правом верхнем углу формы), форма закрывается без предупреждения о необходимости сохранить данные блокнота. Исправьте этот недостаток.
2. Считывание данных в блокнот.
a) При запуске приложения страницы заполняются данными из файлов.
b) Создайте модальное окно выбора папки для сохранения (и считывания) данных блокнота. Модифицируйте код приложения так, чтобы при запуске появлялось модальное окно для выбора папки, в которой хранятся данные.
Примечание. Используйте компоненты DriveComboBox, DirectoryListBox, FileListBox, FilterComboBox со страницы Win 3.1 палитры компонентов.
3. Данные блокнота хранятся в восьми файлах – это не является рациональным с точки зрения компактности данных. Продумайте структуру файла для хранения записей блокнота и внесите необходимые изменения в программный код.


Приложение:
Лабораторная:

(также залил в doc формате на http://slil.ru/29080320, там с изображениями)

Упражнение 1. Создадим программу “Блокнот” с использованием классов – потомков TStrings. Блокнот будет содержать 8 страничек, соответствующих первым буквам записи (АБВ, ГДЕЖ, и т.д.).
Решение
Создайте новый проект. Сохраните новое приложение в папке NoteBook – файл модуля под именем Main.pas, файл проекта – Notebook.dpr.
1-й этап визуальное проектирование. Измените заголовок формы (свойство Caption) на ‘Блокнот’, а значение свойства Name – на NoteBookF.
Поместите на форму компонент NoteBook (блокнот) со страницы Win3.1 палитры компонентов.
Создадим страницы компонента NoteBook, используя свойство Pages (страницы) в инспекторе объектов. При выборе этого свойства, на экране появится диалоговое окно. Создайте в нём список страниц (для этого воспользуйтесь кнопкой Add диалогового окна). После того, как список создан, нажмите на кнопку Close. Поместите компонент TabSet (список закладок) со страницы Win3.1 под компонентом NoteBook. Сделайте эти компоненты одинаковой ширины.
Положим на каждую страницу компонента NoteBook компонент ListBox (окно списка) для размещения записей на каждой странице. Для этого выполните действия:
1. У компонента NoteBook выберите свойство ActivePage (активная страница) и установите значение равное ‘АБВ’. В палитре компонентов на странице Standard выберите компонент ListBox и поместите в компонент NoteBook.
2. Повторите те же действия для всех остальных страниц NoteBook, изменяя свойство ActivePage.
3. Выберите все 8 компонентов ListBox с помощью Active TreeView (окно, расположенное выше окна инспектора объектов) и установите для них свойство Align в alClient.
Итак, сейчас для каждой страницы блокнота существует свой компонент ListBox: для АБВ – ListBox1, для ГДЕЖ – ListBox2 и т. д.
В левой части формы поместим компоненты, позволяющие вводить информацию на страницы блокнота. Со страницы Standard палитры компонентов выберите компонент Panel, на который положите один компонент Label, один компонент Edit и три компонента Button.

Установите свойства компонентов следующим образом:
Компонент Свойство Значение
Panel1 Caption ‘’
Label1 Caption ‘Введите сообщение’
Edit1 Name RecordEdt
Text ‘’
Button1 Name AddBtn
Caption Добавить
Button2 Name ChangeBtn
Caption Изменить
Button3 Name DeleteBtn
Caption Удалить
Поместите еще 2 компонента Button в правой нижней части формы и измените свойства следующим образом:
Компонент Свойство Значение
Button1 Name ClearBtn
Caption Очистить
Button2 Name CloseBtn
Caption Закрыть
Итак, визуальное проектирование главной формы приложения завершено.

2-й этап – создание программного кода
Во-первых, необходимо закладки в TabSet сделать доступными и синхронизировать их с блокнотом. Для этого воспользуемся свойством Tabs (закладки) компонента TabSet, которое представляет список имен закладок. В нашем примере список закладок соответствует списку страниц (Pages) блокнота. Создайте следующий обработчик события:
Procedure TNoteBookF.FormCreate(Sender: TObject);
Begin
TabSet1.Tabs:=NoteBook1.Pages; {копируем содержимое свойства Pages
компонента NoteBook в свойство Tabs компонента TabSet}
TabSet1.TabIndex:=NoteBook1.PageIndex; {Независимо от того, какая
страница блокнота активна во время проектирования (свойство ActivePage) будет выбрана соответствующая этой странице закладка}
End;
Эксперимент. Сохраните и запустите проект. Убедитесь в том, что закладки на форме получили названия, соответствующие страницам блокнота.
Используя свойства UnSelectedColor, SelectedColor, BackgroundColor, DitherBackground, StartMargin, EndMargin компонента TabSet1, измените внешний вид закладок.
Далее создадим обработчик события OnClick для кнопки ‘Добавить’, в котором будем помещать строки (компонент Edit) на страницы блокнота. Для операций со строками у компонента ListBox имеется свойство Items класса TStrings. Для того чтобы добавить строку, воспользуемся свойством Add этого класса. Обработчик события при этом может выглядеть следующим образом:
1-й способ
procedure TNoteBookF.AddBtnClick(Sender: TObject);
Begin
If RecordEdt.Text <>'' Then Begin {Для того чтобы поместить запись на нужную страницу блокнота выбираем компонент ListBox по номеру страницы блокнота}
Case NoteBook1.PageIndex Of
0: ListBox1.Items.Add(RecordEdt.Text);
1: ListBox2.Items.Add(RecordEdt.Text);
2: ListBox3.Items.Add(RecordEdt.Text);
3: ListBox4.Items.Add(RecordEdt.Text);
4: ListBox5.Items.Add(RecordEdt.Text);
5: ListBox6.Items.Add(RecordEdt.Text);
6: ListBox7.Items.Add(RecordEdt.Text);
7: ListBox8.Items.Add(RecordEdt.Text);
End;
RecordEdt.Text:=''; {введенный текст затираем}
End; End;
Процедура получилась довольно громоздкой. Опишем её по-другому.
2-й способ
В Object Pascal определена функция:
function FindComponent(const AName: string): TComponent;
которая возвращает ссылку на компонент, имя которого задано параметром функции AName.
Воспользуемся этой функцией в коде обработчика события OnClick кнопки ‘Добавить’:
procedure TNoteBookF.AddBtnClick(Sender: TObject);
var TempComponent: TListBox; {введем вспомогательную переменную}
begin
TempComponent:=TListBox(FindComponent('ListBox'+
IntToStr(Notebook1.PageIndex+1)));
{TListBox(<компонент>) используется для преобразования к типу TListBox}
if RecordEdt.Text<>'' then
TempComponent.Items.Add(RecordEdt.Text);
RecordEdt.Text:='';
end;
Эксперимент. Сохраните и запустите проект. Попробуйте добавить строки на разные страницы блокнота. Объясните, почему все строки у Вас записываются только на страницу, которая была открыта при запуске приложения.
Строки записываются на одну страницу блокнота потому, что закладки Tabset1 не синхронизированы со страницами NoteBook1, т.е. при выборе закладки соответствующая страница блокнота не активизируется.
Чтобы устранить этот недостаток, создайте обработчик события OnClick закладок:
procedure TNoteBookF.TabSet1Click(Sender: TObject);
begin
NoteBook1.PageIndex:=TabSet1.TabIndex;
{страница блокнота и страница набора закладок должны совпадать}
end;
Эксперимент. Сохраните проект. Проверьте правильность работы приложения, т.е. внесение записей на страницы блокнота.

Задание для самостоятельного выполнения
1. Написать обработчики событий нажатия кнопок «Закрыть», «Изменить», «Удалить», «Очистить»:
• Изменить: выделенная в списке страницы блокнота строка должна быть заменена содержимым окна редактирования.
• Удалить: выделенная в списке страницы блокнота строка должна быть удалена.
• Очистить: содержимое всего блокнота удаляется.
Указание: воспользуйтесь свойствами Items.Strings, Items и ItemIndex компонента ListBox.

2. Модифицировать программу следующим образом:
• при выборе записи на странице блокнота соответствующая запись отображается в окне редактирования;
• при удалении записи в окне редактирования отображается следующая запись станицы блокнота;
• добавление записи из окна редактирования происходит при нажатии клавиши ввода.

Исключительные ситуации
Исключительная (или особая) ситуация представляет собой сигнал о произошедшей в приложении ошибке. Для обработки исключительных ситуаций используются две конструкции:

try
защищаемый код
finally
код завершения
end;
try
защищаемый блок
except
обработчик исключения
end;

В первом варианте блок finally выполняется независимо от того, возникла ли ошибка в процессе выполнения защищаемых операций.
Блок try except используется для обработки исключительных ситуаций. В Object Pascal исключительные ситуации представляют собой объекты, содержащие информацию, идентифицирующую ошибку и место ее возникновения. Внутри части except создаются обработчики особых ситуаций для классов исключительных ситуаций. Обработчик особой ситуации имеет следующий формат:
try
защищаемый блок
except
on E: ESomeException do <обработчик исключения>;
end;
Для обработки особой ситуации Delphi предоставляет возможность создания временных объектов особой ситуации (E), которые могут использоваться в обработчике исключения. Временный объект особой ситуации имеет тот же тип, что и объект исключения, который он обозначает (ESomeException).
Существуют предопределенные классы исключительных ситуаций для обработки стандартных ошибок, таких, как нехватка памяти, деление на ноль, числовое переполнение, ошибки ввода-вывода и другие. Перечислим некоторые из них:
EMathError класс-предок исключений, случающихся при выполнении операций с плавающей точкой;
EInvalidArgument значение параметра выходит за диапазон значений
EInvalidOp передача математическому сопроцессору ошибочной конструкции;
EOverflow переполнение разрядов при работе со слишком большими величинами;
EUnderflow потеря разрядов при работе со слишком малыми величинами;
EZeroDivide деление на ноль;
EIntError класс-предок исключений, случающихся при выполнении целочисленных операций;
EDivByZero деление на ноль;
EIntOverflow выполнение операций, приводящих к переполнению целых переменных;
ERangeError значение целочисленного выражения выходит за пределы установленного целочисленного типа.
Попытка обращения к элементу массива по индексу, выходящему за пределы массива;
EListError обращение к элементу списка (string, List, TStringList) по индексу, выходящему за пределы допустимых значений;
EInOutError ошибки при операциях с файловой системой.
Код ошибки возвращается в локальной переменной ErrorCode, которая может принимать следующие значения:
2 файл не найден
3 неверное имя файла
4 слишком много открыто файлов
5 отказ в доступе
100 конец файла
101 диск полон
106 неверная операция ввода;
EConvertError ошибки преобразования типов (простых, объектных).
Например, для создания устойчивого к ошибкам приложения, записывающего данные в файл, необходимо написать следующий код:
begin
assignfile(f, ‘data.dan’);
try
append(f);
try
writeln(f,s);
finally
closefile(f);
end;
except
on E: EInOutError do
if E.ErrorCode = 2 then
if MessageDlg(‘Файл не найден. Созать его?’, mtError, [mbYes, mbNo],0)=mrYes then FileCreate(‘data.dan’);
end;
end;
В данном листинге внутренний блок try finally используется для того, чтобы файл был закрыт в любом случае, т.е. независимо от того, была ошибка или нет.
Внешний блок try except используется для обработки исключительной ситуации, которая может произойти в программе. После закрытия файла во внутреннем блоке finally блок except использует временный объект E для определения типа произошедшей ошибки ввода/вывода.
Упражнение 2. Модифицируйте приложение «Блокнот», так, чтобы при повторном запуске программы данные, введенные в предыдущем сеансе, отображались на страницах блокнота.
Решение
Для решения задачи напишем процедуру, в которой все странички блокнота будут сохраняться в отдельных файлах на диске. При нажатии на кнопку ‘Закрыть’ появляется диалоговое окно с текстом ‘Сохранить изменения?’ и двумя кнопками ‘Yes’ и ‘No’. При нажатии на ‘Yes’, данные сохраняются в файлах, при нажатии на ‘No’ - приложение закрывается без сохранения изменений.
Напишем метод, который все странички блокнота будет сохранять в отдельных файлах в каталоге, указанном в переменной dir. В разделе public описания класса TNoteBookF опишите метод SaveAll и переменную dir:

public
{ Public declarations }
dir: string;
procedure SaveAll;

В разделе Implementation модуля опишите программный код метода:
procedure TNoteBookF.SaveAll;
var i: integer;
TempComponent: TListBox;
begin
InputQuery('Введите полное имя каталога ','',dir);
for i:=0 to 7 do begin
NoteBook1.PageIndex:=i;
TempComponent:=
TListBox(FindComponent('ListBox'+IntToStr(i+1)));
TempComponent.Items.SaveToFile(dir+'/Page'+IntToStr(i+1));
{Строки компонента ListBox сохраняются в соответствующем файле}
end;
end;
Эксперимент. Сохраните и запустите приложение. Убедитесь в работоспособности приложения для существующих каталогов. Попробуйте сохранить файлы в несуществующий каталог, например c:\NoteBook\Pages\.
Для несуществующего каталога операционная система возбуждает исключительную ситуацию, результатом которой отображается сообщение об ошибке, изображенное на рис. 1.

Рис. 1
Чтобы обезопасить приложение от подобного вида ошибок, добавим блок обработки исключительной ситуации EFCreateError (рис. 1), возникшей при сохранении файла:
begin
InputQuery('Введите полное имя каталога','',dir);
if dir[length(dir)]<>’\’ then dir:=dir+’\’;
{добавляем разделитель подкаталогов в конец строки}
for i:=0 to 7 do begin
NoteBook1.PageIndex:=i;
TempComponent:=
TListBox(FindComponent('ListBox'+IntToStr(i+1)));
try
TempComponent.Items.SaveToFile(dir+'Page'+IntToStr(i+1));
{Строки компонента ListBox сохраняются в соответствующем файле}
except
on EFCreateError do begin
{класс исключений, возникающих при неудачных попытках создания файла}
makedir(dir); {процедура создания каталога (смотри ниже)}
TempComponent.Items.SaveToFile(dir+'Page'+IntToStr(i+1));
end;
end;
end;
end;
Рассмотрим процедуру создания подкаталогов:
procedure MakeDir(dir: string);
var d: string;
k: byte;
begin
k:=pos('\',dir); d:=copy(dir,1,k); delete(dir,1,k);
{выделяем название корневого каталога из dir, запоминаем в переменной d}
while DirectoryExists(d) do begin
{пока каталог с именем, указанным в переменной d, существует}
k:=pos('\',dir); d:=d+copy(dir,1,k); delete(dir,1,k);
{выделяем имя очередного подкаталога из переменной dir}
end;
{в переменной d хранится имя несуществующего каталога}
CreateDir(d); {стандартная функция создания подкаталога с именем d}
while (pos('\',dir)<>0) do begin
k:=pos('\',dir); d:=d+copy(dir,1,k); delete(dir,1,k);
CreateDir(d);
end;
end;

Обсуждение

давно
Профессионал
153662
1070
07.05.2010, 21:11
общий
mihail77:
Могу предложить такой вариант решения задачи.
Об авторе:
Мои программы со статусом freeware для Windows на моём сайте jonix.ucoz.ru

давно
Профессионал
153662
1070
08.05.2010, 14:45
общий
это ответ
Здравствуйте, mihail77.
Могу предложить такой вариант решения данной задачи:
Форма выбора папки
Код:
unit vubor;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, FileCtrl;

type
TFormvubor = class(TForm)
DriveComboBox1: TDriveComboBox;
DirectoryListBox1: TDirectoryListBox;
FileListBox1: TFileListBox;
FilterComboBox1: TFilterComboBox;
Button1: TButton;
Button2: TButton;
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;

var
Formvubor: TFormvubor;

implementation

uses Main;

{$R *.dfm}

procedure TFormvubor.Button1Click(Sender: TObject);
var
i: integer;
TempComponent: TListBox;
f: TextFile;
dir, s, s1: string;
begin
dir:= FileListBox1.Directory + '\NoteBook.ttxt'; // Получаем полный путь к файлу
if not FileExists(dir) then // Проверяем существование файла
begin
ShowMessage('Файл блокнота не найден!'); // Показ окна с сообщением
exit; // Выход из процедуры
end;
AssignFile(f, dir); // Связали файловую переменную с файлом
Reset(f); // Встали на начало файла
while not eof(f) do // Делаем пока не дойдём до конца файла
begin
Readln(f, s); // Считали строку из файла
s1:= copy(s, 1, 5); // Скопировали первые 5 символов из строки
if s1 = '[Page' then // Если это метка номера страницы делаем
begin
i:= StrToInt(copy(s, 6, 1)); // Получили номер страницы
With NoteBookF do // Делаем для основной формы
begin
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(i))); // Нашли нужный listbox
Readln(f, s); // Считали строку из файла
s1:= copy(s, 1, 5); // Скопировали первые 5 символов из строки
while s1 <> '[Page' do // Пока недойдём до следущей метки страницы делаем
begin
TempComponent.Items.Add(s); // Добавляем строку в listbox
Readln(f, s); // Считали строку из файла
s1:= copy(s, 1, 5); // Скопировали первые 5 символов из строки
end;
end;
end;
end;
CloseFile(f); // Закрыли файл
Close; // Закрыли форму
end;

procedure TFormvubor.Button2Click(Sender: TObject);
begin
NoteBookF.SaveAll; // Вызов процедуры сохранения в файл
Close; // Закрыли форму
Button2.Visible:= false; // Спрятали кнопку
end;

end.

Главная форма
Код:
unit Main;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ExtCtrls, StdCtrls, Tabs;

type
TNoteBookF = class(TForm)
Notebook1: TNotebook;
TabSet1: TTabSet;
ListBox1: TListBox;
ListBox2: TListBox;
ListBox3: TListBox;
ListBox4: TListBox;
ListBox5: TListBox;
ListBox6: TListBox;
ListBox7: TListBox;
ListBox8: TListBox;
Panel1: TPanel;
Label1: TLabel;
RecordEdt: TEdit;
AddBtn: TButton;
ChangeBtn: TButton;
DeleteBtn: TButton;
ClearBtn: TButton;
CloseBtn: TButton;
procedure FormCreate(Sender: TObject);
procedure AddBtnClick(Sender: TObject);
procedure TabSet1Click(Sender: TObject);
procedure CloseBtnClick(Sender: TObject);
procedure ChangeBtnClick(Sender: TObject);
procedure DeleteBtnClick(Sender: TObject);
procedure ClearBtnClick(Sender: TObject);
procedure ListBox1Click(Sender: TObject);
procedure RecordEdtKeyPress(Sender: TObject; var Key: Char);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
dir: string;
procedure SaveAll;
end;

var
NoteBookF: TNoteBookF;
modif: Boolean; {переменная хранящая изменение блокнота}

implementation

uses vubor;

{$R *.dfm}

procedure TNoteBookF.SaveAll;
var i, j: integer;
TempComponent: TListBox;
f: TextFile; // переменная для работы с текстовым файлом
begin
dir:= Formvubor.FileListBox1.Directory + '\NoteBook.ttxt'; // Получаем полный путь к файлу
AssignFile(f, dir); // Связали файловую переменную с файлом
Rewrite(f); // Открыли файл для перезаписи
for i:= 0 to 7 do // проходим все страницы блокнота
begin
NoteBook1.PageIndex:= i; // Активная страница блокнота
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(i + 1))); // Нашли компонент listbox
Writeln(f, '[Page' + IntToStr(i + 1) + ']'); // Записали метку номера страницы
for j:= 0 to TempComponent.Items.Count - 1 do
Writeln(f, TempComponent.Items.Strings[j]); // записали содержтмое listbox в файл
end;
CloseFile(f); // Закрыли файл
end;


procedure TNoteBookF.FormCreate(Sender: TObject);
begin
TabSet1.Tabs:= NoteBook1.Pages; {копируем содержимое свойства Pages
компонента NoteBook в свойство Tabs компонента TabSet}
TabSet1.TabIndex:= NoteBook1.PageIndex; {Независимо от того, какая
страница блокнота активна во время проектирования (свойство ActivePage) будет выбрана соответствующая этой странице закладка}
end;

procedure TNoteBookF.AddBtnClick(Sender: TObject);
var
TempComponent: TListBox; {введем вспомогательную переменную}
begin
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(Notebook1.PageIndex + 1)));
{TListBox(<компонент>) используется для преобразования к типу TListBox}
if RecordEdt.Text <> '' then
TempComponent.Items.Add(RecordEdt.Text);
RecordEdt.Text:= '';
modif:= true;
end;

procedure TNoteBookF.TabSet1Click(Sender: TObject);
begin
NoteBook1.PageIndex:= TabSet1.TabIndex;
{страница блокнота и страница набора закладок должны совпадать}
end;

procedure TNoteBookF.CloseBtnClick(Sender: TObject);
begin
Close; {Закрыли приложение}
end;

procedure TNoteBookF.ChangeBtnClick(Sender: TObject);
var
TempComponent: TListBox; {введем вспомогательную переменную}
begin
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(Notebook1.PageIndex + 1)));
{TListBox(<компонент>) используется для преобразования к типу TListBox}
if RecordEdt.Text <> '' then
TempComponent.Items.Strings[TempComponent.ItemIndex]:= RecordEdt.Text; // Записали данные в listbox
modif:= true; // идентифокатор модификации блокнота
end;

procedure TNoteBookF.DeleteBtnClick(Sender: TObject);
var
TempComponent: TListBox; {введем вспомогательную переменную}
i: integer;
begin
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(Notebook1.PageIndex + 1)));
{TListBox(<компонент>) используется для преобразования к типу TListBox}
i:= TempComponent.ItemIndex; // Сохранили номер выделнной строки
TempComponent.Items.Delete(i); // Удалили выделенную строку
TempComponent.ItemIndex:= i; // Выделили следующую запись
RecordEdt.Text:= TempComponent.Items.Strings[i]; // Записали выделенную запись в поле редактирования
modif:= true;
end;

procedure TNoteBookF.ClearBtnClick(Sender: TObject);
var
i: integer;
TempComponent: TListBox; {введем вспомогательную переменную}
begin
for i:= 1 to 8 do
begin {Очищаем все listbox}
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(i))); // Нашли активный listbox
TempComponent.Clear; // Очищаем весь listbox
end;
modif:= true;
end;

procedure TNoteBookF.ListBox1Click(Sender: TObject);
var
TempComponent: TListBox; {введем вспомогательную переменную}
begin
TempComponent:= TListBox(FindComponent('ListBox' + IntToStr(Notebook1.PageIndex + 1)));
{TListBox(<компонент>) используется для преобразования к типу TListBox}
RecordEdt.Text:= TempComponent.Items.Strings[TempComponent.ItemIndex]; // Записали выделенную запись в поле редактирования
end;

procedure TNoteBookF.RecordEdtKeyPress(Sender: TObject; var Key: Char);
begin
if key = #13 then
AddBtn.Click; // Если нажата клавиша ввод, добавляем запись в блокнот
end;

procedure TNoteBookF.FormCloseQuery(Sender: TObject;
var CanClose: Boolean);
begin
if modif then // Если делались изменения в блокноте выдаём диалог с вопросом о сохранениии
if MessageDlg('Сохранить изменения?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then
begin // Ответили да
Formvubor.Button2.Visible:= true; // Сделали видемую кнопку "Сохранить"
Formvubor.ShowModal; // Показать форму выбора папки
end;
end;

procedure TNoteBookF.FormShow(Sender: TObject);
begin
Formvubor.ShowModal; // Перед показом основной форму, показываем форму выбора папки
end;

end.

Прикрепленные файлы:
Об авторе:
Мои программы со статусом freeware для Windows на моём сайте jonix.ucoz.ru

Форма ответа