Страница 1 из 2

Как сделать правильно окошко логина?

Добавлено: 18 май 2006, 09:44
Alchazar
Как правильно сделать окошко логина, может уже кто делал, поделитесь опытом, а то у меня никак невыходит :cry:
где ошибка?

Код: Выделить всё

begin
  Application.Initialize;

  // логотип
  F_Logo:=TF_Logo.Create(Application);
  F_Logo.Show;
  F_logo.Update;


  // загрузка основной формы
  Application.CreateForm(TF_Main, F_Main);
  Application.CreateForm(TF_Login, F_Login);
  F_Login.ShowModal;
  // закрывыю логотип
  F_Logo.Hide;
  F_Logo.Free;
if loginStat= true then
  Application.Run
  else
  Application.Terminate; 
end.

Код: Выделить всё

Unit Login
procedure TF_Login.BitBtn_okClick(Sender: TObject);
var UserLogin, pass: string;
begin
  F_Main.IBQ_User.Close;
  F_Main.IBQ_User.SQL.Clear;
  F_Main.IBQ_User.SQL.Add('Select User_Login, User_Pass FROM TBUSER WHERE User_Login ="'+Ed_Login.Text+'"');
  F_Main.IBQ_User.Open;
  UserLogin:=F_Main.IBQ_User.fieldByName('User_Login').AsString;
  pass:=F_Main.IBQ_User.FieldByName('User_pass').AsString;
 
  if (Ed_Login.Text=UserLogin) and (Ed_Pass.Text=pass) then loginStat:=true
  else   
  begin
    Ed_Pass.Text:='';
    Ed_Pass.SelectAll;
    loginStat:=false;
  end;
 
end;

end.
прога вылетает с ошибкой

Добавлено: 18 май 2006, 10:01
vunder
А что за ошибка?

Вообще

Код: Выделить всё

Application.CreateForm(TF_Login, F_Login);
F_Login.ShowModal;
неправильно. Во-первых, убеди TF_Login из AutoCreate Forms. Создавай ее так же, как и окно логотипа. Должно сработать.

Добавлено: 18 май 2006, 11:24
Naeel Maqsudov
Ошибка понятно какая - нарушение общей защиты при обращении к памяти по адресу 0.

Т.к. делается F_Main.IBQ_User.Close; в то время, когда F_Main равна nil.

Есть КУЧА способов решить эту задачу.
Один из наиболее корректных с точки зрения VCL это оставить все формы в автозагрузке, но у Main выставить Visible=false (в desing-time) и сделать следующее:

Код: Выделить всё

begin 
  Application.Initialize; 
  Application.ShowMainForm:=false;
  Application.CreateForm(TF_Main, F_Main); 
  Application.CreateForm(TF_Login, F_Login); 
  
  if LoginSuccess then begin
     Application.ShowMainForm:=false;
     Application.Run 
  end;
end. 


Функцию LoginSuccess написать "по вкусу" в модуле Login.
Начать ее можно с заполне ния полей (например вставить имя пользователя, который логинился последний раз),
затем сделать F_Login.ShowModal и проверить пароль.
Если пароль правильный функция должна вернуть True.

Есть с десяток способов сделать то же самое.

Добавлено: 18 май 2006, 13:23
vunder
Интересно, как F_Main м.б. равен nil, когда он уже инициализирован Application.CreateForm(TF_Main, F_Main).

Добавлено: 19 май 2006, 13:26
Naeel Maqsudov
Да, точно уже инициализирован.... Извиняюсь. Неправильно прочитал исходник.
Однако, какая ошибка вылетает и в каком месте?
Как осуществляется возврат из ShowModal?
Если ошибку я угадал, то возможно, вы где-то разрушаете форму при закрытии. И по возвращении из ShowModal вызывае Hide и Free для уже несуществующего объекта.

А loginStat - это глобальная переменная что ли?
Хм.... Да-а-а. Так не делается!

Если форма была открыта по ShowModal то закрыть ее можно в обработчике события можно так:

Self.ModalResult := mrOk; {или mrCancel.....}

Причем значение, присвоенное в ModalResult будет результатом функции ShowModal!

Т.е. мой пример можно переписать без функции LoginSuccess:

Код: Выделить всё

begin 
  Application.Initialize; 
  Application.ShowMainForm:=false; 
  Application.CreateForm(TF_Main, F_Main); 
  Application.CreateForm(TF_Login, F_Login); 
  
  if TF_Login.ShowModal=mrOk then begin 
     Application.ShowMainForm:=true; 
     Application.Run 
  end; 
end. 


Добавлено: 20 май 2006, 20:26
Alchazar
а о глобальной переменной можно побольше?

Добавлено: 21 май 2006, 10:11
vunder
Можно, только осторожно.
В данном примере разницы нет. Все хависит от того, как реализуется проект. Если это будут потоки или подключаемые модули, то глобальные переменные для этого не подходят. Нужно все реализовывать через свойства объекта:

Код: Выделить всё

...
type
...
  tMyObj = class (TComponent)
  private
    fField: String;
    procedure SetField (const Value: String);
  ...
  published
    property Field: String read fField write SetField;
  ...
  end;
...

procedure tMyObj.SetField (const Value: String);
begin
  if Value<>fField then
    begin
      fField := Value;
      ...
    end;
end;

Код: Выделить всё

 var
  obj: tMyObj;

...

obj.Field := 'abc';

...

Добавлено: 22 май 2006, 10:35
Alchazar
Вот, разобрался :D
Спасибо за помощь
Форма - Логин

Код: Выделить всё

F_Main.IBQ_User.Close;
  F_Main.IBQ_User.SQL.Clear;
  F_Main.IBQ_User.SQL.Add('Select User_Login, User_Pass FROM TBUSER WHERE User_Login ="'+Ed_Login.Text+'"');
  F_Main.IBQ_User.Open;
  UserLogin:=F_Main.IBQ_User.fieldByName('User_Login').AsString;
  pass:=F_Main.IBQ_User.FieldByName('User_pass').AsString;
  if (Ed_Login.Text=UserLogin) and (Ed_Pass.Text=pass) then ModalResult:=mrOk
  else
  begin
    MessageDlg('Имя пользователя и/или пароль неверны!'+#10#13+'', mtError, [mbok], 0);
    ModalResult:=mrNone;
    Ed_Pass.Text:='';
    Ed_Pass.SelectAll;
  end;
end;
Главная форма

Код: Выделить всё

procedure TF_Main.FormShow(Sender: TObject);
var rez: TModalResult;
begin
  rez:=F_Login.ShowModal;
  if rez = mrOk then F_Main.Visible:=true;
  if rez = mrCancel then Application.Terminate;
end;
Вроде всё работает хорошо :D

Добавлено: 22 май 2006, 18:07
Игорь Акопян
мне кажется, что приложение не закроется, если пользователь наврёт пароль ;)
проще разрешить только одно действие:

Код: Выделить всё

procedure TF_Main.FormShow(Sender: TObject); 
begin 
  if F_Login.ShowModal = mrOK then 
    F_Main.Visible:=true
  else
    Application.Terminate; 
end;
Вы, естесственно, знаете, что хранить пароль в базе в открытом виде можно только если вы хотите исключить случайный набор неверного пароля пользователем. Иначе такая секьюрити никуда не годится ;)

Добавлено: 22 май 2006, 18:18
vunder
оно точно не закроется:

Код: Выделить всё

MessageDlg('Имя пользователя и/или пароль неверны!'+#10#13+'', mtError, [mbok], 0); 
    ModalResult:=mrNone;
, а проверка идет только на mrOk и mrCancel. Надо быть внимательнее!!!