4-6. 암호 변경 및 사용자 관리 화면 암호 변경은 이전 암호를 먼저 비교한 후 변경할 암호를 서버에 UPDATE 한다. 암호를 비교하거나 등록 시 입력값을 SHA256으로 변환해서 처리한다.
    procedure TdlgChgPWD.btnOKClick(Sender: TObject);
    var
      s, l_SQL: string;
    begin
      if edNew.Text <> edConf.Text then
      begin
        MessageDlg(Self.Caption, '"변경 암호"와 "암호 확인" 내용이 다릅니다!', mtError, [mbOK], 0);
        edNew.SetFocus;
        edNew.SelectAll;
        Exit;
      end;

      try
        l_SQL := 'SELECT passwd FROM slusrm WHERE usr_id = ' + QuotedStr(dmSIMLaz.u_uid);
        dmSIMLaz.UP_SIMLazOpen(dmSIMLaz.qrTmp, l_SQL, True);
        if dmSIMLaz.qrTmp.EOF then s := ''
        else s := dmSIMLaz.qrTmp.FieldByName('passwd').AsString;
        dmSIMLaz.qrTmp.Close;

        if dmSIMLaz.UF_SIMLazSHA(edOld.Text) <> s then
        begin
          MessageDlg(Self.Caption, '"이전 암호"가 설정된 값과 다릅니다!', mtError, [mbOK], 0);
          edOld.SetFocus;
          edOld.SelectAll;
          Exit;
        end;

        l_SQL := 'UPDATE slusrm SET passwd = ' +
          QuotedStr(dmSIMLaz.UF_SIMLazSHA(edNew.Text)) +
          ' WHERE usr_id = ' + QuotedStr(dmSIMLaz.u_uid);
        if dmSIMLaz.UF_SIMLazExec(l_SQL) = 1 then
        begin
          ShowMessage('암호가 변경되었습니다!');
          Close;
        end
        else
          MessageDlg(Self.Caption, '처리도중 오류가 발생하였습니다!', mtError, [mbOK], 0);
      finally
        if dmSIMLaz.qrTmp.Active then dmSIMLaz.qrTmp.Close;
      end;
    end;
사용자 관리용 폼을 앞에서 만든 부모폼을 상속해서 만들어 보자. New메뉴에서 Inherited Item에 있는 Inherited project component에서 등록용 팝업 부모폼을 선택한 후 OK 버튼을 클릭한다. 생성된 상속폼에 아래와 같이 TDataSet과 DBGrid를 올려놓고 연결한 다음 DataSet 컴퍼넌트에 TField를 추가하고 DBGrid에 Column들을 추가해준다. 조회조건으로 사용여부를 지정하기위한 체크박스를 추가해준다. 조회용 SQL을 등록하기 위한 procedure와 조회 후 DBGrid로 Focus를 주기위해 조회용 procedure를 override 한다.
    unit user_dlg;
    :
    :
      TdlgUser = class(TdlgSIMLazQ)
      :
      :
      public
        procedure UP_SetSQL; override;
        procedure UP_OpenSQL; override;
    :
    :
    procedure TdlgUser.UP_SetSQL;
    var
      s: string;
    begin
      if ckxUseYN.Checked then s := '''1'''
      else  s := '''0''';
      u_SQL := 'SELECT usr_id, usr_name, passwd, reg_date, admin_yn, use_yn, remark' +
        ' FROM slusrm WHERE use_yn = ' + s + ' ORDER BY usr_name';
    end;

    procedure TdlgUser.UP_OpenSQL;
    begin
      inherited UP_OpenSQL;
      dbgMaster.SetFocus;
    end;
폼 생성 Event에 등록/삭제/저장 시 SQL 구문 생성에 사용되는 테이블명을 설정하고 자료를 조회한다. 사용여부 체크박스의 Click Event에도 조회 처리를 추가한다.
    procedure TdlgUser.FormShow(Sender: TObject);
    begin
      inherited;
      u_TableName := 'slusrm';
      UP_OpenSQL;
    end;

    procedure TdlgUser.ckxUseYNClick(Sender: TObject);
    begin
      UP_OpenSQL;
    end;
DBGrid의 경우 Enter Key 입력시 다른 컨트롤로 이동되면 안 되고 DBGrid 내의 Column간 이동이 되어야한다. 따라서 DBGrid에 Focus가 왔을 때 팝업의 경우 Self.Tag, Docking 폼의 경우 Application.MainForm.Tag를 1로 설정해서 컨트롤간 이동 처리가 안 되게 해야한다.
    procedure TdlgUser.dbgMasterEnter(Sender: TObject);
    begin
      Self.Tag := 1;
    end;

    procedure TdlgUser.dbgMasterExit(Sender: TObject);
    begin
      Self.Tag := 0;
    end;
Enter Key로 DBGrid의 Column간 이동처리는 Delphi의 DBGrid와 비슷하다. 다만 라자루스의 DBGrid의 Column에는 CheckBox나 Button을 사용할 수 있기때문에 Check Box일 경우 EditorMode로 들어가지않고 바로 이동해야한다. (※ Column의 ButtonStyle에 대한 정의는 Grids 유닛에 있다.)
    procedure TdlgUser.dbgMasterKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      if Key = VK_RETURN then // uses LCLType
      begin
        with TDBGrid(Sender) do
        begin
          if (not (SelectedColumn.ButtonStyle in [cbsCheckboxColumn, cbsButtonColumn])) and
             (not SelectedColumn.ReadOnly) and (not EditorMode) then Exit; // uses Grids
          if Shift = [] then
          begin
            if SelectedIndex < (Columns.Count - 1) then SelectedIndex := SelectedIndex + 1
            else
            begin
              SelectedIndex := 0;
              DataSource.DataSet.Next;
              if DataSource.DataSet.Eof then DataSource.DataSet.Append;
            end;
          end
          else if ssShift in Shift then
          begin
            if SelectedIndex > 0 then SelectedIndex := SelectedIndex - 1
            else
            begin
              SelectedIndex := Columns.Count - 1;
              DataSource.DataSet.Prior;
            end;
          end;
        end;
      end;
    end;
사용자ID는 다른 Table에 연계되어 등록되는 경우가 많다. 그렇기때문에 사용자ID가 바뀔 경우 연계된 데이터도 같이 변경되게하거나 아예 변경 못되게 막아야한다. 외래키를 써서 처리하면 되지만 불편한 점이 많아서 실제 개발할 때 쓰지 않는 경우가 많다. 본 예제에서는 한번 등록된 사용자ID는 수정 안 되게 처리 한다. 사용자ID TField의 ProviderFlags 중 pfInUpdate 속성을 False로 설정해서 UPDATE SQL 구문 생성시 제외시키고 TDataSource의 Change Event에서 Insert 상태가 아니면 ReadOnly가 되게 설정한다.
    procedure TdlgUser.dsMasterStateChange(Sender: TObject);
    begin
      qrMasterUSR_ID.ReadOnly := not (qrMaster.State in [dsInsert]);
    end;
신규 레코드가 추가되면 초기값을 설정한다. 암호는 기본 암호를 SHA256으로 인코딩 후 지정한다. 암호 Field 역시 사용자ID와 같이 등록은 되지만 수정하면 안 되기때문에 TField의 ProviderFlags 중 pfInUpdate 속성을 False로 설정한다. 암호는 화면상에 보여줄 필요가 없는 항목이기때문에 ReadOnly 처리는 하지않아도 된다.
    procedure TdlgUser.qrMasterAfterInsert(DataSet: TDataSet);
    begin
      with DataSet do
      begin
        FieldByName('passwd').AsString := dmSIMLaz.UF_SIMLazSHA('1234');
        FieldByName('reg_date').AsDateTime := Date;
        FieldByName('admin_yn').AsString := '0';
        FieldByName('use_yn').AsString := '1';
      end;
      dbgMaster.SelectedIndex := 0;
    end;
사용자ID에 대문자만 입력 받게 할 경우 DBGrid의 Column에는 대문자 처리용 속성이 없으므로 TField의 SetText Event에서 대문자로 변경해야한다.
    procedure TdlgUser.qrMasterUSR_IDSetText(Sender: TField; const aText: string);
    begin
      TField(Sender).AsString := UpperCase(aText);
    end;