4-4. 상속용 부모폼 만들기 업무용 프로그램의 각 화면은 대체적으로 반복적인 형태가 많기때문에 공통적인 부분을 모아서 부모폼을 만들고 그것을 상속해서 만들면 코딩 양을 상당히 줄일 수 있다. 부모폼은 팝업용과 Docking용, 그리고 용도에 따라 조회용과 등록용이 있을 수 있다. Docking용의 경우 화면 배치는 같으나 내부 처리가 달라진다. 편의상 Docking용의 폼명은 앞에 "frm"을, 팝업용은 "dlg"를 붙이기로 한다. 등록폼을 기준으로 권한 처리를 위한 변수와 SQL처리를 위한 변수 및 처리용 function 및 procedure는 아래와 같다.
    unit SIMLazQ_frm;
    :
    :
    uses
      ..., LCLType, simlaz_dm;
      :
      :
      TfrmSIMLazQ = class(TForm)
      :
      :
      public
        u_TableName, // Table Name
        u_SQL: string; // SQL

        u_downkey_flag, // DownKey Pressed
        u_auth_n, // 등록권한
        u_auth_m, // 수정권한
        u_auth_d, // 삭제권한
        u_auth_p, // 인쇄권한
        u_auth_a: Boolean; // 전체권한

        function UF_Modified: Boolean; dynamic; // 등록/수정 상태 확인
        procedure UP_SetSQL; dynamic; // 조회용 SQL 설정
        procedure UP_OpenSQL; dynamic; // 조회
        procedure UP_Append; dynamic; // 등록
        procedure UP_Delete; dynamic; // 삭제
        procedure UP_Save; dynamic; // 저장
조회용일 경우 위에서 등록/수정/삭제 관련 항목만 빼면 된다. u_TableName 변수는 등록시 어느 DB Table에 등록할 것인지를 가지고 있는 변수이므로 조회용에는 필요가 없다. UF_Modified 역시 데이터가 등록이나 수정상태인지를 확인하는 함수이므로 조회용에서는 필요가 없다. 그리고 등록/수정/저장 procedure 역시 조회용에는 필요없는 항목이다. u_downkey_flag 변수는 DBGrid의 맨 끝 항목에서 아래쪽 방향키를 눌렀을 때 빈 레코드가 추가되는 것을 막기위해 사용된다. 마지막 레코드에서 아래쪽 방향키를 눌러 빈 레코드가 추가되었는데도 마구 누르다보면 빈 레코드 상태로 저장이 되거나 필수값이 입력되지않아 오류가 발생된다. 그것을 막기위해 KeyDown Event에서 DOWN 키가 입력되면 u_downkey_flag 변수를 True로 설정하고 DataSet의 BeforeInsert Event에서 u_downkey_flag 변수가 True이면 Abort 처리를 한다. 폼이 활성화 되면 권한 변수의 저장된 값으로 DataModule의 버튼 활성화여부 변수를 초기화하고 Main Form의 OnActivate Event를 실행한다. Main Form의 OnActivate Event 에는 Main Form의 버튼에대한 활성화 처리가 되어있다.
    procedure TfrmSIMLazQ.FormActivate(Sender: TObject);
    begin
      // Main Button Setting
      with dmSIMLaz do
      begin
        u_btn_v := True;
        u_btn_n := u_auth_n;
        u_btn_d := u_auth_d;
        u_btn_s := u_auth_n or u_auth_m or u_auth_d;
      end;
      Application.MainForm.OnActivate(Application.MainForm);
    end;
종료시에는 버튼활성화 변수를 초기화(False) 하고 Main Form의 OnActivate Event를 활성화 한다. 등록 혹은 수정 상태일 경우 저장할 것인지 여부도 확인한다.
    procedure TfrmSIMLazQ.FormClose(Sender: TObject; var CloseAction: TCloseAction);
    begin
      CloseAction := caFree;
    end;

    function TfrmSIMLazQ.UF_Modified: Boolean;
    begin
      Result := qrMaster.Active and (qrMaster.State in [dsEdit, dsInsert]);
    end;

    procedure TfrmSIMLazQ.FormCloseQuery(Sender: TObject; var CanClose: boolean);
    begin
      if UF_Modified then
        if  MessageDlg(Self.Caption,
          '저장되지않은 정보가 있습니다. 지금 저장하시겠습니까?',
          mtConfirmation, [mbYes, mbNo], 0) = mrYes then UP_Save;

      // Main Button Disable
      with dmSIMLaz do
      begin
        u_btn_v := False;
        u_btn_n := False;
        u_btn_d := False;
        u_btn_s := False;
      end;
      Application.MainForm.OnActivate(Application.MainForm);
      CanClose := True;
    end;
폼 생성시에는 DataModule에 설정된 권한 변수값으로 폼의 권한 변수를 초기화 한다. DataModule의 권한 변수값은 메인폼에서 권한 체크를 할 때 설정된다.
    procedure TfrmSIMLazQ.FormCreate(Sender: TObject);
    begin
      u_TableName := '';
      u_downkey_flag := False;
      u_auth_n := dmSIMLaz.u_auth_n;
      u_auth_m := dmSIMLaz.u_auth_m;
      u_auth_d := dmSIMLaz.u_auth_d;
      u_auth_p := dmSIMLaz.u_auth_p;
      u_auth_a := dmSIMLaz.u_auth_a;

      Self.Top := 0;
      Self.Left := 0;
      Self.Height := Application.MainForm.Height - 80;
      Self.Width := Application.MainForm.Width;
      Self.WindowState := wsMaximized;
    end;
메인폼의 KeyDown 이벤트에서 Enter Key로 컨트롤간 이동처리를 해놨기때문에 Docking 폼에서는 그외 처리만 해준다. DOWN 키가 눌려졌는지 여부에 따라 u_downkey_flag 변수를 설정하고 메인폼에 있는 공용 처리버튼(조회/등록/삭제/저장)에 해당되는 키값에 맞춰 procedure를 호출한다.
    procedure TfrmSIMLazQ.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      if Shift = [] then
      begin
        u_downkey_flag := (Key = VK_DOWN);
        case Key of
          VK_F2: UP_OpenSQL;
          VK_F3: UP_Append;
          VK_F8: UP_Delete;
          VK_F9: UP_Save;
        end;
      end;
    end;

    procedure TfrmSIMLazQ.FormKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      if (Shift = []) and (Key = VK_DOWN) then u_downkey_flag := False;
    end;
팝업창의 KeyDown Event에서는 메인폼에서 처리했던 Enter Key로 컨트롤간 이동처리를 해야한다.
    procedure TdlgSIMLazQ.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    begin
      if Shift = [] then
      begin
        if Key in [VK_RETURN, VK_DOWN, VK_UP] then
        begin
          u_downkey_flag := (Key = VK_DOWN);
          if Self.Tag = 1 then Exit;
          case Key of
            VK_RETURN, VK_DOWN: SelectNext(ActiveControl, True, True);
                         VK_UP: SelectNext(ActiveControl, False, True);
          end;
          Key := 0;
        end
        else
        begin
          case Key of
            VK_F2: UP_OpenSQL;
            VK_F3: UP_Append;
            VK_F8: UP_Delete;
            VK_F9: UP_Save;
          end;
        end;
      end;
    end;