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

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

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

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

Как правильно сделать форму логина

Запись от krapotkin размещена 13.08.2017 в 08:46
Показов 15170 Комментарии 30
Метки delphi

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

Итак, сначала должен быть сценарий. Вот он.
Стартует приложение.
Перед показом главной формы мы должны вывести диалог авторизации к кнопками ОК и Отмена
Если в диалоге нажать Отмена, то мы сразу выходим из программы
Если ОК - то нужно проверить логин пароль. Если все правильно - показать главную форму, если нет - опять показать диалог.

Делать это можно двумя способами - в обработчике OnCreate главной формы, и переопределяя конструктор главной формы
Более правильный вариант - второй. Поэтому рассмотрим его.
Дело в том, что если мы выберем выход из программы, в случае OnCreate главная форма все равно сначала загрузится и только потом мигнет и программа закончится. Нам это не хочется видеть, поэтому - конструктор.

Итак. Мы создадим главную форму TMainForm и форму логина TLoginForm.
(примечание про AutoCreate https://www.cyberforum.ru/blog... g4873.html)
LoginForm - два Label два Edit и две TButton с заполненным ModalResult mrOk и mrCancel соответственно.
BorderStyle=bsDialog. Position=poMainFormCenter

В MainForm переопределяем конструктор и пишем туда... оп! не плодить простыни в коде!
Пишем туда
Delphi
1
2
inherited; // нужно вызвать конструктор предка
CheckLogin(); // а тут будут действия по проверке логина
так же стараемся себя вести и в других местах, выделяя логические блоки в отдельные процедуры и функции
например, сама проверка пароля у нас будет выполняться в функции LoginCorrect(login,pass:string):boolean;
и она ничего вообще не будет знать о форме логина, ибо мало ли откуда к нам придут логин и пароль впоследствии...

итого:
Кликните здесь для просмотра всего текста
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 UMainForm;
 
interface
 
uses
  classes, types, forms, Controls, StdCtrls, Dialogs, SysUtils;
 
type
  TMainForm = class(TForm)
  private
    procedure CheckLogin;
    function LoginCorrect(login, pass: String): Boolean;
  public
    constructor Create(AOwner: TComponent); override;
  end;
 
var
  MainForm: TMainForm;
 
implementation
 
uses
  ULoginForm;
 
 
{$R *.dfm}
 
function TMainForm.LoginCorrect(login,pass:String):Boolean;
begin
  result := true;
end;
 
procedure TMainForm.CheckLogin();
var
  f:TLoginForm;
  r:TModalResult;
begin
  f:=TLoginForm.Create(NIL);
  try
    repeat
      r:=f.ShowModal;
      if r=mrOk then
      begin
        // придумаем функцию LoginCorrect() которая возвращает нам True или False
        // откуда она берет эти данные, из базы или файла или придумывает сама, нам все равно
        if LoginCorrect(f.eLogin.text, f.ePassword.text) then
          Break
      end;
    until r=mrCancel;
    if r=mrCancel then
    begin
      ShowMessage('Отказ от авторизации. Программа завершает свою работу.');
      Application.Terminate();
      Abort;
    end;
  finally
    f.free;
  end;
end;
 
 
constructor TMainForm.Create(AOwner: TComponent);
begin
  inherited;
  CheckLogin;
end;
 
end.


Кликните здесь для просмотра всего текста
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
unit ULoginForm;
 
interface
 
uses
  Windows, Messages, Forms, StdCtrls, Classes, Controls;
 
type
  TLoginForm = class(TForm)
    eLogin: TEdit;
    ePassword: TEdit;
    bOk: TButton;
    bCancel: TButton;
  private
    { Private declarations }
  public
    { Public declarations }
  end;
 
 
implementation
 
{$R *.dfm}
 
end.

вот и все

UPD
Более жизненный сценарий старта программы я привел здесь
Метки delphi
Размещено в Без категории
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
Всего комментариев 30
Комментарии
  1. Старый комментарий
    Аватар для DenNik
    а я считаю, что форму авторизации лучше показывать ДО создания главной формы, да и мигание этой формочки при неправильном вводе тоже некомильфо. я делаю обычно так

    форма авторизации
    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
    
    unit Unit2;
     
    interface
     
    uses
      Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
      Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
     
    type
      TfrmLogin = class(TForm)
        Button1: TButton;
        Button2: TButton;
        edtLogin: TEdit;
        edtPass: TEdit;
        procedure Button1Click(Sender: TObject);
      end;
     
      // функция авторизации. ее можно вызывать потом и при работе программы (ну мало ли :))
      // проверять результат и принимать решение
      function Authorized: boolean;
     
    implementation
     
    {$R *.dfm}
     
    // отображение окна авторизации
    function Authorized: boolean;
    begin
      with TfrmLogin.Create(Application) do
      begin
        Result:= ShowModal = mrOk;
        Free;
      end;
    end;
     
    // DUMP-функция. проверка карректности данных
    function CheckLogin(const Login,Password: string): boolean;
    begin
      Result:= true;
    end;
     
    procedure TfrmLogin.Button1Click(Sender: TObject);
    begin
      // click on OK button
      if CheckLogin(edtLogin.Text,edtPass.Text) then ModalResult:= mrOk else
      begin
        ShowMessage('Incorrect!');
        edtLogin.Clear;
        edtPass.Clear;
        edtLogin.SetFocus;
      end;
    end;
     
    end.


    главный модуль проекта
    Delphi
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
    program Project1;
     
    uses
      Vcl.Forms,
      Unit1 in 'Unit1.pas' {frmMain},
      Unit2 in 'Unit2.pas' {frmLogin};
     
    {$R *.res}
     
    begin
      Application.Initialize;
      if not Authorized then Exit;                // добавим всего одну строчку
      Application.MainFormOnTaskbar := True;
      Application.CreateForm(TfrmMain, frmMain);
      Application.Run;
    end.


    да и код по итогу короче получается
    Запись от DenNik размещена 18.08.2017 в 16:41 DenNik вне форума
  2. Старый комментарий
    Аватар для krapotkin
    Не факт. Или не обязательно факт.
    Попробую аргументировать.
    Во-первых, для проверки логина часто нужно подключиться к БД или взять данные из интернета. А настройки подключения считать из файла. Тогда придется и это пихать сюда же. Перебор.
    Более жизненный сценарий старта программы я привел здесь
    Во-вторых, мигания (по крайней мере у меня) не заметно.
    В-третьих, ужасно не люблю вносить правки в DPR.
    Запись от krapotkin размещена 21.08.2017 в 17:22 krapotkin вне форума
  3. Старый комментарий
    Аватар для DenNik
    ужасно не люблю вносить правки в DPR.
    почему так?
    это сугубо личный субъективный принцип кодинга?
    Запись от DenNik размещена 22.08.2017 в 10:13 DenNik вне форума
  4. Старый комментарий
    Аватар для krapotkin
    это старая история. IDE бывало знатно глючила. До сих пор иногда беспричинно портит DPR и PAS
    все дело в том, что она пользуется автоматическим парсингом dpr файла
    и когда там много ей непонятного, фиг знает, что у нее слетит )
    так что да, сугубо личное и субъективное. предрассудки типа не дразнить красной тряпкой черную кошку )
    Запись от krapotkin размещена 22.08.2017 в 10:32 krapotkin вне форума
  5. Старый комментарий
    Аватар для DenNik
    До сих пор иногда беспричинно портит DPK
    вероятно, DPR )
    да, если строки
    Application.CreateForm(TfrmMain, frmMain);
    Application.Run;

    заключить в begin..end
    а если вариант с Exit, то все good )
    Запись от DenNik размещена 21.11.2017 в 09:58 DenNik вне форума
  6. Старый комментарий
    Аватар для Mr_Cipa
    Здравствуйте. У меня проблема в том, что в форме логина в разделе type не отображаются компоненты Tedit. Следовательно я не могу (не знаю как) вставить в функцию проверки на главной форме... Я что то делаю не так?
    Запись от Mr_Cipa размещена 20.03.2019 в 00:25 Mr_Cipa вне форума
  7. Старый комментарий
    Аватар для krapotkin
    Создайте тему на форуме, там и решим
    Запись от krapotkin размещена 20.03.2019 в 07:35 krapotkin вне форума
  8. Старый комментарий
    Аватар для Usaga
    Во-первых, для проверки логина часто нужно подключиться к БД или взять данные из интернета. А настройки подключения считать из файла. Тогда придется и это пихать сюда же. Перебор.
    Что "перебор"? Проверка реквизитов пользователя в базе - нормальная часть бизнес-логики.
    Запись от Usaga размещена 20.03.2019 в 09:01 Usaga вне форума
  9. Старый комментарий
    Аватар для Rius
    DenNik +1
    Не надо всё пихать в одну форму, тем более такой костыль, как вызов одного окна из конструктора другого. Программа может всё нужное отработать и до показа каких-либо окон.
    Запись от Rius размещена 20.03.2019 в 09:57 Rius на форуме
  10. Старый комментарий
    Аватар для krapotkin
    перебор - это то, что для произведения данного действия потребуется выполнить действия, с ним непосредственно не связанные
    например, загрузка настроек программы - это наверное не дело формы логина? а если еще в командной строке какие-то параметры идут, перекрывающие считанные настройки? тогда форма логина и их должна разбирать?
    нарушается принцип разделения логики. Этот кусок становится монолитным и непереносимым в другую программу.
    Хотя я уже писал выше, что это вполне имеет место быть удобным/юзабельным для Вас, но неудобно/неприемлемо для меня
    Я описываю РАБОЧИЙ и довольно сбалансированный концептуально вариант. И нигде не говорю, что он единственно верный...
    Запись от krapotkin размещена 20.03.2019 в 10:27 krapotkin вне форума
  11. Старый комментарий
    Аватар для Rius
    А разбор настроек или параметров командной строки - разве дело основной формы?
    У вас монолит и получается, так как вся логика понапихана в одну форму.
    Рабочих вариантов много, красивых мало.
    Запись от Rius размещена 20.03.2019 в 10:49 Rius на форуме
  12. Старый комментарий
    Аватар для Usaga
    Форма не только не должна настройки разбирать\загружать, но и в сама в базу ходить. Всё это должны делать отдельные модули приложения, а из формы всё это только "пинаться" должно. А значит должно существовать до формы и вообще без неё.

    А если для вас возможность из формы логина в базу сходить - перебор, так это показатель того, что у вас уже монолит неповоротливый и никуда не переносимый.
    Запись от Usaga размещена 21.03.2019 в 11:03 Usaga вне форума
  13. Старый комментарий
    Аватар для krapotkin
    ну, то, что вы мне приписываете, вовсе не следует это из моего текста )
    главная форма в конструкторе вызывает чужие методы и для разбора и для обращений к базе
    я уже писал выше, что просто стараюсь не писать ничего в DPR, потому что единственное место, куда можно переместить всю эту логику - туда.

    так что никакого монолита не возникает.
    у меня несколько программ используют модули друг друга
    соответственно, архитектура вполне себе модульная
    Запись от krapotkin размещена 21.03.2019 в 12:46 krapotkin вне форума
  14. Старый комментарий
    Аватар для Rius
    Вообще тут явно говорится: правильно вызывать форму логина из конструктора основной формы. Причём метод проверки логина является членом класса основной формы, и в ней же, очевидно (из показываемого) идёт обращение к БД.
    Что плохого в коде в dpr? Это, как я понимаю, аналог Program.Main() из C#. Нормальное место для подготовки данных, ещё не требующих показа форм.

    В дельфях DI так и не применяется?
    Запись от Rius размещена 21.03.2019 в 20:01 Rius на форуме
  15. Старый комментарий
    Аватар для krapotkin
    обратите внимание. весь пример здесь умещен в 50 строк. Сознательно. Чтобы речь шла о принципе.
    ни о какой БД речи не идет. почему мы не можем проверить логин и пароль например через веб-запрос?

    код в dpr делфи пытается автоматически анализировать. и не думаю, чтобы там стоял мощный AI.
    А когда ей чего-то не удается, я не верю в стойкость ее алгоритмов. Она и напортить может.
    Хотя я абсолютно не возражаю, если опытные программисты будут делать ЭТО в DPR. Но считаю достаточным и разумным компромиссом советовать новичкам делать вот так.
    Например, возникнет вопрос, куда помещать компоненты доступа к БД чтобы проверить логин, если он в базе. Вариант с динамическим созданием точно выше среднего уровня. Вариант с глобальным датамодулем, который создается ДО главной формы уже мне не очень нравится. Я как-то люблю сам создавать и хранить нужные мне вещи. Что и делаю иногда в том же конструкторе. А иногда нет.
    Есть много различных моментов, которые могут повлиять на выбор стратегии. А эта статья не призвана раскрывать тонкости, тут только объясняется принцип - открывать форму логина, не вкладывая в нее никакой логики. Сделано это потому что 99% всяких интернет - находок делают не так.

    Про DI не понял.
    Запись от krapotkin размещена 21.03.2019 в 20:28 krapotkin вне форума
  16. Старый комментарий
    Аватар для Rius
    Внедрение зависимости (англ. Dependency injection, DI)
    Вкратце: создать и считать настройки до формы, распознать все параметры командной строки до формы, передать то и другое в конструктор формы уже готовым к применению.

    Компромисс между "новичкам", "правильнее" и "попроще"... ОК.
    Запись от Rius размещена 21.03.2019 в 20:58 Rius на форуме
  17. Старый комментарий
    Аватар для Usaga
    Можем проверить и через веб-запрос, только с точки зрения потребителя (формы авторизации) разницы нет вообще никакой.

    Ходилки в БД или веб-сервисы и вообще все сервисы создаются до создания формы и внедряются ей в конструктор (DI). К этому моменту все настройки уже разобраны, все параметры командной строки уже распаршены и применены. Какова природа полученного в конструкторе сервиса (БД или веб-сервис) - форме не известно.

    Всё это должно работать и без UI. Вот это правильно и именно такое нужно новичкам прививать. А ужимать пример до пятидесяти строк для "упрощения" архитектуры, когда вы пример этой самой архитектуры показываете... Ну вы поняли...
    Запись от Usaga размещена 22.03.2019 в 08:13 Usaga вне форума
  18. Старый комментарий
    Аватар для Mr_Cipa
    Цитата Сообщение от Usaga
    Всё это должно работать и без UI. Вот это правильно и именно такое нужно новичкам прививать...
    А не могли бы вы показать наглядно? Как это с вашей точки зрения должно выглядеть в коде.
    Запись от Mr_Cipa размещена 22.03.2019 в 08:26 Mr_Cipa вне форума
  19. Старый комментарий
    Аватар для krapotkin
    нет в делфи необходимости чего-то "внедрять" ))
    создайте объект, ссылку на него используйте, вот и все внедрение. Тогда все в делфи изначально injected )))

    дело в том, что в делфи исторически программа практически ассоциирована со своей главной формой, а не с
    program XXX;
    begin end.
    а требовать, чтобы форма логина и пароля была в программе без UI это вы у себя так делайте, радибоха ))
    буду ждать ваши простые и доступные статьи как рассказать новичкам о создании микросервисной архитектуры

    и я по-прежнему не вижу, откуда взялись обвинения, что ничего не будет работать без UI ? прямо вдруг интересно стало
    Запись от krapotkin размещена 22.03.2019 в 08:47 krapotkin вне форума
  20. Старый комментарий
    Аватар для Usaga
    А не могли бы вы показать наглядно? Как это с вашей точки зрения должно выглядеть в коде.
    Речь о разделении функционала на отдельные сервисы со строгими обязанностями. Форма к этим сервисам обращается по мере надобности и не напрямую, а через один из вариантов MVC\MVP\MVVM\Presentation Model\Document-View и тому подобное. В двух словах и формате комментария показывать такое себе)

    нет в делфи необходимости чего-то "внедрять" ))
    А дельфи не язык программирования общего назначения, чтоли?)))

    Я не требую форму без UI. Я о том, что весь функционал должен быть работоспособен и переиспользуем без форм и UI. Т.е. никаких завязок на UI быть не должно. Идеальный тест: вызвать метод входа по логину из консоли.

    То, что визуальный конструктор начинает ваш путь в разработке приложения с дизайна основной формы не значит, что вы должны слепо ему следовать. WinForms тоже начинается с дизайнера формы. Но что-то это не особо мешает мыслить сервисами и бизнес-логикой, а не историческим мышкованием.

    И микросервисы тут причём?
    Запись от Usaga размещена 22.03.2019 в 12:01 Usaga вне форума
 
Новые блоги и статьи
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
Запись в регистр сведений независимо от заполненности табличной части
Maks 25.08.2026
Реализация из решения ниже выполнена на нетиповом документе с несколькими табличными частями, разработанного в КА2. Задача: Обеспечить запись документа в регистр сведений независимо от. . .
Ноутбук Альфария
kumehtar 24.08.2026
Встретился тут в сети ноутбук Альфария, примарха Альфа-Легиона. Хотя возможно, это ноутбук Омегона, разумеется. Ну как вам?
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru