task_15087

advertisement
ПРОГРАММИРОВАНИЕ
В СРЕДЕ C++ BUILDER
Оформление контрольной работы.
1. Формулировка задания (с методички полностью).
2. Разработка тестов.
3. Разработка алгоритма, алгоритмов (алгоритм должен отображать
взаимодействие пользователя с приложением, из этого алгоритма
должен быть понятен интерфейс).
4. Таблица идентификаторов.
Имя в
алгоритме
Имя в
программе
Тип
Диапазон
Назначение,
содержание
5. Код с комментариями.
6. Результаты использования приложения (входные данные, обработка
исключительных ситуаций).
7. Библиографический список.
ДВУНАПРАВЛЕННЫЙ НЕОДНОРОДНЫЙ СПИСОК
С ОДНОРОДНЫМИ ПОДСПИСКАМИ
Задание
1. Написать и протестировать функции для включения, исключения и
поиска элемента кругового списка для: а)списка без заголовка; б)списка с
заголовком (заголовок может содержать некоторую информацию о списке,
например, число элементов списка).
Введение
Список является структурой хранения данных. Если список –
динамическая структура данных, то в простейшем случае – это линейный
связный список, состоящий из элементов (узлов), каждый из которых
содержит как собственные данные, так и одну (или две) ссылки на
следующий (и предыдущий) узел. Принципиальным преимуществом перед
массивом является структурная гибкость: порядок элементов связного
списка может не совпадать с порядком расположения элементов данных в
памяти компьютера, количество элементов не нужно задавать заранее,
порядок обхода списка всегда явно задается его внутренними связями.
Существует
несколько
разновидностей
связного
списка.
Однонаправленный список – каждый элемент содержит данные и
указатель на следующий элемент. В кольцевом списке последний элемент
содержит указатель на первый элемент. Двунаправленный связный список
– в этом списке каждый элемент содержит указатели как на следующий,
так и на предыдущий элементы. В таком списке, в отличие от
однонаправленного списка, можно перемещаться в двух направлениях. В
однородном списке все элементы имеют один и тот же тип. Неоднородный
(гетерогенный) список имеет разнотипные элементы, причем однотипные
элементы в нем объединяют в однородные подсписки.
Целью данной лабораторной работе является изучение приложения
для работы с двунаправленным неоднородным списком с однородными
подсписками, представленным на рис.7.1. Из структуры списка видно, что
основной список состоит из взаимосвязанных первых элементов
подсписков. Ссылка на начало списка находится в указателе first, а ссылка
на конец списка – в указателе last.
Классы
Примем, что разнотипными элементами в списке являются объекты
разных классов. Общее для них состоит в том, что они связаны друг с
другом указателями. Поэтому введем базовый класс с указателями на этот
же класс:
class link
{
public:
link* prev; // указатель на предыдущий элемент основного списка
link* next; // указатель на следующий элемент основного списка
link* down; // указатель на следующий элемент подсписка
types type;
link(){prev=next=down=0;}//конструктор с умолчанием
};
2
first
prev=0
prev
bike
down
bike
roll
next
down
roll
next
down
bike
down
roll
down
bike
down=0
1- й подсписок
next=
0
bike
down
bike
last
prev
down=0
2-й подсписок
down=0
n-й подсписок
Рис.7.1 – структура двунаправленного неоднородного списка
с n однородными подсписками
Примем также, что список предназначен для контроля товаров в
спортивном магазине, группируемых в подсписки по наименованию и
фирме-производителю. Пусть товарами будут «велосипеды» и «роликовые
коньки». Тогда в списке они должны быть представлены элементами
подсписков - объектами соответствующих классов. Эти классы будут
производными классами от базового класса. Для определения объекта
производного класса в базовый класс введен элемент
type типаперечисление: enum types{Roll, Bike}.
//--------------------------------------------------------------------------//производный класс для элемента подсписка - роликовые коньки
class TRoll:public link
{
public:
char* date; //дата поступления
char* comp; //производитель
int diam; //диаметр колес (в мм)
int count; //количество (штук)
TRoll(); //конструктор
3
~TRoll(); //деструктор
};
//-------------------------------------------------------------------------//производный класс для элемента подсписка - велосипед
class TBike:public link
{
public:
char* date; //дата поступления
char* comp; //производитель
int diam; //диаметр колес (в мм)
int count; //количество (штук)
float weight; //вес (в кг)
int speeds; //количество скоростей
TBike(); //конструктор
~TBike(); //деструктор
};
//-------------------------------------------------------------------------При создании объектов классов TRoll и TBike – элементов
подсписков – в конструкторах этих классов в данное-элемент базового
класса type подставляется значение (Roll, Bike), позволяющее
идентифицировать создаваемые объекты. Доступ к type – через указатель
на базовый класс link.
Теперь создадим класс, объединяющий созданные выше классы для
элементов подсписков и предназначенный для создания объекта «список».
//-------------------------------------------------------------------------//класс для списка
class list
{
public:
link* first; //указатель на начало списка
link* last; //указатель на конец списка
int count_dsp; //количество подсписков
int count_elem_sp; //количество элементов в списке
bool is_empty; //флаг "список пуст"
list(); //конструктор
~list(); //деструктор
void append_bike(TBike*);//добавление элемента-велосипеда в список
void append_roll(TRoll*);//добавление элемента-роликовые коньки
// в список
void del(int); //удаление элемента из списка
void out_list(); //вывод списка в таблицу
void clear_down(int); //удаление подсписка из списка
4
void clear();
//уничтожение списка
};
//-------------------------------------------------------------------------Комментарии в объявлении последнего класса содержат перечень
большинства операций при работе со списком. Следует отметить, что все
элементы списка имеют по три указателя (prev, next, down), но только в
элементах основной части списка, т.е. в первых элементах подсписков,
используются все три указателя, а в остальных элементах подсписков –
один указатель (down). При удалении первого элемента подсписка на его
место ставится второй, что потребует в нем инициализации указателей
prev и next адресами предыдущего и последующего элементов
соответственно в основной части списка.
Проектирование приложения.
Выбор, размещение и задание свойств компонентов.
Коды классов, функций и обработчиков событий
Сохраните модуль главной формы под именем LR_7, а проект – под
именем PR_LR_7.
Для размещения классов в проекте использован модуль, не
связанный с формой. Чтобы создать такой модуль, нужно выполнить
команду Файл/Новый/Другое… и открывшемся окне Новые элементы на
странице Новый щелкнуть на пиктограмме Модуль. Модулю дано имя f_7.
В заголовочном файле этого модуля f_7.h находятся приведенные выше
объявления типа-перечисление и классов, а в файле реализации модуля
f_7.cpp – реализации классов (определения функций-элементов классов).
Чтобы получить возможность отладки модуля, перенесем на форму со
страницы Дополнительно компонент StringGrid1 и директивой #include
"LR_7.h" подключим модуль формы к файлу f_7.cpp.
Заголовочный файл f_7.h модуля f_7 (без формы)
//--------------------------------------------------------------#ifndef f_7H
#define f_7H
//--------------------------------------------------------------------------//тип-перечисление для идентификации элементов списка
enum types{Roll, Bike};
//--------------------------------------------------------------------------//класс указателей - базовый класс для элементов подсписков
class link
{
5
public:
link* prev; // указатель на предыдущий элемент основного списка
link* next; // указатель на следующий элемент основного списка
link* down; // указатель на следующий элемент подсписка
types type;
link(){prev=next=down=0;}//конструктор с умолчанием
};
//--------------------------------------------------------------------------//производный класс для элемента подсписка - роликовые коньки
class TRoll:public link
{
public:
char* date; //дата поступления
char* comp; //производитель
int diam; //диаметр колес (в мм)
int count; //количество (штук)
TRoll(); //конструктор
~TRoll(); //деструктор
};
//-------------------------------------------------------------------------//производный класс для элемента подсписка - велосипед
class TBike:public link
{
public:
char* date; //дата поступления
char* comp; //производитель
int diam; //диаметр колес (в мм)
int count; //количество (штук)
float weight;//вес (в кг)
int speeds; //количество скоростей
TBike(); //конструктор
~TBike(); //деструктор
};
//-------------------------------------------------------------------------//класс для списка
class list
{
public:
link* first; //указатель на начало списка
link* last; //указатель на конец списка
int count_dsp; //количество подсписков
int count_elem_sp; //количество элементов в списке
bool is_empty; //флаг "список пуст"
6
list(); //конструктор
~list(); //деструктор
void append_bike(TBike*);//добавление элемента-велосипеда в список
void append_roll(TRoll*);//добавление элемента-роликовые коньки в
//список
void del(int); //удаление элемента из списка
void out_list(); //вывод списка в таблицу
void clear_down(int); //удаление подсписка из списка
void clear(); //уничтожение списка
};
//-------------------------------------------------------------------------#endif
Файл реализации f_7.cpp модуля f_7 (без формы)
//---------------------------------------------------------------------------
#pragma hdrstop
#include "f_7.h"
#include "LR_7.h"
//--------------------------------------------------------------------------#pragma package(smart_init)
//--------------------------------------------------------------------------//конструктор класса роликовые коньки
TRoll::TRoll()
{
type=Roll;
date=new char[50];
comp=new char[50];
diam=count=0;
}
//--------------------------------------------------------------------------//деструктор класса роликовые коньки
TRoll::~TRoll()
{
delete[]date;
delete[]comp;
}
7
//--------------------------------------------------------------------------//конструктор класса велосипед
TBike::TBike()
{
type=Bike;
date=new char[50];
comp=new char[50];
diam=count=weight=speeds=0;
}
//--------------------------------------------------------------------------//деструктор класса велосипед
TBike::~TBike()
{
delete[]date;
delete[]comp;
}
//--------------------------------------------------------------------------//конструктор класса список
list::list()
{
first=last=0;
count_dsp=count_elem_sp=0;
is_empty=true;
}
//------------------------------------------------------------------------//деструктор класса список
list::~list()
{
clear();
}
//-----------------------------------------------------------------------//добавление элемента-велосипеда в список
void list::append_bike(TBike*bike)
{
if(is_empty)//если список пуст
{//в список заносится первый элемент
//первый элемент образует первый подсписок
first=bike;
8
last=bike;
bike->prev=0;
bike->next=0;
bike->down=0;
bike->count=1;
count_dsp=1;
count_elem_sp=1;
is_empty=false;
return;
}
//список не пуст
bool f=false; //подсписок для добавляемого элемента не определен
//создаем указатель для просмотра основной части списка
//ставим указатель на начало списка
link* current=first;
//просматриваем основную часть списка для поиска подсписка,
//в который нужно добавить элемент
while(current)
{
if(current->type==Bike&&
strcmp(((TBike*)current)->comp,bike->comp)==0)
{f=true;break;} //подсписок для добавления элемента найден
current=current->next;
} //подсписок для добавления элемента не найден
if(!f)//добавляем элемент в конец списка, образуя новый подсписок
{
bike->prev=last;
last->next=bike;
last=bike;
bike->next=0;
bike->down=0;
bike->count=1;
count_dsp++;
count_elem_sp++;
}
else //добавляем элемент в конец найденного подсписка
{
link *curr=current;
while(curr->down)
curr=curr->down;
9
curr->down=bike;
bike->down=0;
((TBike*)current)->count++;
count_elem_sp++;
}
}
//-------------------------------------------------------------------------//добавление элемента-роликовые коньки в список
void list::append_roll(TRoll*roll)
{
if(is_empty) //если список пуст
{ //в список заносится первый элемент
//первый элемент образует первый подсписок
last=roll;
last->next=0;
first=roll;
first->prev=0;
roll->down=0;
roll->count++;
count_dsp=1;
count_elem_sp=1;
is_empty=false;
return;
}
//список не пуст
bool f=false;//подсписок для добавляемого элемента не определен
//создаем указатель для просмотра основной части списка
//ставим указатель на конец списка
link* current=last;
//просматриваем основную часть списка для поиска подсписка,
//в который нужно добавить элемент
while(current)
{
if(current->type==Roll&&
strcmp(((TRoll*)current)->comp,roll->comp)==0)
{f=true; break;} //подсписок для добавления элемента найден
current=current->prev;
} //подсписок для добавления элемента не найден
if(!f)//добавляем элемент в конец списка, образуя новый подсписок
10
{
roll->prev=last;
last->next=roll;
last=roll;
roll->next=0;
roll->down=0;
roll->count=1;
count_dsp++;
count_elem_sp++;
}
else //добавляем элемент в конец найденного подсписка
{ link *curr=current;
while(curr->down)
curr=curr->down;
curr->down=roll;
roll->down=0;
((TRoll*)current)->count++;
count_elem_sp++;
}
}
//-------------------------------------------------------------------------//вывод списка в таблицу StringGrid1
void list::out_list()
{
if(is_empty)//если список пуст
{
MessageBox(NULL,"Список пуст!","",0);
}
//число строк в таблице увеличиваем на количество
//элементов в списке
Form1->StringGrid1->RowCount=1+count_elem_sp;
//создаем указатель для просмотра основной части списка
//ставим указатель на начало списка
link *current=first;
int j=1; //вывод списка начнем с первой строки таблицы
//просматриваем основную часть списка,
//или первые элементы подсписков
for(int i=1; i<=count_dsp; i++)
11
{
if(current->type==Roll)//если в подсписке - ролик. коньки
{
//создаем текущий указатель подсписка и ставим его
//на первый элемент подсписка
TRoll* curr=(TRoll*)current;
//выводим элементы подсписка в таблицу
while(curr)
{ //выводим элемент подсписка в строку таблицы
Form1->StringGrid1->Cells[0][j]=IntToStr(j);
Form1->StringGrid1->Cells[1][j]="Roll";
Form1->StringGrid1->Cells[2][j]=IntToStr(curr->count);
Form1->StringGrid1->Cells[3][j]=curr->date;
Form1->StringGrid1->Cells[4][j]=curr->comp;
Form1->StringGrid1->Cells[5][j]=IntToStr(curr->diam);
j++; //переходим на следующую строку таблицы
//ставим указатель подсписка на следующий элемент подсписка
curr=(TRoll*)curr->down;
}
}
else if(current->type==Bike)//если в подсписке - велосипеды
{
//создаем текущий указатель подсписка и ставим его
//на первый элемент подсписка
TBike* curr=(TBike*)current;
//выводим элементы подсписка в таблицу
while(curr)
{ //выводим элемент подсписка в строку таблицы
Form1->StringGrid1->Cells[0][j]=IntToStr(j);
Form1->StringGrid1->Cells[1][j]="Bike";
Form1->StringGrid1->Cells[2][j]=IntToStr(curr->count);
Form1->StringGrid1->Cells[3][j]=curr->date;
Form1->StringGrid1->Cells[4][j]=curr->comp;
Form1->StringGrid1->Cells[5][j]=IntToStr(curr->diam);
Form1->StringGrid1->Cells[6][j]=FloatToStr(curr->weight);
Form1->StringGrid1->Cells[7][j]=IntToStr(curr->speeds);
j++; //переходим на следующую строку таблицы
12
//ставим указатель подсписка на следующий элемент подсписка
curr=(TBike*)curr->down;
}
}
current=current->next;//переходим на следующий подсписок
}
//вывод информации о списке
Form1->StatusBar1->SimpleText="Количество подсписков - "+
IntToStr(count_dsp)+" "+"Количество элементов в списке - "+
IntToStr(count_elem_sp);
}
//------------------------------------------------------------------------//удаление из списка элемента, выделенного в строке r
//таблицы вывода списка
void list::del(int r)
{
if(r==1&&count_elem_sp==1)//в списке только один элемент
{
link *current=first;
delete first;
first=last=0;
if(current->type==Roll) ((TRoll*)current)->count--;
else ((TBike*)current)->count--;
count_elem_sp--;//количество элементов в списке уменьшаем на один
count_dsp--;
is_empty=true;
MessageBox(NULL,"Список из одного элемента уничтожен!","",0);
return;
}
link *curr, *current=first;
int j;
if(current->type==Roll) j=((TRoll*)current)->count;
else j=((TBike*)current)->count;
bool f1=false,
f2=false;
while(current)//ищем подсписок с удаляемым элементом
{
if(j==r) {f1=true; break;}//удаляемый элемент - последний в подсписке
13
if(j>r) {f2=true; break;} //удаляемый элемент - внутри подсписка
current=current->next;//переход на следующий подсписок
if(current->type==Roll) j+=((TRoll*)current)->count;
else j+=((TBike*)current)->count;
}
//удаляемый элемент - последний в подсписке из нескольких элементов
if(f1&&current->down)
{
curr=current;
while(curr->down->down)//ищем предпоследний элемент в подсписке
curr=curr->down;
delete curr->down; //удаление последнего элемента в подсписке
curr->down=0;
//количество элементов в подсписке уменьшаем на один
if(current->type==Roll) ((TRoll*)current)->count--;
else ((TBike*)current)->count--;
count_elem_sp--;//количество элементов в списке уменьшаем на один
MessageBox(NULL,"Элемент удален!","",0);
return;
}
//удаляемый элемент - в первом подсписке из одного элемента
if(f1&&!current->down&&current->next&&!current->prev)
{
first=current->next;//переносим начало списка на следующий элемент
first->prev=0;
delete current; //удаление единственного элемента в подсписке
count_dsp--; //количество подсписков в списке уменьшаем на один
count_elem_sp--; //количество элементов в списке уменьшаем на один
MessageBox(NULL,"Элемент удален!","",0);
return;
}
//удаляемый элемент - в последнем подсписке из одного элемента
if(f1&&!current->down&&!current->next&&current->prev)
{
last=current->prev;//переносим конец списка на предыдущий элемент
last->next=0;
delete current; //удаление единственного элемента в подсписке
count_dsp--; //количество подсписков в списке уменьшаем на один
count_elem_sp--; //количество элементов в списке уменьшаем на один
MessageBox(NULL,"Элемент удален!","",0);
14
return;
}
//удаляемый элемент - в одноэлементном подсписке
//внутри основной части списка
if(f1&&!current->down&&current->next&&current->prev)
{
current->prev->next=current->next;//выключаем одноэлементный
// подсписок
current->next->prev=current->prev;//из списка
delete current; //удаление единственного элемента в подсписке
count_dsp--; //количество подсписков в списке уменьшаем на один
count_elem_sp--; //количество элементов в списке уменьшаем на один
MessageBox(NULL,"Элемент удален!","",0);
return;
}
//удаляемый элемент - первый в подсписке из нескольких элементов
int k;
if(current->type==Roll) k =((TRoll*)current)->count;
else k =((TBike*)current)->count;
if(f2&&(j-k+1==r))
{
//на место первого ставим второй элемент подсписка
//удаляемый элемент - первый в единственном
//подсписке из нескольких элементов
if(current==first&&current==last)
{
first=current->down;
last=current->down;
}
//удаляемый элемент - первый в первом
//подсписке из нескольких элементов
if(current==first)
{
current->next->prev=current->down;
current->down->next=current->next;
}
//удаляемый элемент - первый в последнем
//подсписке из нескольких элементов
if(current==last)
15
{
current->prev->next=current->down;
current->down->prev=current->prev;
}
//удаляемый элемент - первый во внутреннем
//подсписке из нескольких элементов
if(current->prev&&current->next)
{
current->next->prev=current->down;
current->down->next=current->next;
current->prev->next=current->down;
current->down->prev=current->prev;
}
//количество элементов в подсписке уменьшаем на один
if(current->type==Roll) ((TRoll*)current->down)->count=k-1;
else ((TBike*)current->down)->count=k-1;
//если подсписок первый - переносим first на второй элемент подсписка
if(current==first) first=current->down;
// если подсписок последний - переносим last на второй элемент
// подсписка
if(current==last) last=current->down;
delete current;
count_elem_sp--;
MessageBox(NULL,"Элемент удален!","",0);
return;
}
//удаляемый элемент - внутри подсписка из нескольких элементов
j=j-k;//количество элементов в списке до подсписка
//с удаляемым элементом
curr=current;
link *pr;//указатель на предыдущий по отношению к текущему (curr)
// элементу подсписка
while(j<r) //поиск элемента в подсписке
{
pr=curr;
curr=curr->down;
j++;
}
16
pr->down=curr->down;//выключение элемента из подсписка
delete curr; //удаление элемента
//количество элементов в подсписке уменьшаем на один
if(current->type==Roll) ((TRoll*)current)->count--;
else ((TBike*)current)->count--;
count_elem_sp--;//количество элементов в списке уменьшаем на один
MessageBox(NULL,"Элемент удален!","",0);
return;
}
//------------------------------------------------------------------------//удаление подсписка с выделенным в строке rd
//таблицы вывода списка элементом
void list::clear_down(int rd)
{
if(is_empty)
{
// MessageBox(NULL,"Список пуст!","",0);
return;
}
link *current=first;//указатель на текущий элемент списка
if(!current->next) //список состоит из одного подсписка
{
link *pr;//указатель на предыдущий по отношению
//к текущему (current) элементу подсписка
while(current)
{
pr=current;
current=current->down;
delete pr;
}
first=last=0;
count_dsp=0;
count_elem_sp=0;
is_empty=true;
MessageBox(NULL,"Список из одного подсписка уничтожен!","",0);
return;
}
17
int j;//номер текущей строки в таблице вывода списка
if(current->type==Roll) j=((TRoll*)current)->count;
else j=((TBike*)current)->count;
while(j<rd) //поиск подсписка с выделенным в таблице элементом
{
current=current->next;//переход на следующий подсписок
if(current->type==Roll) j+=((TRoll*)current)->count;
else j+=((TBike*)current)->count;
}
//выключение подсписка из списка
//выключаемый подсписок - первый в списке
if(!current->prev)
{
current->next->prev=0;
//перенос начала списка па следующий подсписок
first=current->next;
}
//выключаемый подсписок - последний в списке
else if(!current->next)
{
current->prev->next=0;
//перенос конца списка на предыдущий подсписок
last=current->prev;
}
//выключаемый подсписок - внутри списка
else
{
current->prev->next=current->next;
current->next->prev=current->prev;
}
count_dsp--;//количество подсписков в списке уменьшаем на один
//количество элементов в списке уменьшаем на подсписок
if(current->type==Roll)
count_elem_sp-=((TRoll*)current)->count;
else count_elem_sp-=((TBike*)current)->count;
//освобождение памяти, занимаемой подсписком
link *pr;//указатель на предыдущий по отношению
//к текущему (current) элементу подсписка
while(current)
{
pr=current;
current=current->down;
delete pr;
18
}
MessageBox(NULL,"Подсписок удален!","",0);
return;
}
//-----------------------------------------------------------------------//уничтожение списка
void list::clear()
{
if(is_empty)
{
MessageBox(NULL,"Список пуст!","",0);
return;
}
link *pr,*curr,*current=first;
int k;
while(current)
{
curr=current;
if(current->type==Roll) k=((TRoll*)current)->count;
else k=((TBike*)current)->count;
count_elem_sp-=k;
current=current->next;//переход на следующий подсписок
while(curr)
{
pr=curr;
curr=curr->down;
delete pr;
}
count_dsp--;
}
if(!count_dsp&&!count_elem_sp)
{
is_empty=true;
first-0;
last=0;
}
if(is_empty)
{
MessageBox(NULL,"Список уничтожен!","",0);
return;
}
}
19
//-----------------------------------------------------------------------Достаточно полную информацию для размещения остальных
компонентов на форме и задания их свойств можно получить из
представленных ниже рис.7.2, рис.7.3 и заголовочного файла модуля
LR_7.
Рис.7.2 – форма по окончании проектирования
Рис.7.3 – дерево объектов
Заголовочный файл LR_7.h модуля LR_7
//--------------------------------------------------------------------------#ifndef LR_7H
#define LR_7H
20
//--------------------------------------------------------------------------#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Grids.hpp>
#include <ComCtrls.hpp>
#include <ExtCtrls.hpp>
#include "CSPIN.h"
#include <ActnList.hpp>
#include <ActnMan.hpp>
#include <ImgList.hpp>
#include <StdActns.hpp>
#include <ActnCtrls.hpp>
#include <ActnMenus.hpp>
#include <ToolWin.hpp>
#include <Dialogs.hpp>
//--------------------------------------------------------------------------class TForm1 : public TForm
{
__published:
// IDE-managed Components
TStringGrid *StringGrid1;
TStatusBar *StatusBar1;
TGroupBox *GroupBox1;
TLabeledEdit *LabeledEdit1;
TLabeledEdit *LabeledEdit2;
TLabeledEdit *LabeledEdit3;
TRadioButton *RadioButton1;
TRadioButton *RadioButton2;
TCSpinEdit *CSpinEdit1;
TDateTimePicker *DateTimePicker1;
TButton *Button1;
TLabel *Label1;
TLabel *Label2;
TImageList *ImageList1;
TActionManager *ActionManager1;
TAction *FileSave1;
TAction *Add;
TAction *Del;
TAction *Clear_down;
TAction *Clear;
TAction *A_exit;
TActionMainMenuBar *ActionMainMenuBar1;
21
TAction *Out;
TSaveDialog *SaveDialog1;
TCheckBox *CheckBox1;
TAction *FileSaveAs1;
TAction *FileOpen1;
TActionToolBar *ActionToolBar2;
TActionToolBar *ActionToolBar1;
void __fastcall FormCreate(TObject *Sender);
void __fastcall RadioButton1Click(TObject *Sender);
void __fastcall RadioButton2Click(TObject *Sender);
void __fastcall AddExecute(TObject *Sender);
void __fastcall A_exitExecute(TObject *Sender);
void __fastcall OutExecute(TObject *Sender);
void __fastcall StringGrid1SelectCell(TObject *Sender, int ACol,
int ARow, bool &CanSelect);
void __fastcall DelExecute(TObject *Sender);
void __fastcall Clear_downExecute(TObject *Sender);
void __fastcall ClearExecute(TObject *Sender);
void __fastcall FileSave1Execute(TObject *Sender);
void __fastcall FileOpen1Execute(TObject *Sender);
void __fastcall FileSaveAs1Execute(TObject *Sender);
private:
// User declarations
public:
// User declarations
__fastcall TForm1(TComponent* Owner);
};
//--------------------------------------------------------------------------extern PACKAGE TForm1 *Form1;
//--------------------------------------------------------------------------#endif
Перенесем на форму остальные компоненты и зададим их свойствам
значения. Со страницы Стандарт - контрольный индикатор с флажком
CheckBox1 (Caption – добавлять и удалять с выводом в таблицу, Checked
– false), две радиокнопки – RadioButton1 (Caption - Велосипед, Checked –
true, Enabled - true) и RadioButton2 (Caption - Ролик. коньки, Checked –
false, Enabled - true), GroupBox1 (Caption – Велосипед), Label1 (Caption –
Дата поступления), Label2 (Caption – Кол-во скоростей), Button1
(Caption – Добавить элемент), со страницы Win32 – окно ввода дат и
времени DateTimePicker1, StatusBar1, ImageList1, со страницы
Дополнительно – LabeledEdit1 (EditLabel->Caption – Производитель:),
LabeledEdit2 (EditLabel->Caption – Колеса (мм):), LabeledEdit3
(EditLabel->Caption – Вес (кг):), диспетчер действий ActionManager1 и
полосу главного меню ActionMainMenuBar1, со страницы Примеры –
CSpinEdit1, со страницы Диалоги – SaveDialog1.
22
По умолчанию полоса главного меню расположится вверху, на всю
ширину формы. Задайте её свойство Align = alNone, чтобы придать ей
нужные размеры и расположить в нужном месте.
Диспетчеризация действий на основе компонентов ActionManager,
ActionMainMenuBar, ActionToolBar
Диспетчер действий ActionManager не только создает и хранит
набор действий, как и ActionList, но и управляет полосами действий –
визуальными компонентами, на которых располагаются элементы
пользовательского интерфейса. К таким компонентам относятся
ActionMainMenuBar – полоса главного меню и ActionToolBar –
инструментальная панель. Во время проектирования эти компоненты
могут вводиться в приложение непосредственно из палитры компонентов,
или создаваться простым перетаскиванием на них необходимых действий
из окна Редактора Действий ActionManager. Компонент ActionManager
запоминает информацию о составе набора действий и конфигурации полос
действий в текстовом или двоичном файле на диске.
Рассмотрим основной компонент всей этой системы –
ActionManager. Свойство Images компонента ActionManager указывает
на компонент ImageList, содержащий пиктограммы, используемые для
обозначения действий.
Загрузим в компонент ImageList1 пиктограммы из файлов fldropen,
filesave, floppy, insert, show, delete, arrow1u, erase, dooropen. В компоненте
ActionManager1 установим свойство Images равным ImageList1, связав
тем самым диспетчер действий со списком изображений.
Свойство State определяет реакцию на действия пользователя.
Значение asNormal соответствует нормальной рабочей реакции: при
щелчке пользователя на доступных интерфейсных компонентах действий
выполняются соответствующие действия.
Свойство FileName задает имя файла, в котором ActionManager
хранит информацию о составе связанных с ним полос действий. В начале
выполнения приложения ActionManager читает информацию из этого
файла и в соответствии с ней формирует полосы действий. А при любых
изменениях настройки в процессе выполнения ActionManager записывает
в этот файл проведенные изменения. Так что при следующем сеансе
работы состав полос действий будет таким, каким сделал его пользователь
в предыдущем сеансе.
Примечание. При изменении полос действий в процессе
проектирования нужно задавать значение FileName по окончании
проектирования, так как в противном случае в файле будет сохранено
состояние полос действий предыдущего сеанса. Если же потребовалось
изменить полосы действий после того, как было задано значение
FileName, то нужно предварительно удалить с диска файл, в котором
23
запоминается состояние. В этом случае при очередном выполнении
приложения этот файл создастся заново.
Если в процессе проектирования впервые задается значение
FileName, надо просто записать в этом свойстве имя файла с путем к нему.
При отсутствии пути файл будет создан в том каталоге, в котором
расположен проект. Если же нужно задать в качестве значения FileName
имя уже существующего файла, то можно воспользоваться для его выбора
кнопкой с многоточием около свойства FileName в окне Инспектора
Объектов.
Перейдем к рассмотрению и использованию основного инструмента
проектирования – Редактора Действий компонента ActionManager1.
Двойным щелчком на компоненте вызывается окно Редактора Действий
(Редактирование Form1->ActionManager1) на странице Действия с
пустыми панелями Категории: и Действия:. Щелкнем правой кнопкой
мыши и в появившемся контекстном меню выберем команду Новое
действие. Повторим команду Новое действие еще два раза. После этого в
панели Действия: появятся имена Action1, Action2, Action3 объектов этих
действий, а в панели Категории: – их категории. Выделим Action1. В
Инспекторе Объектов будут видны свойства, которые можно изменить:
Caption, Hint, ShortCut и другие. Строка свойства Hint отображается в
окне Редактора Действий в панели Описание. Можно изменить также
категории действий – их свойства Category. Если в компоненте ActionList
понятия категорий лишены определенного смысла, то здесь – при создании
меню названия категорий станут надписями головных разделов меню.
Зададим свойства объектов действий. Для Action1: Caption –
Сохранить, Category - Файл, Hint – сохранить список в файле, Name FileSave1, ShortCat - F2. Для Action2: Caption – Сохранить как, Category
- Файл, Hint – сохранить список в файле как…, Name - FileSaveAs1,
ShortCat – Ctrl+K. Для Action3: Caption – Открыть, Category - Файл,
Hint – вывести список из файла, Name - FileOpen1, ShortCat - Ctrl+O. В
свойство ImageIndex заносим соответствующие значения.
В дальнейшем действия будут связаны с соответствующими
компонентами, например, разделами меню. Щелчок пользователя на
разделе будущего меню инициализирует соответствующее действие, что
вызывает событие OnExecute. Для перехода в обработчик этого события
действия Сохранить сделайте на нем двойной щелчок. Занесите в
обработчик соответствующий код (см. файл реализации модуля LR_7).
Подобным же образом заполните обработчики для действий Сохранить
как и Открыть. Затем для всех действий задайте свойство Enabled = true.
Описанным выше образом командой Новое действие создайте
действия Action1, Action2, Action3, Action4, Action5, Action6. Для всех
этих действий в свойство Category внесите Действия. Задайте остальные
свойства новых объектов действий. Для Action1: Caption – Добавить
24
элемент, Hint – добавить элемент в список, Name - Add, ShortCat Ctrl+A. Для Action2: Caption – Вывести список, Hint – вывести список в
таблицу, Name - Out, ShortCat – Ctrl+T. Для Action3: Caption – Удалить
элемент, Hint – удалить элемент из списка, Name - Del, ShortCat Ctrl+B. Для Action4: Caption – Удалить подсписок, Hint – удалить
подсписок из списка, Name - Clear_down, ShortCat - Ctrl+C. Для Action5:
Caption – Уничтожить список, Hint – уничтожить список, Name Clear, ShortCat – Ctrl+D. Для Action6: Caption – Выход, Hint –
Выход/Завершение работы, Name - A_exit, ShortCat - Ctrl+E. В свойство
ImageIndex заносите соответствующие значения.
В обработчики события OnExecute этих шести действий внесите
коды из файла реализации модуля LR_7. Убедитесь, что для всех шести
действий свойство Enabled = true.
Теперь выбор категории (Файл, Действия) означает выбор
соответствующего списка действий. Порядок действий можно изменить
перетаскиванием мышью.
Поочередно перетащите мышью категории на полосу главного меню.
При этом все действия перенесутся в меню, а названия категорий станут
надписями головных разделов меню (см. рис.7.4). Действия также можно
перетаскивать в меню поодиночке и там изменять порядок их следования.
Перейдите на страницу Панели окна Редактора Действий. Кнопкой
Новый…добавьте на форму первую инструментальную панель
ActionToolBar1. (Отметим, что компонент ActionToolBar можно также
добавлять на форму переносом из палитры компонентов.) По умолчанию
панель расположится вверху, на всю ширину формы. Задайте её свойство
Align = alNone, чтобы придать ей нужные размеры и расположить в
нужном месте. Здесь и в дальнейшем может оказаться полезным задание
свойству Orientation
значения boTopToBottom или boBottomToTop.
Полезно также воспользоваться свойством Constraints. В свойство Hint
занесите инструментальная панель 1, в ShowHint – true.
Перейдите на страницу Действия окна Редактора Действий.
Перетащите из Редактора Действий на панель категорию Файл. При этом
все действия категории перенесутся на панель. Действия также можно
перетаскивать на панель поодиночке и там изменять порядок их
следования.
Описанным выше образом добавьте на форму вторую
инструментальную панель ActionToolBar2, задайте в ней свойства и
перетащите на неё категорию Действия.
Выделите одну из полос действий на странице Панели окна
Редактора Действий и просмотрите в Инспекторе Объектов ее свойства.
В свойствах Caption (надпись) измените значения полос действий
соответственно на Главное меню, Инструментальная панель 1,
Инструментальная панель 2.
25
Выделите компонент ActionManager1 и задайте значение свойства
FileName в окне Инспектора Объектов, т.е. имя файла, в котором
ActionManager1 хранит информацию о составе связанных с ним полос
действий.
Выделите кнопку Добавить элемент и в её свойство Action занесите
Add, чтобы связать кнопку с одноименным действием.
Дополните файл реализации модуля LR_7 обработчиками событий:
создания формы, где размещается код для создания заголовка таблицы, и
щелчков на компонентах RadioButton1 и RadioButton2, в которых
реализуется подготовка компонентов для ввода данных элементов списка.
Удаление элемента и подсписка из списка осуществляется по ячейке,
выделенной в таблице вывода списка. При этом используется событие
OnSelectCell компонента StringGrid1. В обработчик этого события
передаются целые параметры ACol и ARow – столбец и строка
выделенной ячейки и булев параметр CanSelect – допустимость выбора.
int r; //переменная для номера строки выделенной ячейки в таблице
bool flag=true; //флаг - нет выделенной ячейки в таблице
void __fastcall TForm1::StringGrid1SelectCell(TObject *Sender, int ACol,
int ARow, bool &CanSelect)
{
r=ARow; //номер строки выделенной ячейки сохранен в переменной r
flag=false; //ячейка в таблице выделена
}
Для удаления элемента и подсписка из списка используется параметр
ARow – номер строки выделенной ячейки.
На этом проектирование приложения завершается.
Рис.7.4 – меню
Тестирование и использование приложения
1. Запустите приложение на выполнение, нажав быстрые
Сохранить все и Запуск.
26
кнопки
2. Выполните тестирование по рис.7.5. Рекомендуется добавлять и удалять
элементы с включенным индикатором. Команда Вывести список
необходима при отладке и тестировании приложения.
3. Составьте и выполните тесты, которые проверят правильность всех
случаев добавления и удаления элементов подсписков (см. комментарии в
файлах f_7.cpp и LR_7.cpp).
4. Убедитесь в правильности сохранения списка в файле.
5. Модифицируйте код, переместив данные-элементы классов TRoll и
TBike в закрытые части классов. Выполните отладку. Результаты
продемонстрируйте преподавателю.
Рис.7.5 – форма с результатами тестирования
Файл реализации LR_7.cpp модуля LR_7
//--------------------------------------------------------------------------#include <vcl.h>
#pragma hdrstop
#include "LR_7.h"
#include "f_7.h"
#include<string.h>
#include<fstream.h>
//---------------------------------------------------------------------------
27
#pragma package(smart_init)
#pragma link "CSPIN"
#pragma resource "*.dfm"
TForm1 *Form1;
//--------------------------------------------------------------------------__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
}
//--------------------------------------------------------------------------//при создании формы создаем заголовок таблицы
void __fastcall TForm1::FormCreate(TObject *Sender)
{
StringGrid1->FixedRows=1;
StringGrid1->RowCount=1;
StringGrid1->FixedCols=0;
StringGrid1->ColCount=8;
StringGrid1->Cells[0][0]="номер";
StringGrid1->Cells[1][0]="изделие";
StringGrid1->Cells[2][0]="кол-во(шт) в п/сп";
StringGrid1->Cells[3][0]="дата поступления";
StringGrid1->Cells[4][0]="производитель";
StringGrid1->Cells[5][0]="диам колес(мм)";
StringGrid1->Cells[6][0]="вес(кг)";
StringGrid1->Cells[7][0]="кол-во скоростей";
}
//--------------------------------------------------------------------------//активация компонентов для ввода данных элемента списка - велосипед
void __fastcall TForm1::RadioButton1Click(TObject *Sender)
{
GroupBox1->Caption="Велосипед";
DateTimePicker1->SetFocus();
LabeledEdit3->Enabled=true;
CSpinEdit1->Enabled=true;
Label2->Enabled=true;
}
//--------------------------------------------------------------------------//подготовка компонентов для ввода данных элемента
// списка - ролик. коньки
void __fastcall TForm1::RadioButton2Click(TObject *Sender)
28
{
GroupBox1->Caption="Ролик. коньки";
DateTimePicker1->SetFocus();
LabeledEdit3->Enabled=false;
CSpinEdit1->Enabled=false;
Label2->Enabled=false;
}
//--------------------------------------------------------------------------list spisok;//создаем объект класса - список
void __fastcall TForm1::AddExecute(TObject *Sender)
{
if(RadioButton1->Checked)
{ //создаем элемент списка - велосипед
TBike *bike=new TBike;
strcpy(bike->date,(DateToStr(DateTimePicker1->Date)).c_str());
if(LabeledEdit1->Text=="")
{
MessageBox(NULL,"Введите название производителя!","Ошибка", 0);
LabeledEdit1->SetFocus();
return;
}
strcpy(bike->comp,(LabeledEdit1->Text).c_str());
if(LabeledEdit2->Text==""||!isdigit(LabeledEdit2->Text[1]))
{
MessageBox(NULL,"Введите диаметр колес!","Ошибка",0);
LabeledEdit2->SetFocus();
return;
}
bike->diam=StrToInt(LabeledEdit2->Text);
if(LabeledEdit3->Text==""||!isdigit(LabeledEdit3->Text[1]))
{
MessageBox(NULL,"Введите вес!","Ошибка",0);
LabeledEdit3->SetFocus();
return;
}
bike->weight=StrToFloat(LabeledEdit3->Text);
bike->speeds=CSpinEdit1->Value;
//созданный элемент добавляем в список
spisok.append_bike(bike);
}
29
if(RadioButton2->Checked)
{ //создаем элемент списка - роликовые коньки
TRoll *roll=new TRoll;
strcpy(roll->date,(DateToStr(DateTimePicker1->Date)).c_str());
if(LabeledEdit1->Text=="")
{
MessageBox(NULL,"Введите название производителя!","Ошибка",0);
LabeledEdit1->SetFocus();
return;
}
strcpy(roll->comp,(LabeledEdit1->Text).c_str());
if(LabeledEdit2->Text==""||!isdigit(LabeledEdit2->Text[1]))
{
MessageBox(NULL,"Введите диаметр колес!","Ошибка",0);
LabeledEdit2->SetFocus();
return;
}
roll->diam=StrToInt(LabeledEdit2->Text);
//созданный элемент добавляем в список
spisok.append_roll(roll);
}
MessageBox(NULL,"Элемент добавлен!","",0);
//если индикатор включен - список выводится в таблицу
if(CheckBox1->Checked)spisok.out_list();
//вывод информации о списке
Form1->StatusBar1->SimpleText="Количество подсписков - "+
IntToStr(spisok.count_dsp)+" "+"Количество элементов в списке - "+
IntToStr(spisok.count_elem_sp);
}
//--------------------------------------------------------------------------void __fastcall TForm1::A_exitExecute(TObject *Sender)
{
Close();
}
//--------------------------------------------------------------------------//вывод списка в таблицу
void __fastcall TForm1::OutExecute(TObject *Sender)
{
30
spisok.out_list();
}
//--------------------------------------------------------------------------int r; //переменная для номера строки выделенной ячейки в таблице
bool flag=true; //флаг - нет выделенной ячейки в таблице
void __fastcall TForm1::StringGrid1SelectCell(TObject *Sender, int ACol,
int ARow, bool &CanSelect)
{
r=ARow; //номер строки выделенной ячейки сохранен в переменной r
flag=false; //ячейка в таблице выделена
}
//--------------------------------------------------------------------------//удаляем из списка элемент, соответствующий номеру
//строки выделенной в таблице ячейки
void __fastcall TForm1::DelExecute(TObject *Sender)
{
if(spisok.is_empty)//если список пуст
{
MessageBox(NULL,"Список пуст!","",0);
return;
}
if(flag) //если ячейка в таблице не выделена
{
MessageBox(NULL,"Выделите элемент в таблице!","Ошибка",0);
return;
}
//удаляем из списка элемент, соответствующий значению переменной r
spisok.del(r);
//если индикатор включен - список выводится в таблицу
if(CheckBox1->Checked)spisok.out_list();
flag=true;//можно снова выделять ячейку в таблице
}
//--------------------------------------------------------------------------//удаляем из списка подсписок, соответствующий номеру
// строки выделенной в таблице ячейки
void __fastcall TForm1::Clear_downExecute(TObject *Sender)
31
{
if(spisok.is_empty) //если список пуст
{
MessageBox(NULL,"Список пуст!","",0);
return;
}
if(flag) //если ячейка в таблице не выделена
{
MessageBox(NULL,"Выделите элемент в таблице!","Ошибка",0);
return;
}
//удаляем из списка подсписок, соответствующий значению переменной r
spisok.clear_down(r);
//если индикатор включен - список выводится в таблицу
if(CheckBox1->Checked)spisok.out_list();
flag=true; //можно снова выделять ячейку в таблице
}
//--------------------------------------------------------------------------//уничтожаем список
void __fastcall TForm1::ClearExecute(TObject *Sender)
{
if(spisok.is_empty) //если список пуст
{
MessageBox(NULL,"Список пуст!","",0);
return;
}
//для объекта - список вызывается функция уничтожения списка
spisok.clear();
//уничтожение списка контролируется выводом в таблицу
spisok.out_list();
}
//--------------------------------------------------------------------------AnsiString fn=""; //строка для имени файла
//вспомогательная строка для вывода списка из таблицы в файл
char str[50];
32
int s;//вспомогательная переменная для вывода в файл
//количества элементов в списке
//--------------------------------------------------------------------------//сохраняем список в файле
void __fastcall TForm1::FileSave1Execute(TObject *Sender)
{
if(fn!="") //если есть имя файла со списком
{
ofstream outfile(fn.c_str(),ios::out);//открываем файл для записи
//в переменную s заносим количество элементов в списке
s=spisok.count_elem_sp;
//выводим в файл число из переменной s побайтно
outfile.write((char*)&s,sizeof(s));
//из таблицы список выводим в файл
for(int i=1; i<=s; i++)
{
for(int j=0;j<8;j++)
{ //преобразовав элемент из таблицы к типу char*,
//копируем его в вспомогательную строку str
strcpy(str,Form1->StringGrid1->Cells[j][i].c_str());
//выводим побайтно содержимое str в файл
outfile.write((char*)&str,50);
}
}
outfile.close();//закрываем файл
}
else //если файл со списком отсутствует
//открывается диалог сохранения в файле и пользователь
//выбирает имя файла
if(SaveDialog1->Execute())
{ //выбранное имя файла сохраняется в строке fn
fn=SaveDialog1->FileName;
//создается и открывается для записи файл с выбранным именем
ofstream outfile(fn.c_str(),ios::out);
//в переменную s заносим количество элементов в списке
s=spisok.count_elem_sp;
//выводим в файл число из переменной s побайтно
outfile.write((char*)&s,sizeof(s));
//из таблицы список выводим в файл
33
for(int i=1; i<=s; i++)
{
for(int j=0;j<8;j++)
{ //преобразовав элемент таблицы к типу char*,
//копируем его во вспомогательную строку str
strcpy(str,Form1->StringGrid1->Cells[j][i].c_str());
//выводим побайтно содержимое str в файл
outfile.write((char*)&str,50);
}
}
outfile.close();//закрываем файл
}
}
//--------------------------------------------------------------------------//выводим список из файла в таблицу
//по данным таблицы формируем список в оперативной памяти
void __fastcall TForm1::FileOpen1Execute(TObject *Sender)
{
spisok.clear();//уничтожаем список в оперативной памяти
//открываем файл на чтение с выбранным при сохранении именем
ifstream infile(fn.c_str(),ios::in);
if(!infile) //проверка, удалось ли открыть файл
{
MessageBox(NULL,"Файл не удается открыть!","Ошибка",0);
return;
}
//в переменную s читаем из файла количество элементов в списке
infile.read((char*)&s,sizeof(s));
//читаем файл в таблицу
for(int i=1; i<=s; i++)
{
Form1->StringGrid1->RowCount++;//добавляем строку в таблице
for(int j=0;j<8;j++)
{ //читаем в строку str из файла очередную запись в 50 байт
infile.read((char*)&str,50);
//из строки str переносим запись в элемент таблицы
Form1->StringGrid1->Cells[j][i]=(AnsiString)str;
}
34
}
infile.close();//закрываем файл, открытый на чтение
//из данных строк таблицы формируем элементы списка
//элементы списка добавляем в список
for(int i=1; i<=s; i++)
{
if(StringGrid1->Cells[1][i]=="Bike")
{ //формируем элемент списка - велосипед
TBike* bike=new TBike;
strcpy(bike->date,StringGrid1->Cells[3][i].c_str());
strcpy(bike->comp,StringGrid1->Cells[4][i].c_str());
bike->diam=StrToInt(StringGrid1->Cells[5][i]);
bike->weight=StrToFloat(StringGrid1->Cells[6][i]);
bike->speeds=StrToInt(StringGrid1->Cells[7][i]);
spisok.append_bike(bike);//добавляем в список
}
if(StringGrid1->Cells[1][i]=="Roll")
{ //формируем элемент списка - роликовые коньки
TRoll* roll=new TRoll;
strcpy(roll->date,StringGrid1->Cells[3][i].c_str());
strcpy(roll->comp,StringGrid1->Cells[4][i].c_str());
roll->diam=StrToInt(StringGrid1->Cells[5][i]);
spisok.append_roll(roll);//добавляем в список
}
}
spisok.out_list(); //выводим прочитанный список в таблицу
//вывод информации о прочитанном списке
StatusBar1->SimpleText="Количество подсписков - "+
IntToStr(spisok.count_dsp)+" "+
"Количество элементов в списке - "+
IntToStr(spisok.count_elem_sp);
}
//--------------------------------------------------------------------------//сохраняем как...
void __fastcall TForm1::FileSaveAs1Execute(TObject *Sender)
{
//выбранное ранее имя файла заносится в свойство FileName
//компонента SaveDialog1 и предлагается пользователю по умолчанию
35
SaveDialog1->FileName=fn;
//если при открытии диалога пользователь выбрал новое имя
if(SaveDialog1->Execute())
{ //то новое имя файла сохраняется в строке fn
fn=SaveDialog1->FileName;
//создается и открывается для записи файл с новым именем
ofstream outfile(fn.c_str(),ios::out);
if(!outfile) //проверка, удалось ли создать и открыть файл
{
MessageBox(NULL,"Файл не удается создать!","Ошибка",0);
return;
}
//в переменную s заносим количество элементов в списке
s=spisok.count_elem_sp;
//выводим в файл число из переменной s побайтно
outfile.write((char*)&s,sizeof(s));
//из таблицы список выводим в файл
for(int i=1; i<=s; i++)
{
for(int j=0;j<8;j++)
{ //преобразовав элемент таблицы к типу char*,
//копируем его в вспомогательную строку str
strcpy(str,Form1->StringGrid1->Cells[j][i].c_str());
//выводим побайтно содержимое str в файл
outfile.write((char*)&str,50);
}
}
outfile.close(); //закрываем файл
}
}
//---------------------------------------------------------------------------
36
Download