4-3. 메인 화면 TreeView 메뉴 및 권한체크 메뉴 버튼은 트리 메뉴를 숨기거나 나타내기위한 버튼이다. Docking 폼이 생성되면 트리 메뉴를 감춰 메인 폼 전체를 Docking 폼이 쓸 수 있게한다.
    procedure TfrmMain.btnMenuClick(Sender: TObject);
    begin
      trvMenu.Visible := not trvMenu.Visible;
      if trvMenu.Visible then trvMenu.SetFocus;
    end;
트리 메뉴 노드에 아이콘을 보여주기 위해서 TImageList를 추가하고 트리 메뉴에 연결한다. 메인 폼 Show Event에서 트리 메뉴를 생성한다. 그 외 상태바에 날짜와 사용자명도 표시한다. TTreeView는 ReadOnly를 True로 설정해서 수정을 막고, RightClickSelect를 True 설정해서 마우스 오른쪽 버튼으로도 선택되게 한다. 관리자일 경우 메뉴 전체를, 일반 사용자일 경우 각 사용자에게 할당된 메뉴만을 선별해서 생성한다. 메뉴와 프로그램을 구분해서 아이콘을 지정해준다. 아이콘 Index 값은 TreeView 클릭시 메뉴 항목인지 프로그램 항목인지 구분하기위한 값으로도 활용된다.
    procedure TfrmMain.FormShow(Sender: TObject);

      // ID로 노드찾기
      function LF_FindNode(AID: string): TTreeNode;
      var
        i: Int32;
        s: string;
        l_Tmp: PSIMLazNodeInfo;
      begin
        Result := nil;
        if trvMenu.Items.Count < 1 then Exit;

        i := -1;
        repeat
          Inc(i);
          l_Tmp := trvMenu.Items[i].Data;
          s := l_Tmp^.menu_id;
        until (i = (trvMenu.Items.Count - 1)) or (s = AID);
        if s = AID then Result := trvMenu.Items[i];
      end;

    var
      l_SQL: string;
      l_Node: TTreeNode;
      l_NodeInfo: PSIMLazNodeInfo;
    begin
      stbMain.Panels[0].Text := FormatDateTime('yyyy"년 "m"월 "d"일"', Date);
      stbMain.Panels[1].Text := dmSIMLaz.u_uname;

      // Tree Menu 생성
      trvMenu.Items.BeginUpdate;
      try
        trvMenu.Items.Clear;

        if dmSIMLaz.u_admin_flag then
          l_SQL :=
            'SELECT menu_id, up_id, menu_name, menu_yn, prg_id, ord FROM slmenum ORDER BY up_id, ord'
        else
          l_SQL := 'SELECT a.menu_id, a.up_id, a.menu_name, a.menu_yn, a.prg_id, a.ord' +
            ' FROM slmenum a' +
            ' WHERE EXISTS ( SELECT 1 FROM slmenut z' +
            ' WHERE z.usr_id = ' + QuotedStr(dmSIMLaz.u_uid) + ' AND z.menu_id = a.menu_id )' +
            ' ORDER BY a.up_id, a.ord';

        dmSIMLaz.UP_SIMLazOpen(dmSIMLaz.qrTmp, l_SQL, True);
        with dmSIMLaz.qrTmp do
        begin
          while not Eof do
          begin
            New(l_NodeInfo);
            l_NodeInfo^.menu_id := FieldByName('menu_id').AsString;
            l_NodeInfo^.prg_id := FieldByName('prg_id').AsString;

            // Root Node
            if FieldByName('up_id').IsNull or (FieldByName('up_id').AsString = '') then
              trvMenu.Selected :=
                trvMenu.Items.AddObject(nil, FieldByName('menu_name').AsString, l_NodeInfo)
            // Sub Node
            else
            begin
              l_Node := LF_FindNode(FieldByName('up_id').AsString);
              trvMenu.Selected :=
                trvMenu.Items.AddChildObject(l_Node, FieldByName('menu_name').AsString, l_NodeInfo);
            end;

            if FieldByName('menu_yn').AsString = '1' then
            begin
              trvMenu.Selected.ImageIndex := 0;
              trvMenu.Selected.SelectedIndex := 0;
            end
            else
            begin
              trvMenu.Selected.ImageIndex := 1;
              trvMenu.Selected.SelectedIndex := 1;
            end;

            Next;
          end;
          Close;
        end;
      finally
        if dmSIMLaz.qrTmp.Active then dmSIMLaz.qrTmp.Close;
        trvMenu.FullExpand;
        SetScrollPos(trvMenu.Handle, SB_VERT, 0, True);
        if trvMenu.Items.Count > 0 then trvMenu.Selected := trvMenu.Items[0];
        trvMenu.Items.EndUpdate;
        trvMenu.SetFocus;
      end;
    end;
TreeView 클릭시 선택한 Node가 메뉴인지 프로그램 항목인지는 메뉴 생성시 설정한 ImageIndex로 구분한다. 메뉴면 접거나 펼치는 동작을, 프로그램 항목이면 해당 폼을 생성한다.
    procedure TfrmMain.trvMenuClick(Sender: TObject);
    var
      l_NodeuInfo: PSIMLazNodeInfo;
    begin
      if TTreeView(Sender).Selected = nil then Exit;

      if TTreeView(Sender).Selected.ImageIndex = 0 then
      begin
        if TTreeView(Sender).Selected.Expanded then TTreeView(Sender).Selected.Collapse(False)
        else TTreeView(Sender).Selected.Expand(False);
      end
      else
      begin
        l_NodeuInfo := TTreeView(Sender).Selected.Data;
        UP_CreatePRG(l_NodeuInfo^.menu_id, l_NodeuInfo^.prg_id, TTreeView(Sender).Selected.Text);
      end;
    end;

    procedure TfrmMain.trvMenuKeyPress(Sender: TObject; var Key: char);
    begin
      if Key = #13 then trvMenuClick(Sender);
    end;
메뉴ID를 이용해서 폼을 생성하기 전에 먼저 사용권한을 확인한다. 사용권한이 있을 경우, 프로그램 ID가 "http"로 시작하면 웹브라우저를 띄우고 "dlg"로 시작하면 Popup 창을, 아니면 Docking 폼을 생성한다. Docking된 TabSheet의 Name은 차후 Docking한 폼을 찾기위한 정보로 활용하기 위해 Docking 폼의 이름 앞에 "ts_"를 붙여서 할당한다.
    procedure TfrmMain.UP_CreatePRG(AMID, APID, ACaption: string);

      function LF_Auth(AID: string): Boolean;
      var
        l_SQL: string;
      begin
        Result := False;

        with dmSIMLaz do
        begin
          try
            l_SQL := 'SELECT auth_v, auth_n, auth_m, auth_d, auth_p, auth_a' +
              ' FROM slmenut' +
              ' WHERE usr_id = ' + QuotedStr(u_uid) +
              ' AND menu_id = ' + QuotedStr(AID);

            UP_SIMLazOpen(qrTmp, l_SQL, True);
            if not qrTmp.Eof then
            begin
              u_auth_n := qrTmp.FieldByName('auth_n').AsString = '1';
              u_auth_m := qrTmp.FieldByName('auth_m').AsString = '1';
              u_auth_d := qrTmp.FieldByName('auth_d').AsString = '1';
              u_auth_p := qrTmp.FieldByName('auth_p').AsString = '1';
              u_auth_a := qrTmp.FieldByName('auth_a').AsString = '1';
              Result := qrTmp.FieldByName('auth_v').AsString = '1';
            end;
            qrTmp.Close;
          finally
            if qrTmp.Active then qrTmp.Close;
          end;
        end;
      end;

    var
      i: Int32;
      l_Form: TCustomForm;
    begin
      if not (dmSIMLaz.u_admin_flag or LF_Auth(AMID)) then
      begin
        MessageDlg(Self.Caption,
          '사용 권한이 없거나 프로그램이 존재하지않습니다! [' + ACaption + ']', mtError, [mbOK], 0);
        Exit;
      end;

      // URL
      if LeftStr(APID, 4) = 'http' then
      begin
        ShellExecute(0, 'open', PChar(APID), nil, nil, SW_SHOWNORMAL);
        Exit;
      end;

      // Create Form
      if LeftStr(APID, 3) = 'dlg' then GF_SIMLazForm(APID)
      else
      begin
        for i := 0 to pgcMain.PageCount - 1 do
        begin
          if pgcMain.Pages[i].Name = 'ts_' + APID then
          begin
            pgcMain.ActivePageIndex := i;
            l_Form := Screen.FindForm(APID);
            if l_Form <> nil then l_Form.SetFocus;
            Exit;
          end;
        end;

        if pgcMain.PageCount >= 10 then
        begin
          MessageDlg(Self.Caption, '너무 많은 프로그램이 실행중입니다!', mtError, [mbOK], 0);
          Exit;
        end;

        if GF_SIMLazForm(APID) then
        begin
          l_Form := Screen.FindForm(APID);
          if l_Form <> nil then;
          begin
            l_Form.ManualDock(pgcMain);
            pgcMain.ActivePageIndex := pgcMain.PageCount - 1;
            l_Form.Show;
            l_Form.SetFocus;
          end;
          pgcMain.ActivePage.Name := 'ts_' + APID;
        end;
        if pgcMain.PageCount > 0 then trvMenu.Hide;
      end;
    end;