Форум программистов, компьютерный форум, киберфорум
Наши страницы
krapotkin
Войти
Регистрация
Восстановить пароль
Блог. Двадцать пять лет Делфи-практики

В этом блоге я буду публиковать ответы на вопросы, которые постоянно приходится повторять на форуме.
Здесь можно это сделать более развернуто и спокойно.

Все, что здесь написано, не является истиной в последней инстанции, скорее, это результат моих размышлений над архитектурой проектов, маленьких и больших, которых я сделал на Делфи более дюжины.

Начав с Делфи-2 двадцать пять лет назад, я прошел все версии, испробовал массу технологий, включая работу с БД, с графикой DirectX, связью с серверами и интернетом, разработку на Андроид и IOS, и многое, многое другое.
____________________________________________________________________________________
P.S. все, о чем здесь написано, всего лишь измышления из головы.
совпадения с реальными людьми и фактами случайны.
Оценить эту запись

Пишем тест. Уровень Beginner. Урок 1

Запись от krapotkin размещена 19.05.2018 в 18:28
Обновил(-а) krapotkin 19.05.2018 в 19:01

Давайте еще раз. Напишем очередной тест

Раз пошла такая пьянка, делаем полный разбор, начиная с проектирования
Что нам нужно знать о программе
Хранение данных.
Первое что надо обдумать. Сейчас думать не будем вообще, потому что уровень Beginner.
Пусть у нас есть текстовый файл, который содержит две строки в начале
первая - какой-то текст, вторая - число - количество вопросов в файле
а после этого идут блоки в соответстви с кол-вом вопросов. каждый блок состоит из 6 строк
текст вопроса
вариант ответа1
вариант ответа2
вариант ответа3
вариант ответа4
номер правильного ответа

после этого сразу блок следующего вопроса
В программе вопрос пусть хранится в записи
Delphi
1
2
3
4
5
TQuestion=record
  Q:string; // текст вопроса
  A:array[0..3] of string; // варианты ответа 1..4
  Right:integer; // номер правильного варианта 1..4
end;
соответственно, у нас есть массив вопросов
Delphi
1
var    Questions:array of TQuestion;
Думаю, что пусть будет и массив ответов
Delphi
1
var    Answers:array of integer;
чтобы все было совсем хорошо, создадим отдельный юнит File--New--Unit, куда сложим все наши классы
Комплект классов и переменных будет важно называться нашей моделью данных ))
кроме TQuestion пусть там еще лежит класс глобальных переменных программы TMySettings
и все процедуры, которые нужны для работы с моделью
назовем юнит UMyClasses.pas
обратим внимание на то, что этот юнит ничего не знает о форме, компонентах и прочей беде
только работа с самими данными

первая функция, которая туда попала - function ReadQuestionsFromFile(Filename:string):String;
на входе имя файла, на выходе - та самая первая строка из файла. ХЗ почему, просто так, чужой файл взял для образца
итого у нас сейчас вот такой файл UMyClasses.pas
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
unit UMyClasses; 
 
interface
 
uses
  Classes, Types, Sysutils;
 
type
  TQuestion = record
    Q: string;
    A: array[0..3] of string;
    Right: integer;
  end;
 
  TDBSettings = record
    server: string;
    db: string;
  end;
 
  TMySettings = class
  public
    Login: string;
    Role: string;
    DBSettings: TDBSettings;
  end;
 
var
  Settings: TMySettings;
  Questions: array of TQuestion;
  Answers: array of integer;
 
function ReadQuestionsFromFile(FName: string): string;
 
implementation
 
function ReadQuestionsFromFile(FName: string): string;
var
  List: TStringList;
  VCount, I: integer;
begin
  List := TStringList.Create();
  List.LoadFromFile(FName); //прочитаем весь файл в список строк
  result := List[0]; // В первой строке у вас какой-то текст для заголовка
  VCount := StrToInt(List[1]); // во второй строке - кол-во записей
  SetLength(Questions, VCount);  // теперь,зная это количество, установим размер массива Questions
  SetLength(Answers, VCount); // и массива Answers
  I := 0;
  /// начиная с третьей строки, читаем вопросы
  while I < VCount do
  begin
    Questions[I].Q := List[2 + I * 6 + 0];
    Questions[I].A[0] := List[2 + I * 6 + 1];
    Questions[I].A[1] := List[2 + I * 6 + 2];
    Questions[I].A[2] := List[2 + I * 6 + 3];
    Questions[I].A[3] := List[2 + I * 6 + 4];
    Questions[I].Right := strToInt(List[2 + I * 6 + 5]);
    I := I + 1;
  end;
  List.Free;
end;
 
initialization
  Settings := TMySettings.Create;
 
finalization
  FreeAndNil(Settings);
 
end.

теперь немного об интерфейсе
сама тестовая форма выглядит так (Screen 166)
чтобы туда попасть,нужно пройти авторизацию
поэтому первая форма нашего приложения выглядит так (Screen 167)
и содержит интересный код
Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
type
  TfMainForm = class(TForm)
    grp1: TGroupBox;
    eLogin: TEdit;
    ePass: TEdit;
    bOk: TButton;
    lbl1: TLabel;
    lbl2: TLabel;
    procedure bOkClick(Sender: TObject);
  private
    procedure GoTest;
  public
  end;
 
var
  fMainForm: TfMainForm;
 
implementation
 
uses
  UTestForm;
 
{$R *.dfm}
 
procedure TfMainForm.bOkClick(Sender: TObject);
begin
  // здесь будет проверка логина, но пока просто переход к тесту
  GoTest();
end;
 
procedure TfMainForm.GoTest;
var f:TfTestForm;
begin
  Hide;
  f:=TfTestForm.Create(self);
  try
    f.ShowModal;
  finally
    show;
    FreeAndNil(F);
  end;
end;

обратите внимание на то, что мы прячем главную форму
создаем и показываем тестовую
а потом опять показываем главную
это тоже не огонь, но для Beginner - в самый раз
кстати - TestForm удалена из Project options - Forms - Auto create !! ибо нефиг http://www.cyberforum.ru/blogs/469693/blog4873.html

Форма для теста
Вернемся к тестовой форме
Заведем на ней поле - переменную - CurQuestion:integer;
Она будет изменяться от 0 до количества вопросов -1
И в пару к ней сделаем процедуру "отобразить текущий тест" ShowCurQuestion
Там прямо примитивно всё
Берем элемент массива Questions c индексом CurQuestion
и переписываем то что там хранится в компоненты на экране

Кликните здесь для просмотра всего текста
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
unit UTestForm;
 
interface
 
uses
  classes, types, forms, Controls, UMyClasses, ExtCtrls, StdCtrls;
 
type
 
  TfTestForm = class(TForm)
    pnl1: TPanel;
    lblQuestion: TLabel;
    bNext: TButton;
    rgVariants: TRadioGroup;
    pnlQuectionNo: TPanel;
    procedure FormCreate(Sender: TObject);
  private
    procedure ShowCurQuestion;
  public
    CurQuestion : integer;
  end;
 
var
  fTestForm: TfTestForm;
 
implementation
 
uses
  sysutils;
 
{$R *.dfm}
 
{ TMainForm }
procedure TfTestForm.FormCreate(Sender: TObject);
var
  Filename: string;
begin
  Filename := extractFilePath(ParamStr(0))+'questions.dat';
  Caption := ReadQuestionsFromFile(Filename);
  CurQuestion := 0;
  ShowCurQuestion;
end;
 
procedure TfTestForm.ShowCurQuestion;
var
  i: Integer;
begin
  pnlQuectionNo.Caption := Format('Вопрос %d / %d',[curQuestion+1, Length(Questions)]);
  lblQuestion.Caption := questions[CurQuestion].Q;
  rgVariants.Items.Clear;
  for i := 0 to 3 do
    rgVariants.Items.Add(questions[CurQuestion].A[i]);
  rgVariants.ItemIndex := -1;
end;
end.

теперь если на кнопку Далее повесить обработчик, который сохраняет ответ пользователя в массив Answers, просто увеличивает CurQuestion и просит форму нарисовать вопрос, то в общем-то тестовая часть нашего проекта завершена!
Delphi
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
procedure TfTestForm.bNextClick(Sender: TObject);
begin
  // проверим, вдруг ничего не выбрано
  if rgVariants.ItemIndex=-1 then
  begin
    showMessage('Выберите вариант ответа');
    exit;
  end;
 
  Answers[CurQuestion] := rgVariants.ItemIndex;
  if CurQuestion<Length(Questions)-1 then
  begin
    CurQuestion := CurQuestion + 1;
    ShowCurQuestion;
  end;
end;
хорошая идея если мы нажали Далее на последнем вопросе, то закрыть форму с тестом и вывести форму Итого, и возможно даже записать результаты в к-нить файл или даже БД, но это следующий урок.

Приложу исполняемый файл и файл с вопросами, чтобы можно было посмотреть, что получилось...
Миниатюры
Нажмите на изображение для увеличения
Название: QIP Shot - Screen 166.png
Просмотров: 328
Размер:	30.1 Кб
ID:	4821   Нажмите на изображение для увеличения
Название: QIP Shot - Screen 167.png
Просмотров: 317
Размер:	16.4 Кб
ID:	4822  
Вложения
Тип файла: 7z BeginnersTestStep1.7z (2.25 Мб, 58 просмотров)
Размещено в Без категории
Просмотров 621 Комментарии 10
Всего комментариев 10
Комментарии
  1. Старый комментарий
    а почему
    TQuestion = record
    TDBSettings = record
    а
    TMySettings = class
    ??
    Запись от qwertehok размещена 21.05.2018 в 09:45 qwertehok вне форума
  2. Старый комментарий
    Аватар для krapotkin
    на самом деле, мне все равно)) я обычно везде классы использую
    но есть тонкость )
    там где есть процедура копирования данных, лучше использовать записи, т.к. они копируются как одна переменная
    это удобно.
    DBSettings у меня взято с реального проекта, и там это было нужно. Поэтому RECORD
    Для TQuestion record выбрано, чтобы не ныли эти "я классы не учил, нам препод сказал и т.п."
    если бы для себя делал, это было бы 146% так :
    Delphi
    1
    2
    3
    4
    5
    6
    
    TQuestion = class
    ...
    end;
    TQuestions = class(TObjectList<TQuesion>)
    ...
    end;
    Запись от krapotkin размещена 21.05.2018 в 10:12 krapotkin вне форума
  3. Старый комментарий
    Аватар для Usaga
    Цитата:
    чтобы не ныли эти
    Ого, сколько презрения! Зачем тогда вообще вести блог для "этих"?..
    Запись от Usaga размещена 21.05.2018 в 10:43 Usaga вне форума
  4. Старый комментарий
    Аватар для krapotkin
    потому что если человек сначала спрашивает, как сделать, а потом говорит, что он так делать не будет, потому что не хочет вдумываться, понять и т.п. - это значит, он ваше время потратил, а свое - не хочет.
    это обычно слегка обидно

    блог предназначен для тех, кто хочет узнать как грамотнее сделать те или иные вещи.
    или хотя бы как решить вашу задачу меньшими усилиями, не скатываясь в пучины г-кода
    при этом цели написать вам курсовую, чтобы вы сдали и забыли, передо мной вообще не стоит
    могу себе позволить.
    если вы отождествили себя с моим лирическим героем, что я могу поделать.
    впрочем, вот:
    P.S. все, о чем здесь написано, всего лишь измышления из головы.
    совпадения с реальными людьми и фактами случайны.
    Запись от krapotkin размещена 21.05.2018 в 12:10 krapotkin вне форума
  5. Старый комментарий
    Аватар для Avazart
    Типичная задача для фрианса, смысл постить такое ...

    Тот кто соображает скорее всего сам дойдет, а кто не хочет ...
    Запись от Avazart размещена 21.05.2018 в 12:50 Avazart вне форума
    Обновил(-а) Avazart 21.05.2018 в 12:54
  6. Старый комментарий
    Аватар для krapotkin
    вопрос появляется на форуме еженедельно
    остается на выбор либо пулять ссылкой на платный раздел, либо ссылкой на готовую статью
    либо вариант 100500 раз объяснять как и что делать. но этот вариант - не вариант
    вопрос про смысл постить такое ничем не отличается от смысла читать эти посты )
    Запись от krapotkin размещена 21.05.2018 в 13:20 krapotkin вне форума
  7. Старый комментарий
    Аватар для SatanaXIII
    Цитата:
    Сообщение от krapotkin Просмотреть комментарий
    остается на выбор либо пулять ссылкой на платный раздел, либо ссылкой на готовую статью
    А отсылки в платный раздел запрещены.
    Запись от SatanaXIII размещена 23.05.2018 в 10:33 SatanaXIII вне форума
  8. Старый комментарий
    Аватар для krapotkin
    вовсе нет
    ссылки на платный раздел не запрещены
    запрещено только вымогательство
    Запись от krapotkin размещена 23.05.2018 в 13:54 krapotkin вне форума
  9. Старый комментарий
    вовсе нет
    пункт 5.9
    Цитата:
    Запрещено отсылать пользователей из тематических разделов в разделы фриланса
    вот тут пользователь предлагает мне деньги, я ему пишу - "А не пойти бы вам в платный раздел?" и БАБАХ. Я виноват.
    http://www.cyberforum.ru/delphi-beginners/thread2249181.html
    Запись от qwertehok размещена 23.05.2018 в 16:08 qwertehok вне форума
  10. Старый комментарий
    Аватар для krapotkin
    поиск по форуму Delphi платный раздел дает тучу постов, в которых советуют туда обратиться
    http://www.cyberforum.ru/delphi-begi...ml#post9815643
    Запись от krapotkin размещена 23.05.2018 в 16:33 krapotkin вне форума
 
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2018, vBulletin Solutions, Inc.
Рейтинг@Mail.ru