Система тестирования. Часть 5
Ранее, в данном цикле статей, посвященных написанию программы для тестирования на Delphi, мы начали создание системы управления тестом. Сейчас мы ее, наконец, закончим.
Управление вариантами ответа
При клике на кнопку или метку «Редактировать», должно открывать окно управления вариантами ответа.
Создадим для этого новую форму, назовем ее EditUnit (скачать dfm).
Внешний вид:
Как видно, она чем-то похожа на главную форму. Рассмотрим основные компоненты.
Метка куда выводится текст вопроса, это QTextLabel.. При нажатии на метку «Редактировать» (QEditLabel), QTextLabel заменяется текстовым полем QTextMemo, в котором текст вопроса можно редактировать.
Список вариантов ответа выводится в компонент AListBox типа TCheckListBox.
Справа также расположены две TCategoryPanel: AnswerPanel (Вариант ответа) и QuestionPanel (Тест).
Панель «Вариант ответа»
Текст выбранного варианта ответа выводиться в поле ATextMemo. Его правильность определяет Check Box ARightCheckBox.
Метка «Сохранить» (ASaveLabel) собственно сохраняет изменения для текущего варианта ответа.
Метка «Добавить» (ACreateLabel) вызывает модальное окно для добавления нового варианта ответа.
Метка «Удалить» (ADeleteLabel) удаляет выбранный вариант ответа.
Панель «Тест»
Здесь только одна кнопка «Применить» (AplayButton). При клике на ней сохраняются изменения и закрывается окно управления вариантами ответа.
Получение вопроса
Для начала, рассмотрим, каким образом эта форма получает вопрос, с вариантами которого нужно работать. Самым простым вариантом, без введения глобальных переменных, является переопределение конструктора. Нужно просто добавить еще один параметр, которой и будет определять вопрос.
Так же, для удобства сделаем вопрос полем класса формы.
- TQEditForm = class(TForm)
- ...
- public
- Question: TStQuestion;
- constructor Create( AOwner: TComponent; setQuestion: TStQuestion );
- end;
- ...
- constructor TQEditForm.Create( AOwner: TComponent; setQuestion: TStQuestion );
- begin
- inherited Create( AOwner );
- Question := setQuestion;
- end;
Поскольку нам нужно работать с каждым вариантом ответа по отдельности, введем свойство SelectAnswer. По аналогии с главной формой, оно будет означать вариант ответа, выбранный в данный момент.
Запись в свойство SelectAnswer
Рассмотрим метод при записи в свойство SelectAnswer – SetSelectAnswer. Нам просто нужно заполнить текстовое поле ATextMemo и флажок ARightCheckBox.
- TQEditForm = class(TForm)
- ...
- private
- procedure SetSelectAnswer(const Value: TStAnswer);
- public
- Question: TStQuestion;
- constructor Create( AOwner: TComponent; setQuestion: TStQuestion );
- property SelectAnswer: TStAnswer read FSelectAnswer write SetSelectAnswer;
- end;
- ...
- procedure TQEditForm.SetSelectAnswer(const Value: TStAnswer);
- begin
- ATextMemo.Text := Value.Text;
- ARightCheckBox.Checked := Value.Right;
- FSelectAnswer := Value;
- end;
Загрузка вопроса
Введем еще закрытых метода для полной «загрузки» данных из вопроса на форму.
Метод LoadData
Просто выводит варианты ответа в AListBox.
- procedure TQEditForm.LoadData;
- var
- i: integer;
- Answer: TStAnswer;
- begin
- AListBox.Items.Clear;
- for i := 0 to Question.StAnswerList.Count - 1 do
- begin
- Answer := TStAnswer( Question.StAnswerList.Items[i] );
- AListBox.Items.Add( Answer.Text );
- AListBox.Checked[ i ] := Answer.Right;
- end;
- end;
Метод LoadHead
Показывает текст вопроса в метке QTextLabel.
- procedure TQEditForm.LoadHead;
- begin
- QTextLabel.Caption := Question.Text;
- end;
Метод LoadAnswer
Делает выбранным вариант ответа (свойство SelectAnswer) под заданным индексом.
- procedure TQEditForm.LoadAnswer( index: integer );
- begin
- if (index >= 0) and (index < Question.StAnswerList.Count) then
- begin
- SelectAnswer := TStAnswer( Question.StAnswerList.Items[ index ] );
- end;
- end;
Как видно, все, в общем-то, очень похоже на методы загрузки из главной формы, написанные нами ранее.
Осталось только обработать событие при активизации формы – FormActivate:
- procedure TQEditForm.FormActivate(Sender: TObject);
- begin
- LoadHead;
- LoadData;
- LoadAnswer( 0 );
- end;
Теперь можно перейти к, собственно, реализации функционала управления вариантами ответа.
Редактирование текста вопроса
Как уже сказано выше, текст вопроса выводится в метку QTextLabel. Если нажать на «Редактировать», то это метка заменяется текстовым полем QTextMemo, и соответственно текст «Редактировать» меняется на «Сохранить», при клике на который, изменения в тексте вопроса сохраняются, и вновь отображается метка QTextLabel.
Введем два закрытых метода: EditQText, который скрывает метку и показывает поле для редактирования и ShowQText, который наоборот показывает метку, при этом сохраняя изменения, сделанные в текстовом поле.
Метод EditQText
Кроме сказанного этот метод еще должен управлять меткой QEditLabel («Редактировать» или «Сохранить»). Ее текущее состояние записывается в свойство Tag.
- procedure TQEditForm.EditQText;
- begin
- QTextLabel.Hide; // Скрываем метку
- QTextMemo.Text := QTextLabel.Caption; // Текст из метки копируется в
- // текстовое поле
- QTextMemo.Show; // Отображение поля
- QEditLabel.Tag := 0;
- QEditLabel.Caption := 'Сохранить';
- end;
Метод ShowQText
Обратный методу EditQText. Так же сохраняет сделанные изменения.
- procedure TQEditForm.ShowQText;
- begin
- QTextMemo.Hide;
- QTextLabel.Caption := QTextMemo.Text;
- Question.Text := QTextMemo.Text;
- QTextLabel.Show;
- QEditLabel.Tag := 1;
- QEditLabel.Caption := 'Редактировать';
- end;
Клик по QEditLabel
Обработчик события клика по метке. В зависимости от свойства Tag вызывает один из предыдущих методов.
- procedure TQEditForm.QEditLabelClick(Sender: TObject);
- begin
- if QEditLabel.Tag = 1 then
- EditQText;
- else
- ShowQText;
- end;
Список вариантов ответа (AListBox)
При выборе варианта ответа в AListBox, этот же вариант ответа должен записываться в свойство SelectAnswer. Определим обработчик события OnClick для AListBox:
- procedure TQEditForm.AListBoxClick(Sender: TObject);
- begin
- LoadAnswer( AListBox.ItemIndex );
- end;
Так же, поскольку AListBoxэто компонент типа TCheckListBox, то и при изменении check box'a у конкретного варианта ответа, должен изменения и check box на панели «Вариант ответа».
- procedure TQEditForm.AListBoxClickCheck(Sender: TObject);
- begin
- LoadAnswer( AListBox.ItemIndex );
- SelectAnswer.Right := AListBox.Checked[ AListBox.ItemIndex ];
- end;
Панель «Вариант ответа»
Перейдем, теперь, к этой панели.
Сохранение изменений
При клике на метку «Сохранить», все изменения, сделанные с вариантом ответа должны сохраниться:
- procedure TQEditForm.ASaveLabelClick(Sender: TObject);
- begin
- if (SelectAnswer <> nil) and (ATextMemo.Text <> '') then
- begin
- SelectAnswer.Text := ATextMemo.Text;
- SelectAnswer.Right := ARightCheckBox.Checked;
- LoadData;
- end;
- end;
Удаление варианта ответа
Создадим метод DeleteSelectAnswer. Как понятно из названия – это удаление выбранного вопроса.
- procedure TQEditForm.DeleteSelectAnswer;
- begin
- Question.StAnswerList.Remove( SelectAnswer );
- LoadData;
- FSelectAnswer := nil;
- LoadAnswer( 0 );
- end;
Теперь напишем обработчик события клика по метке «Удалить»:
- procedure TQEditForm.ADeleteLabelClick(Sender: TObject);
- begin
- if SelectAnswer <> nil then
- if MessageBox(handle, 'Вы действительно хотите удалить этот вариант ответа?' + #13#10,
- 'Удаление варината ответа', mb_YesNo) = mrYes then
- DeleteSelectAnswer;
- end;
Добавление варианта ответа
Реализуем добавление нового варианта ответа, так же как и добавление вопроса. То есть, покажем модальное окно, в которое вводится текст варианта ответа и определятся верный он или нет.
Создадим новую форму, назовем ACreateUnit (скачать dfm).
Внешний вид:

Так же, как и в QEditForm, переопределим конструктор, добавив один параметр:
- constructor TACreateForm.Create( AOwner: TComponent; setQuestion: TStQuestion );
- begin
- inherited Create( AOwner );
- Question := setQuestion;
- end;
При клике на кнопку «ОК» должен создаться новый вариант ответа:
- procedure TACreateForm.OkButtonClick(Sender: TObject);
- var
- newAnswer: TStAnswer;
- begin
- newAnswer := TStAnswer.Create;
- if ATextMemo.Text <> '' then
- begin
- newAnswer.Text := ATextMemo.Text;
- newAnswer.right := QActiveCheckBox.Checked;
- Question.StAnswerList.Add( newAnswer );
- end;
- end;
Теперь с ACreateUnitможно закончить. Вернемся к форме управления вариантами ответа.
Напишем обработчик события OnClick для метки «Добавить»:
- procedure TQEditForm.ACreateLabelClick(Sender: TObject);
- var
- CreateForm: TACreateForm;
- begin
- CreateForm := TACreateForm.Create( self, Question );
- if CreateForm.ShowModal = mrOk then
- begin
- self.LoadData;
- AListBox.ItemIndex := AListBox.Count - 1;
- LoadAnswer( AListBox.Count - 1 );
- end;
- end;
Панель «Тест»
Наконец, осталось лишь обработать клик по кнопке «Применить» на панели «Тест». Поскольку все изменения сохранялись сразу, то при клике на эту кнопку нужно просто закрыть форму.
На этом и закончим с формой управления вариантами ответа. Вернемся к MainForm.
Поскольку управление вариантами ответа уже готово, осталось лишь его вызвать. Для этого добавим новый метод EditSelectQuestion. В котором и будет создаваться форма TQEditForm.
- procedure TMainForm.EditSelectQuestion;
- var
- QEditForm: TQEditForm;
- begin
- if SelectQuestion <> nil then
- begin
- QEditForm := TQEditForm.Create( self, SelectQuestion );
- QEditForm.ShowModal;
- LoadData;
- SelectQuestion := FSelectQuestion;
- end;
- end;
Теперь, нужно лишь вызвать этот метод при лике на кнопку в панели инструментов и метку «Редактировать»:
- procedure TMainForm.EditToolButtonClick(Sender: TObject);
- EditSelectQuestion;
- end;
- procedure TMainForm.QEditLabelClick(Sender: TObject);
- begin
- EditSelectQuestion;
- end;
Закрытие формы
Переопределим обработчик события OnClose для формы. Перед закрытием программы, нужно узнать, желает ли пользователь сохранить сделанные изменения:
- procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction);
- begin
- if Changed then
- begin
- case MessageBox(handle, 'Сохранить сделанные изменения?' + #13#10,
- 'Сохранение', mb_YesNoCancel) of
- IDYES: SaveTestSimple;
- IDCANCEL: action := caNone;
- end;
- end;
- end;
Теперь программа составления теста полностью дописана и удовлетворяет всем требованиям, поставленным ранее. В следующих частях цикла статей мы напишем и саму программу тестирования.
delphi, тест

Комментарии (0)
Добавить комментарий