Практическое занятие № 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;