2. Разработка многомодульных приложений (548347), страница 2
Текст из файла (страница 2)
StringGrid1->Cells[0][i]="Строка" + IntToStr(i);
// В нулевой строке – номера столбцов
for (j=1; j<=n; j++)
StringGrid1->Cells[j][0]="Столбец" + IntToStr(j);
// Значения ячеек обнуляются
for (i=1;i<=n; i++)
for (j=1; j<=m; j++)
StringGrid1->Cells[j][i]="0";
}
Оформить каждую ячейку таблицы компонента StringGrid можно, воспользовавшись событием OnDrawCell, которое возникает каждый раз при необходимости перерисовки ячейки. Параметры ARow, ACol задают номер ячейки, а Rect – координаты прямоугольника для рисования. Следующий код задает новый цвет фона для фиксированных ячеек компонента StringGrid1:
void __fastcall TForm1::StringGrid1DrawCell(Tobject
*Sender, int ACol,int ARow, TRect &Rect,
TGridDrawState State)
{ if (ARow==0 && ACol==0) //Ячейка(0,0)– красный фон
{ StringGrid1->Canvas->Brush->Color = clRed;
StringGrid1->Canvas->FillRect(Rect);
}
else
{ if ( ACol==0) // нулевой столбец: фон - желтый
{ StringGrid1->Canvas->Brush->Color =
clYellow;
StringGrid1->Canvas->FillRect(Rect);
StringGrid1->Canvas ->
TextOut(Rect.Left+2,Rect.top+2,
StringGrid1->Cells[ACol][ARow]);
}
// нулевая строка: фон – бледно-голубой
if ( ARow==0)
{ StringGrid1->Canvas->Brush->Color =
clSkyBlue;
StringGrid1->Canvas->FillRect(Rect);
StringGrid1->Canvas->
TextOut(Rect.Left+2,Rect.top+2,
StringGrid1->Cells[ACol][ARow]);
}
}
}
Обработчик команды меню Вычисления – Настройки… вызывает диалоговое окно (Form5) в модальном режиме и после его закрытия проверяет настройки произведенные пользователем. Кнопки вычислений (Button1, Button2 и Button3) на главной форме становятся доступны в зависимости от выбранной части массива для проведения вычислений (возможные варианты представлены в ComboBox1 на Form5):
void __fastcall TForm1::OptionClick(TObject *Sender)
{
Form5->ShowModal();
int id = Form5 -> ComboBox1 -> ItemIndex;
Button1->Enabled=false;
Button2->Enabled=false;
Button3->Enabled=false;
switch (id)
{
case 0: Button1 -> Enabled = true;
break;
case 1: Button2 -> Enabled = true;
break;
case 2: Button3 -> Enabled = true;
break;
}
}
Команда меню Вычисления - Вычислить выполняет те же действия, что и отдельные кнопки, но предварительно выясняет, как именно производятся вычисления: по строкам, по столбцам или для всего массива. Чтобы программный код не повторялся, в обработчике команды производятся обращения к обработчикам кнопок, так как будто щелчок на кнопке произведен пользователем:
void __fastcall TForm1:CalculateClick(TObject *Sender)
{
int id = Form5 -> ComboBox1 -> ItemIndex;
switch (id)
{
case 0: Button1Click(this);
break;
case 1: Button2Click(this) ;
break;
case 2: Button3Click(this) ;
break;
}
}
Рассмотрим обработчики команд выполняющих непосредственно вычисления в двумерном массиве. Кнопка Button1 отвечает за обработку всего массива:
void __fastcall TForm1::Button1Click(TObject *Sender)
{
int i, j;
char str[40];
bool flag = false;
float a[6][6];
float b;
// В цикле производится попытка перевести строковые
// данные ячеек таблицы
// в вещественные числа и записать их в массив a.
// При возникновении ошибок
// элемент массива a[i][j] обнуляется
for (i=0; i for (j=0; j { try {a[i][j]=(StrToFloat)(StringGrid1-> Cells[j+1][i+1]); } catch (EConvertError&) { a[i][j]=0; flag = true;} } int id=Form5->RadioGroup1->ItemIndex; switch (id) { case 0: // Вычислить среднее арифметическое //.Обращение к функции модуля “Unit2” strcpy(str," SA = "); break; case 1: //Здесь следует разместить обращения к //функциям модуля “Unit2” break; //... case 3: // Вычисление максимального значения // max_massiv (a,b); - вызов функции strcpy(str," MAX = "); break; //… } // Создание формы для вывода результатов Application->CreateForm(__classid(TForm6),&Form6); Form6 -> Caption = Form5->RadioGroup1->Items->Strings[id]; // Вывод результата AnsiString AStr; AStr = (AnsiString)str + FloatToStr(b); Form6 -> Memo1 -> Lines->Insert(0,AStr); // После проверки наличия ошибок в компонент Memo1 // добавляется информационное сообщение if (flag) Form6 -> Memo1 -> Lines->Insert(1,"В исходных данных найдены ошибки"); if (!Form6->Visible) Form6->ShowModal(); delete(Form6); } Щелчок на кнопке Button2 приводит к вычислениям по строкам. Результаты вычисления помещаются в столбец компонента Form3->StringGrid1. void __fastcall TForm1::Button2Click(TObject *Sender) { int i, j; bool flag=false; float a[6][6]; float b[6] = {0}; for (i=0; i for (j=0; j { try {a[i][j]=(StrToFloat)(StringGrid1-> Cells[j+1][i+1]); } catch (EConvertError&) { a[i][j]=0; flag=true; } } // При наличии ошибок в исходных данных // выдается соответствующее информационное сообщение. // Вычисления не производятся. if (flag) Application -> MessageBox("Массив содержит некорректные данные", "Информация", MB_OK+MB_ICONEXCLAMATION); else { int id=Form5->RadioGroup1->ItemIndex; switch (id) { case 0: // Вычисление среднего арифметического sr_ar_stroka (a,b); break; case 1: //Здесь следует разместить обращения //к функциям модуля “Unit2” //... break; //... } // Вывод результатов на Form3 for (i=0; i Form3->StringGrid1->Cells[1][i+1] = (FloatToStr)(b[i]); Form3 -> Caption=Form5-> RadioGroup1->Items->Strings[id]; Form3->Show(); } } Следующие два обработчика используют стандартные диалоговые окна сохранения и открытия файлов. Компонент StringGrid не имеет метода для сохранения значений в файл, но можно воспользоваться методом компонента Memo. Для этого на главную форму поместим Memo1 и сделаем его невидимым во время выполнения программы (свойство Visible = false). void __fastcall TForm1::SaveClick(TObject *Sender) { AnsiString FName; int i, j; if (SaveDialog1 -> Execute()) { FName=SaveDialog1->FileName; Memo1->Clear(); // Значения из ячеек добавляем по порядку в строки // компонента Memo1 for (i=1; i<=n; i++) for (j=1; j<=m; j++) Memo1->Lines ->Add(StringGrid1-> Cells[i][j]); // Сохранить строки в файле с именем FName Memo1->Lines->SaveToFile(FName); } } Команда Файл – Открыть осуществляет обратные действия, то есть вводит строковые данные в Memo1, а затем по порядку записывает строчки в ячейки компонента StringGrid1->Cells[i][j]. void __fastcall TForm1::OpenClick(TObject *Sender) { AnsiString FName, s; int i, j, id; if (OpenDialog1 -> Execute()) { FName=OpenDialog1->FileName; // Загрузить данные из файла Memo1->Lines->LoadFromFile(FName); id=0; for (i=1; i<=n; i++) for (j=1; j<=m; j++) { s= Memo1->Lines->Strings[id]; StringGrid1-> Cells[i][j]=(AnsiString)s; id++; } } } Разработать многомодульную программу, осуществляющую вычислительные операции над массивами (за основу взять приложение представленное в этом документе). Состав проекта Главная форма должна содержать меню и управлять работой всего приложения. Кроме меню на форме может быть расположена картинка – эмблема. Форма для ввода исходных данных должна содержать компонент для ввода исходного массива. Форма для задания режимов обработки массива (диалоговое окно) должна содержать управляющие элементы по выбору программиста (радиокнопки, кнопки выбора, списки и т.д.). Одна или несколько форм для вывода результатов вычислений. Окно «О программе…». Проект этого окна можно скопировать из репозитория объектов. Автономный модуль, содержащий функции для обработки двумерных вещественных массивов. Порядок создания приложения Создать новое Windows –приложение и сохранить проект в отдельной папке. Создать макет главной формы приложения и сохранить его. Продумать внешний вид каждой формы и создать в Builder C++ макеты форм, каждый раз добавляя их в созданный проект и сохраняя в той же папке. Установить связь между формами. Все формы должны быть «видимы» из главной формы и вызываться только из нее. Включить в проект автономный модуль. Разработать и внести в модуль код функций для работы с массивами (код не должен содержать ссылок на формы и компоненты). Массивы должны передаваться в функции в качестве параметров. Написать обработчики для всех событий меню и кнопок. В модуле главной формы предусмотреть объявление вспомогательных массивов (они будут передаваться в качестве фактических параметров в вычислительные функции автономного модуля) и запись в них данных из компонентов формы. Примечание: для того, чтобы добиться правильного построения проекта и проверить его работоспособность можно сначала написать код только одной вычислительной функции (например, вычислять максимальный элемент массива). Проект протестировать и добиться правильной работы. Затем добавить функцию, получающую в качестве результата одномерный массив, например, среднее арифметическое по строкам и проверить работу. Затем дописать все остальные функции и процедуры. Проверка работоспособности приложения После старта приложения открыть форму для ввода исходных данных и ввести значения элементов исходного массива. Сохранить данные в файле. Изменить введенный массив. Открыть диалоговое окно для выбора режима вычисления и указать в нем расчетную процедуру (вычисление для всего массива). Выполнить вычисление и проверить результат. Затем проверить работы процедур для строк и столбцов. Открыть созданный файл и проверить работу процедур, используя сохраненные данные. Открыть окно «О программе» и получить информацию об авторе программного продукта.Задание