Практическое занятие № 9
Тема: "Работа с табличными данными. Построение графиков и диаграмм"
Цель работы: получить практические навыки для отображения и обработки табличных данных, а также построения графиков и диаграмм.
Ход работы
Создать программу для работы с табличными данными. При этом главная форма программы имеет вид:

Указания: для формы задайте свойства: Caption = текст заголовка, BorderStyle = bsSingle, BorderIcons - Maximized = false, Position = poDesktopCenter.
Для создания сетки нанесите на форму компонент StringGrid (Additional) и задайте для него свойства: ColCount = 8, RowCount=5, Options (включите goEditing, goTab).
Для настройки параметров шапки таблицы в событии OnCreate формы введите код:
procedure TForm1.FormCreate(Sender: TObject);
begin
//задаем ширину колонки с указанным номером
StringGrid1.ColWidths[0]:=40;
//задаем текст надписи в первой строке (нумерация с 0)
//и колонке с указанным номером
StringGrid1.Cells[0,0]:='№ п/п';
StringGrid1.ColWidths[1]:=100;
StringGrid1.Cells[1,0]:='Фамилия';
StringGrid1.ColWidths[2]:=100;
StringGrid1.Cells[2,0]:='Имя';
StringGrid1.ColWidths[3]:=100;
StringGrid1.Cells[3,0]:='Отчество';
StringGrid1.ColWidths[4]:=100;
StringGrid1.Cells[4,0]:='Дата рожд.';
StringGrid1.ColWidths[5]:=40;
StringGrid1.Cells[5,0]:='Пол';
StringGrid1.ColWidths[6]:=60;
StringGrid1.Cells[6,0]:='Ср.балл';
StringGrid1.ColWidths[7]:=60;
StringGrid1.Cells[7,0]:='Стипендия';
end;
При вводе среднего балла строки в сетке должны закрашиваться цветами: 5 - зеленый, 4 - синий, 3 - желтый, 2 - красный. Активная ячейка в сетке должна окрашиваться салатовым цветом. Текст в ячейках выравнивается так: ФИО - по левому краю, остальные - по центру.
Указания: в событии OnDrawCell сетки введите код окрашивания:
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
//метка для перехода к блоку выдачи текста в сетке
begin
//если ячейка относится к фиксированной области, то конец
if (ACol=0) or (ARow=0) then exit;
//если ячейка активная, то фон для нее салатовый
if gdFocused in State then
StringGrid1.Canvas.Brush.Color:=clLime;
//если в 7 колонке нет данных (средний балл не введен)
if StringGrid1.Cells[6,ARow]='' then
//цвет фон ячеек белый
StringGrid1.Canvas.Brush.Color:=clWhite
//если балл 5
else if StrToFloat(StringGrid1.Cells[6,ARow])=5 then
//цвет фона зеленый
StringGrid1.Canvas.Brush.Color:=clGreen
//если средний балл 4 и выше
else if StrToFloat(StringGrid1.Cells[6,ARow])>=4 then
//цвет фона синий
StringGrid1.Canvas.Brush.Color:=clBlue
//если средний балл 3 и выше
else if StrToFloat(StringGrid1.Cells[6,ARow])>=3 then
//цвет фона желтый
StringGrid1.Canvas.Brush.Color:=clYellow
else
//во всех остальных случая цвет фона красный
StringGrid1.Canvas.Brush.Color:=clRed;
//заливаем строку сетки указанным фоном
StringGrid1.Canvas.FillRect(Rect);
//блок вывода текста в сетку
//если колонки не 1, не 2 или не 3 (не ФИО)
if (ACol<>1) or (ACol<>2) or (ACol<>3) then
//выдаем текст по центру ячейки
StringGrid1.Canvas.TextOut((Rect.Left+(Rect.Right-Rect.Left-Canvas.TextWidth(StringGrid1.Cells[ACol,ARow]))div 2), Rect.Top+2,StringGrid1.Cells[ACol,ARow])
//ячейки с ФИО выдаем по левому краю
else
StringGrid1.Canvas.TextOut(Rect.Left+2, Rect.Top+2,StringGrid1.Cells[ACol,ARow]);
end;
Колонка "Стипендия" рассчитывается по формуле: средний балл * 120. При этом необходимо отфильтровать ввод в колонку "Средний балл", чтобы пользователь не мог ввести никаких данных кроме оценок в диапазоне от 2 до 5.
Указания: в событии сетки OnSetEditText введите код:
procedure TForm1.StringGrid1SetEditText(Sender: TObject; ACol,ARow: Integer; const Value: String);
//переменная для считывания значения из ячейки сетки
var ch:real;
begin
//если редактируется не 7 колонка (не средний балл)
if ACol<>6 then
//процедура завершает свою работу
Exit;
//пытаться выполнить код
Try
//конвертируем содержимое ячейки 7 колонки в число
ch:=StrToFloat(StringGrid1.Cells[6,ARow]);
//если конвертирование удалось и
//полученное значение попадает в допустимый диапазон (от 2 до 5)
if (ch>=2) and (ch<=5) then
begin
//считаем размер стипендии
StringGrid1.Cells[7,ARow]:=FloatToStr(StrToFloat(StringGrid1.Cells[6,ARow])*120);
//завершаем работу процедуры
Exit;
end;
//если конвертирование не удалось (в ячейке не число)
//ничего не делаем (пустой оператор "точка с запятой")
Except ;
end;
//если работа процедуры не завершена (в ячейке не число или
//оно не попадает в диапазон от 2 до 5)
//колонки "Средний балл" и "Стипендия" очищаются
StringGrid1.Cells[6,ARow]:='';
StringGrid1.Cells[7,ARow]:='';
end;
end;
Замечание: в приведенном коде присутствует команда обработки исключений
Try
. . .
Except
. . .
End;
По умолчанию данный оператор не выполняется при компиляции программы. Для работы оператора необходимо выполнить настройку среды: выполните команду Tools - Options. В левой части раскройте узел Debugger Options, затем узел CodeGear Debuggers, выберите узел Language Exception. В правой части окна выключите флажок Notify on language exception.
Так как колонка "Стипендия" рассчитывается по формуле, то необходимо заблокировать возможность установки в нее курсора для редактирования.
Указания: В событии сетки OnSelectCell введите код:
procedure TForm1.StringGrid1SelectCell(Sender: TObject; ACol,ARow: Integer; var CanSelect: Boolean);
begin
//если колонка 8 (Стипендия)
if ACol=7 then
//блокируем установку в нее курсора
CanSelect:=false;
end;
При закрашивании сетка не отображает цвет строки корректно: закрашивается только активная ячейка и ячейка с расчетной стипендией. Остальные ячейки не успевают перерисоваться..
Указания: для решения данной проблемы нужно перерисовывать сетку при окончании ввода среднего балла. Окончание ввода может произойти в нескольких случаях:
- курсор перевели на другую ячейку в сетке (событие сетки OnSelectCell);
- курсор перевели за пределы сетки (событие сетки OnExit);
- пользователь нажал клавишу Enter (событие формы OnKeyDown).
В событии OnSelectCell добавьте команду
//перерисовать сетку
StringGrid1.Repaint;
В событии OnExit введите код:
procedure TForm1.StringGrid1Exit(Sender: TObject);
begin
//перерисовать сетку
StringGrid1.Repaint;
end;
Для реакции нажатия на клавишу Enter для формы установите свойство KeyPreview = true. В событии OnKeyDown сетки введите код:
procedure TForm1.StringGrid1KeyDown(Sender: TObject; var Key: Word;Shift: TShiftState);
begin
//и нажата клавиша Enter
if (Key=VK_RETURN then
//перерисовать сетку
StringGrid1.Repaint;
end;
Организуем добавление данных в сетку через вспомогательную форму вида:

Указания: добавьте новую форму и перенесите ее в спиcок Available Forms. Для формы задайте свойства: Caption = Данные, BorderStyle = bsDialog, Position = poDesktopCenter. Форма должна при закрытии удаляться из памяти. для этого в событии OnClose формы введите код:
procedure TForm2.FormClose(Sender: TObject; var Action: TCloseAction);
begin
Action:=caFree;
end;
Нанесите на форму надписи и текстовые поля, а также две кнопки. Кнопка отменить просто закрывает окно:
procedure TForm2.Button2Click(Sender: TObject);
begin
Close;
end;
Поле "Средний балл" должно фильтровать ввод: можно ввести оценку в диапазоне от 2 до 5. Для этого в событии OnChange поля введите код:
procedure TForm2.Edit6Change(Sender: TObject);
//переменная для считывания содержимого поля
var ch:real;
begin
//пытаться выполнить действия
Try
//конвертируем поле в число
ch:=StrToFloat(Edit6.Text);
//если конвертирование удалось, но полученное число не в допустимом диапазоне
if (ch<2) or (ch>5) then
//поле очищается
edit6.Text:='';
//если конвертирование не удалось (в поле не число)
Except
//поле очищается
edit6.Text:='';
end;
end;
Кнопка "Сохранить" добавляет в сетку новую строку и заполняет колонки сетки полями из формы.
procedure TForm2.Button1Click(Sender: TObject);
begin
//если ФИО или средний балл не введены, то процедура не выполняется
if (Edit1.Text='') or (Edit2.Text='') or (Edit3.Text='') or (Edit6.Text='') then
Exit;
//увеличиваем количество строк на 1
Form1.StringGrid1.RowCount:=Form1.StringGrid1.RowCount+1;
//заполняем колонки сетки полями из формы
Form1.StringGrid1.Cells[0,Form1.StringGrid1.RowCount-1]:=
IntToStr(Form1.StringGrid1.RowCount-1);
Form1.StringGrid1.Cells[1,Form1.StringGrid1.rOwCount-1]:=Edit1.Text;
Form1.StringGrid1.Cells[2,Form1.StringGrid1.RowCount-1]:=Edit2.Text;
Form1.StringGrid1.Cells[3,Form1.StringGrid1.RowCount-1]:=Edit3.Text;
Form1.StringGrid1.Cells[4,Form1.StringGrid1.RowCount-1]:=Edit4.Text;
Form1.StringGrid1.Cells[5,Form1.StringGrid1.RowCount-1]:=Edit5.Text;
Form1.StringGrid1.Cells[6,Form1.StringGrid1.RowCount-1]:=Edit6.Text;
Form1.StringGrid1.Cells[7,form1.StringGrid1.RowCount-1]:=
FloatToStr(StrToFloat(Edit6.Text)*120);
//закрываем форму
Close;
end;
На главной форме разместите кнопку Добавить и введите для нее код:
procedure TForm1.Button1Click(Sender: TObject);
begin
Form2:=TForm2.Create(nil);
Form2.ShowModal;
end;
Организуйте удаление выбранной строки из сетки.
Указания: нанесите на главную форму кнопку и для нее напишите код:
procedure TForm1.Button5Click(Sender: TObject);
//переменные для организации цикла
var i,j:integer;
begin
//если число строк в сетке =1 (только шапка)
if StringGrid1.RowCount=1 then
//завершаем работу процедуры
Exit;
//выдаем запрос на удаление текущей строки
//если на запрос ответили нет, то завершаем работу процедуры
if Application.MessageBox(Pchar('Удалить данные о студенте: '
+StringGrid1.Cells[1,StringGrid1.Row]+' '
+StringGrid1.Cells[2,StringGrid1.Row]+' '
+StringGrid1.Cells[3,StringGrid1.Row]),
'Подтвердите операцию',MB_YESNO+MB_IconQuestion)=IDNO then
Exit;
//в цикле смещаем все строки под удаляемой на 1 позицию вверх
for i:=0 to StringGrid1.ColCount-1 do
for j:=StringGrid1.Row to StringGrid1.RowCount-2 do
StringGrid1.Cells[i,j]:=StringGrid1.Cells[i,j+1];
//в сетке должно всегда оставаться 2 строки (шапка + новая строка)
//если в сетке более 2 строк
if StringGrid1.RowCount>2 then
//уменьшаем в сетке количество строк на 1
StringGrid1.RowCount:= StringGrid1.RowCount-1
//иначе, если строк 2
//очистим все колонки этой строки без уменьшения количества
else
begin
StringGrid1.Cells[0,StringGrid1.Row]:='';
StringGrid1.Cells[1,StringGrid1.Row]:='';
StringGrid1.Cells[2,StringGrid1.Row]:='';
StringGrid1.Cells[3,StringGrid1.Row]:='';
StringGrid1.Cells[4,StringGrid1.Row]:='';
StringGrid1.Cells[5,StringGrid1.Row]:='';
StringGrid1.Cells[6,StringGrid1.Row]:='';
StringGrid1.Cells[7,StringGrid1.Row]:='';
end;
end;
Замечание: при очистке всех колонок текущей строки сетки мы написали 8 одинаковых команд, которые отличаются только номер колонки. Этот код можно оформить в виде цикла вида:
for i:=0 to StringGrid1.ColCount do
StringGrid1.Cells[i,StringGrid1.Row]:='';
Организовать вывод графика или диаграммы на основании данных о стипендии студентов.
Указания: нанесите на форму компонент Chart (TeeChart Std). Двойным щелчком откройте его и задайте свойства: Series - добавьте два типа диаграммы (график и столбчатая диаграмма).
Для переключения типа отображения данных на диаграмме добавьте на форму компонент RadioGroup, для которого задайте свойства: Columns - 2 (две колонки), Items - названия переключателей, ItemIndex = 0 (выбран по умолчанию первый переключатель).
Так как график должен перестраиваться при наступлении множества событий (при открытии формы, при редактировании среднего балла в сетке, при добавлении или удалении данных в сетке), то оформим код построения в виде отдельной процедуры без параметров.
Вверху кода модуля формы добавьте заголовок процедуры:
procedure ShowChart;
В основном коде добавьте код процедуры:
procedure TForm1.ShowChart;
//переменная для цикла
var i: Integer;
begin
//задаем заголовок диаграммы
Chart1.Title.Text.Clear;
Chart1.Title.Text.Add('Данные о сумме стипендии');
//очищаем первый тип диаграммы от данных
Chart1.Series[0].Clear;
//в цикле наполняем ряд значениями из сетки
//стипендия - это данные
//фамилия - это подпись для данных
for i := 1 to StringGrid1.RowCount-1 do
begin
//при этом, если стипендия не пустая
if StringGrid1.Cells[7,i]<>'' then
//то в качестве значения добавляется ее значение
Chart1.Series[0].Add(StrToFloat(StringGrid1.Cells[7,i]),StringGrid1.Cells[1,i])
else
//в противном случае, если стипендия не посчитана, то добавляется 0
Chart1.Series[0].Add(0,StringGrid1.Cells[1,i]);
end;
//первая диаграмма становится активной (отображается)
Chart1.Series[0].Active:=true;
//вторая диаграмма пока не активна (не отображается)
Chart1.Series[1].Active:=false;
//группа переключателей устанавливается на первый элемент
RadioGroup1.ItemIndex:=0;
end;
Для вызова данной процедуры используйте команду вида:
ShowChart;
Вызов процедуры нужно добавить в конец кода следующих событий:
- OnCreate формы;
- OnSetEditText сетки; (вызвать перед командой Exit и в конце процедуры обработчика события)
- OnClick для кнопки "Удалить".
На второй форме для кнопки "Сохранить" вызов процедуры выполняют с указание имени формы:
Form1.ShowChart;
С помощью группы переключателей организуйте переключение типа отображаемой информации на диаграмме.
В событии OnClick компонента RadioGroup введите код:
procedure TForm1.RadioGroup1Click(Sender: TObject);
begin
//если выбран первый тип (график)
case RadioGroup1.ItemIndex of
0: begin
//первый тип диаграммы отображаем
Chart1.Series[0].Active:=true;
//второй тип скрываем
Chart1.Series[1].Active:=false;
end;
//если выбран второй тип (диаграмма)
1: begin
//для второго типа диаграммы загружаем данные из первого типа,
//который заполняется по умолчанию в разных событиях
Chart1.Series[1].Assign(Chart1.Series[0]);
//первый тип диаграммы скрываем
Chart1.Series[0].Active:=false;
//второй тип отображаем
Chart1.Series[1].Active:=true;
end;
end;
end;