본문 바로가기

파이어몽키

"나의 도서관 앱" 개발 따라하기 - (1) 사용자화면 만들기와 기능 구현하기

"나의 도서관" 앱 개발 따라하기

❑ 앱 소개

  • 감명깊게 읽은 도서 정보를 기록하는 앱입니다.
  • 세미나 발표와 샘플소스 제공을 위해 다소 주제와 맞지 않은 기능이 포함되어 있습니다.
  • 해당 앱은 RAD Studio XE7(또는 AppMethod 1.15)로 개발 후 하나의 소스코드로 안드로이드와 iOS 앱을 동시에 개발하였습니다.

따라하기를 통해 습득할 수 있는 기술

  • 앱 개발의 전반적인 흐름을 따라하며 익혀 볼 수 있습니다.
  • 기본적인 UI 컨트롤 사용법과 속성 사용법
  • 화면 구성에 도움이 되는 샘플데이터 생성(프로토타입 데이터 소스)
  • 화면요소와 데이터를 (소스코드 없이)시각적으로 연결하는 기술(라이브바인딩)
  • 이미 구현된 기능을 재활용할 수 있는 프래임 활용방법(TFrame)
  • 앱에 포함하여 배포할 수 있는 임베디드 데이터베이스 사용법(IBLite)
  • 앱에서 데이터 연결 후 입력/수정/삭제 과정
총 2번의 따라하기로 "나의 도서관" 앱이 완성됩니다.
  1. 사용자화면 만드기, 기능 구현하기
  2. 실제 데이터베이스 연결, 배포
이 따라하기는 따라하기 과정 중 나오는 기술에 대한 이해 없이 일단(무조건) 따라하며 완성하는 것을 목적으로 작성되었습니다. 따라하는 도중 잘 이해가 되지 않더라도 끝까지 따라해보시길 권장합니다.

기술에 대한 설명은 글의 하단에 링크를 통해 제공하고 있습니다. 기타 궁금한 점은 댓글로 남겨주시기 바랍니다.
※ 해당 따라하기는 AppMethod를 통해 진행할 수 있습니다. 하단의 AppMethod 설치를 참고해 설치 후 진행하시기 바랍니다.

따라하기 1 - 사용자 화면 만들기와 기능 구현하기

  1. 빈 멀티-디바이스 앱 하나를 선택합니다. 
  2. 사용자들에게 보여질 화면을 만듭니다. 
  3. 샘플 데이터 추가 후 화면요소와 연결해 화면 표시 후 테스트하기
  4. 사용자의 조작에 동작하는 기능코드를 작성합니다. 
  5. 전화걸기, 사진, 웹페이지 표시 기능 추가 
  6. 사용자화면 완성! 테스트 하기

1, 빈 멀티-디바이스 앱 하나를 선택합니다.

  1. File > New > Multi-Device Application - Delphi 메뉴를 선택 하고, Blank Application을 선택해 프로젝트를 생성합니다.
  2. File > Save all 메뉴를 선택하고 유닛이름은 "MainForm.pas"로 프로젝트 이름은 'BookLogFMX"로 저장합니다.


2, 사용자들에게 보여질 화면을 만듭니다.

모바일 앱 스타일로 화면 구성을 위해 폼디자이너 스타일을 Android(또는 iOS)로 변경합니다.


총 3개의 화면을 구성해야 합니다. 

탭컨트롤

여러화면을 구성하기 위해 탭컨트롤을 아래 표를 참고해 추가합니다.

 상위 오브젝트

오브젝트 

속성 

값(또는 설명) 

 

 Form1

 Width / Height

 380 / 530(폼의 가장자리를 마우스로 적당한 크기로 조정)

 Form1

 TabControl1

 Align

 Client

 TabPosition

 Bottom
 (개발 시 탭이동 편의를 위해, 실행 시 탭은 표시하지 않음)

 TabControl1

 TabItem1(추가방법[각주:1])

 Text

 도서 목록

 Tabitem2

 Text

 도서 상세보기

 TabItem3

 Text

 새로운 도서 추가

도서 목록

"도서 목록"탭에서 아래 그림과 표를 참고해 화면 구성합니다.




 상위 오브젝트

오브젝트 

속성 

값(또는 설명) 

 TabItem1

 ToolBar1

 

 

 ToolBar1 Label1  Align Contents
 StyleLookup

 toollabel 

 Text 나의 도서관
 TextSettings.HorzAlign Center

 btnNewItem

 (TButton)

 Name btnNewItem
 Align  Right
 StyleLookup additemButton

 Tabitem1

ListView1AlignClient
 ItemApperance.ItemAppearance  ImageListItemBottomDetail

 ItemApperance.ItemHeight

 88

 ItemApperance.ItemObjects

.Image.Width / Height

 60 / 80
  ItemApperance.ItemObjects

.Text.WordWrap

 True


도서 상세보기

"도서 상세보기"탭에서 아래 그림과 표를 참고해 화면 구성합니다.


 상위 오브젝트

오브젝트 

속성 

값(또는 설명) 

 TabItem2

 ToolBar2

 

 

 ToolBar2

 Label2

 Align Contents
 StyleLookup toollabel 
 Text 제목
 TextSettings.HorzAlign Center
 TextSettings.WordWrap False

 btnBackList
 (TButton)

 Name btnBackList
 Align  Left
 StyleLookup arrowlefttoolbutton

 btnDetail

 (TButton)

 Name btnDetail
 Align

 Right

 StyleLookup detailstoolbutton

 TabItem2

 Layout1

 Align

 Client

 Layout1 Panel1 Align Top
 Height 116
 Margins 8, 8, 8, 8
 Panel1

 ShadowEffect1

 Distance 2
 ShadowColor Gray

 Rectangle1

 Image1 Align Left
 Margins 8, 8, 8, 8

 Width

 75
 Rectangle1 Layout2 Align Client
 Layout2

 lblTitle(TLabel)

 Name

 lblTitle

 Align MostTop
 AutoSize

 True

 Margins 0, 8, 3, 16

 StyledSettings.Style

 False
 TextSettings.Font.Size

 16

 TextSettings.Font.Style.fsBold

 True
 lblAuthor(TLabel) Name

 lblAuthor

 Align Top
 Margins 3, 12, 3, 10

 Layout1

 ListBox1 Align Client
 ListBox1 

 ListBoxItem1[각주:2]
 ListBoxItem2
 ListBoxItem3
 ListBoxItem4

 StyleLookup
 Text
 listboxitemnodetail
 출판사, 연락처, 사이트, 감상평

 ListBoxitem4

 Height 150
 ListBoxItem1 lblPublisher(TLabel) Align
Margins.Left
(4개 공통)

 Client
80
(4개 공통)

 ListBoxItem2 lblPhone(TLabel)
 ListBoxItem3 lblWebSite(TLabel)
 ListBoxItem4 lblComment(TLabel)
 ListBoxItem2 lblPhone HitTest Ture
 ListBoxItem3 lblWebSite

 HitTest

 True
 ListBoxItem4 lblComment TextSettings.VertAlign Leading
 Tabitem2 OverflowMenu(TListBox) Name OverflowMenu
 Position.X / Position.Y

 Button3 아래로 이동

 Width / Height 88 / 96
 OverflowMenu

 lstItemModify,

 lstItemDelete

 (TListBoxItem)

 Name

 lstItemModify /  lstItemDelete

 StyleLookup listboxitemstyle
 Text

 수정 / 삭제

 TextSettings.HorzAlign Center
 ShadowEffect2  

새로운 도서 추가

"새로운 도서 추가"탭에서 아래 그림과 표를 참고해 화면 구성합니다.



 상위 오브젝트

오브젝트 

속성 

값(또는 설명) 

 TabItem3

 ToolBar3

 

 

 ToolBar3

 Label3 

 Align Contents
 StyleLookup toolbutton 
 Text 도서 추가
 TextSettings.HorzAlign Center

 btnCancel

 (TButton)

 Name btnCancel
 Align  Left
 StyleLookup backtoolbutton
 Text 취소

 btnSaveitem

 (TButton)

 Name btnSaveItem
 Align

 Right

 StyleLookup

 donetoolbutton

 Text 

 저장

 TabItem3

 vsbEditForcus

 (TVertScrollBox)

 Name

 vsbEditFocus

 Align Client
 vsbEditForcus lytContentsNew(TLayout) Name lytContentsNew
 Align Client
 Layout3 Layout4 Align Top
 Height 113
 Layout4 Rectangle2 Align Center

 Fill.Kind

 None

 Width / Height

 100 / 100
 Rectangle2 imgNewItem(TImage) Name imgNewItem
 Align Client
 Margins 2, 2, 2, 2
 Layout3 ListBox2 Align Client
 ListBox2

 ListBoxItem7 ~ 12

 (6개 추가)

 StyleLookUp
 Text


 listboxitemnodetail
 제목, 저자, 출판사, 연락처, 사이트, 감상평

 ListBoxitem12

 Height 100

 ListBoxitem7

 edtTitle(TEdit)

 Align
 Margins
 Client
 7, 80, 5, 7

 ListBoxitem8

 edtAuthor(TEdit)

 ListBoxitem9

 edtPublisher(TEdit)

 ListBoxitem10

 edtPhone(TEdit)

 ListBoxitem11

 edtWebSite(TEdit)

 ListBoxitem12

 mmoComment(TMemo)
 mmoComment

 TextSettings.WordWrap

 True


3, 샘플 데이터 추가 후 화면요소와 연결해 화면 표시 후 테스트하기

화면 테스트를 위해 샘플(프로토타입) 데이터를 데이터 모듈에 추가합니다. 뒤에서 샘플 데이터를 실제 데이터베이스로 변경합니다.

데이터 엑세스 기능을 구현하기 위해 데이터모듈 추가

  1. File > New > Other 메뉴를 선택 해 "New Items" 대화상자를 표시합니다.
  2. 왼쪽 트리메뉴에서 Object Pascal Projects > Object Pascal Files를 선택합니다.
  3. Data Module을 선택 하고 OK 버튼을 누릅니다.
  4. 데이터 모듈이 추가되면 File > Save 메뉴를 누르고 "DataAccessModule.pas"로 저장합니다.
  5. Object Inspect(속성창)에서 Name 속성을 dmDataAccess로 변경합니다.

테스트용 샘플 데이터 추가

  1. 데이터모듈에 TPrototypeDataSource를 추가합니다.
  2. PrototypeDataSource1의 RecordCount30으로 변경합니다.
  3. PrototypeDataSource1을 더블클릭 후 Add New 버튼으로 위 그림을 참고해 항목 5개를 추가합니다.

샘플데이터와 화면요소 연결하기

  1. MainForm으로 돌아와 위에서 추가한 데이터 모듈 사용하기 위해 File > Use unit 메뉴를 선택하고 "DataAccessModule.pas" 파일을 선택 후 OK 버튼을 누릅니다.
  2. View > LiveBindings Designer 메뉴를 통해 라이브 바인딩 디자이너를 표시하고, 아래 그림을 참고해 화면요소에 데이터를 연결합니다.(두 항목간 마우스로 드래그해 연결)

도서 목록

도서 상세보기

새로운 도서 추가


연결을 마치면 Live Bindings Designer를 닫습니다.(창 우측 상단 X 버튼)


4, 사용자의 조작에 동작하는 기능코드를 작성합니다.

사용자가 목록을 누르고 버튼을 누를때 동작하는 기능을 구현 합니다.

화면(탭)이동 기능 구현

  1. 폼에 TActionList(ActionList1) 컴포넌트를 추가합니다.
  2. ActionList1을 더블클릭 후 Add Action > New Standard Action 메뉴를 선택 합니다.
  3. Tab > TChangeTabAction 항목 선택 후 OK 버튼을 눌러 추가합니다.
  4. 코드 에디터를 열고(폼 디자이너에서 F12 버튼) 선언부(코드 상단) private 영역에 아래 코드를 입력합니다.

      private
        { Private declarations }
        procedure GotoList;
        procedure GotoDetail;
        procedure GotoNew;
      public
        { Public declarations }
      end;
  5. 구현부(선언부 입력 후 Ctrl + Shift + C 단축키를 누르면 구현부의 구조가 자동 완성됩니다.)에 아래의 코드를 입력합니다.
    procedure TForm1.GotoDetail;
    begin
      ChangeTabAction1.Tab := TabItem2;
      ChangeTabAction1.ExecuteTarget(nil);
    end;
    
    procedure TForm1.GotoList;
    begin
      ChangeTabAction1.Tab := TabItem1;
      ChangeTabAction1.ExecuteTarget(nil);
    end;
    
    procedure TForm1.GotoNew;
    begin
      ChangeTabAction1.Tab := TabItem3;
      ChangeTabAction1.ExecuteTarget(nil);
    end;
  6. 도서 목록 탭에서 ListView1의 OnItemClick 이벤트에 아래의 코드를 입력[각주:3]합니다.

    procedure TForm1.ListView1ItemClick(const Sender: TObject;
      const AItem: TListViewItem);
    begin
      GotoDetail;
    end;
  7. 위 방식과 같이 아래의 표를 참고해 이벤트 핸들러 코드를 입력합니다.

    오브젝트 

    이벤트 

    소스코드 

     btnNewItem

     OnClick 

     GotoNew;

     btnBackList

     OnClick

     GotoList;
     btnCancel

     OnClick

     GotoList;

     btnSaveItem 

     OnClick

     GotoList;

  8. 폼을 선택하고 OnCreate 이벤트에 아래 코드를 입력합니다.(실행 시 탭을 감추고 첫번째 탭을 표시하는 코드입니다.)

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TabControl1.TabPosition := TTabPosition.None;
      TabControl1.TabIndex := 0;
    end;


도서 상세정보 수정/삭제 팝업메뉴 구현

  1. 도서 상세정보 탭의 추가정보 버튼(btnDetail)과, 수정(lstItemModify), 삭제(lstItemDelete) 항목의 OnClick 이벤트에 아래를 참고해 코드를 추가합니다.

    procedure TForm1.btnDetailClick(Sender: TObject);
    begin
      OverflowMenu.Visible := not OverflowMenu.Visible;
      if OverflowMenu.Visible then
      begin
        OverflowMenu.ItemIndex := -1;
        OverflowMenu.BringToFront;
        OverflowMenu.ApplyStyleLookup;
        OverflowMenu.RealignContent;
        OverflowMenu.Position.X := Width - OverflowMenu.Width - 5;
        OverflowMenu.Position.Y := Toolbar2.Height;
      end;
    end;
    
    // 수정
    procedure TForm1.lstItemModifyClick(Sender: TObject);
    begin
      OverflowMenu.Visible := False;
      GotoNew;
    end;
    
    // 삭제
    procedure TForm1.lstItemDeleteClick(Sender: TObject);
    begin
      OverflowMenu.Visible := False;
    
      MessageDlg('해당 정보를 삭제하시겠습니까?', TMsgDlgType.mtWarning,
        [TMsgDlgBtn.mbYes, TMsgDlgBtn.mbNo], 0, procedure(const AResult: TModalResult)
        begin
          if AResult = mrYes then
          begin
            ShowMessage('삭제');
          end;
        end);
    end;
  2. 폼을 선택하고 OnCreate 이벤트에 아래 코드를 추가합니다.

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TabControl1.TabPosition := TTabPosition.None;
      TabControl1.TabIndex := 0;
    
      OverflowMenu.Visible := False; // 시작 시 팝업메뉴 감추기
    end;

입력 시 키보드가 가려지지 않도록 입력박스 위치조정 기능 구현

하단의 입력박스에 입력 시 키보드가 입력박스를 가리는 경우 키보드 위로 입력박스 위치를 조정하는 기능을 구현합니다.

  1. 선언부 private 영역에 아래 코드를 입력합니다.
      private
        { Private declarations }
        FKBBounds: TRectF;
        FNeedOffset: Boolean;
    
        procedure CalcContentBoundsProc(Sender: TObject; var ContentBounds: TRectF);
        procedure RestorePosition;
        procedure UpdateKBBounds;
  2. 구현부에 아래의 코드를 입력합니다.
    procedure TForm1.CalcContentBoundsProc(Sender: TObject;
      var ContentBounds: TRectF);
    begin
      if FNeedOffset and (FKBBounds.Top > 0) then
      begin
        ContentBounds.Bottom := Max(
              ContentBounds.Bottom, 2 * ClientHeight - FKBBounds.Top);
      end;
    end;
    
    procedure TForm1.RestorePosition;
    begin
      vsbEditFocus.ViewportPosition := PointF(vsbEditFocus.ViewportPosition.X, 0);
      lytContentsNew.Align := TAlignLayout.Client;
      vsbEditFocus.RealignContent;
    end;
    
    procedure TForm1.UpdateKBBounds;
    var
      LFocused : TControl;
      LFocusRect: TRectF;
    begin
      FNeedOffset := False;
      if Assigned(Focused) then
      begin
        LFocused := TControl(Focused.GetObject);
    
        LFocusRect := LFocused.AbsoluteRect;
        LFocusRect.Offset(vsbEditFocus.ViewportPosition);
        if (LFocusRect.IntersectsWith(TRectF.Create(FKBBounds))) and
           (LFocusRect.Bottom > FKBBounds.Top) then
        begin
          FNeedOffset := True;
          lytContentsNew.Align := TAlignLayout.Horizontal;
          vsbEditFocus.RealignContent;
          Application.ProcessMessages;
          vsbEditFocus.ViewportPosition := PointF(vsbEditFocus.ViewportPosition.X,
                                                  LFocusRect.Bottom - FKBBounds.Top);
        end;
      end;
      if not FNeedOffset then
        RestorePosition;
    end;
  3. 코드에서 수학함수(Max)를 사용하기 위해 구현부(implementation) uses 절에 System.math 유닛을 추가합니다.

    implementation
    
    {$R *.fmx}
    
    uses DataAccessModule, System.Math;
  4. 폼(Form1)의 OnFocusChanged, OnVirtualKeyboardShown, OnVirtualKeyboardHidden 이벤트에 아래 코드를 참고해 코드를 추가합니다.
    procedure TForm1.FormFocusChanged(Sender: TObject);
    begin
      UpdateKBBounds;
    end;
    
    procedure TForm1.FormVirtualKeyboardHidden(Sender: TObject;
      KeyboardVisible: Boolean; const Bounds: TRect);
    begin
      FKBBounds.Create(0, 0, 0, 0);
      FNeedOffset := False;
      RestorePosition;
    end;
    
    procedure TForm1.FormVirtualKeyboardShown(Sender: TObject;
      KeyboardVisible: Boolean; const Bounds: TRect);
    begin
      FKBBounds := TRectF.Create(Bounds);
      FKBBounds.TopLeft := ScreenToClient(FKBBounds.TopLeft);
      FKBBounds.BottomRight := ScreenToClient(FKBBounds.BottomRight);
      UpdateKBBounds;
    end;
  5. 폼의 OnCreate 이벤트에 아래 코드를 추가합니다.

    procedure TForm1.FormCreate(Sender: TObject);
    begin
      TabControl1.TabPosition := TTabPosition.None;
      TabControl1.TabIndex := 0;
    
      OverflowMenu.Visible := False;
    
      vsbEditFocus.OnCalcContentBounds := CalcContentBoundsProc; // 추가
    end;


5, 전화걸기, 사진, 웹페이지 표시 기능 추가

전화걸기, 사진 촬영, 불러오기, 웹페이지 표시 기능을 추가합니다.


전화걸기 기능 추가하기

  1. 전화걸기 기능 사용을 위해 FMX.Platform과 FMX.PhoneDialer 유닛을 구현부(implementation) 유즈절에 추가합니다.

    implementation
    
    {$R *.fmx}
    
    uses DataAccessModule, System.Math, FMX.Platform, FMX.PhoneDialer;

  2. 도서 상세보기 탭의 lblPhone(연락처 항목)의 OnClick 이벤트 핸들러에 아래의 코드를 입력합니다.

    procedure TForm1.lblPhoneClick(Sender: TObject);
    var
      PhoneDlrSvc: IFMXPhoneDialerService;
    begin
      if TPlatformServices.Current.SupportsPlatformService(IFMXPhoneDialerService, IInterface(PhoneDlrSvc)) then
        PhoneDlrSvc.Call(lblPhone.Text);
    end;


웹페이지 표시 기능, 사진 기능 추가하기

웹페이지 기능과 사진 기능은 이미 구현된 소스코드를 다운받아 구현합니다.

  1. 카메라 기능, 웹브라우저 기능이 구현된 프레임 소스코드 를 다운로드 받고 압축 해제 후 프로젝트 파일(BookLogFMX.dpr) 저장경로의 하위에 Frames 폴더를 추가 후 Frames 폴더 안으로 복사합니다.

  2. Project Manager 윈도우에서 프로젝트 이름(BookLogFmx)에 마우스 오른쪽 팝업메뉴를 표시하고 Add... 메뉴를 선택 후 위 1번에서 복사한 "PhotoFrame.pas"를 선택 해 추가합니다.

  3. PhotoFrame 사용을 위해 구현부 uses절에 WebBrowserFrame, PhotoFrame을 추가합니다.

  4. "도서 상세보기" 탭의 lblWebSite(사이트 항목)의 OnClick 이벤트 핸들러에 아래의 코드를 입력합니다.

    procedure TForm1.lblWebSiteClick(Sender: TObject);
    begin
      TfrWebBrowser.CreateAndShow(Self, lblWebSite.Text);
    end;

  5. 선언부 private  영역에 아래의 메소드를 선언하는 코드를 추가합니다.

        procedure ChangeImageEvent(Image: TBitmap);

  6. 구현부에 아래의 코드를 추가합니다.

    procedure TForm1.ChangeImageEvent(Image: TBitmap);
    begin
      imgNewItem.Bitmap.Assign(Image);
    end;

  7. "새로운 도서 추가" 탭의 imgNewItem(사진)의 OnClick 이벤트 핸들러에 아래 코드를 입력합니다.

    procedure TForm1.imgNewItemClick(Sender: TObject);
    begin
      TfrPhoto.CreateAndShow(Self, ChangeImageEvent, nil);
    end;

  8. 안드로이드 백버튼을 누를때 기능이 닫히게 하기위해 폼(Form1)의 OnKeyUp 이벤트에 아래 코드를 입력합니다.
    procedure TForm1.FormKeyUp(Sender: TObject; var Key: Word; var KeyChar: Char;
      Shift: TShiftState);
    begin
      if Key = vkHardwareBack then
      begin
        if Assigned(frPhoto) then
        begin
          frPhoto.CloseFrame;
          Key := 0;
        end;
    
        if Assigned(frWebBrowser) then
        begin
          frWebBrowser.CloseFrame;
          Key := 0;
        end;
      end;
    end;


6, 사용자화면 완성! 테스트 하기

1차 사용자화면 개발완료되었습니다. 

  • 배포를 원하는 플랫폼을 선택하고 Run > Run Without Debugging 메뉴를 통해 배포 및 실행합니다.
    (안드로이드 개발환경 설정은 앱메소드 튜토리얼 동영상을 통해 확인할 수 있습니다.)

2차 따라하기에서는 실제 사용할 데이터베이스를 만들고 앱에서 데이터 연결하는 내용을 진행합니다.

관련글


  1. TabItem 추가는 TabControl 더블클릭 후 나오는 Items Designer 대화상자에서 TTabItem 선택 후 [Add Item] 버튼을 눌러 추가 가능 [본문으로]
  2. ListBoxItem 추가는 ListBox컴포넌트 더블클릭 후 나타나는 Items Designer 대화상자에서 TListBoxItem을 선택 후 [Add Item] 버튼을 눌러 추가 가능 [본문으로]
  3. Object Inspector 창의 Event 탭으로 이동 후 OnItemClick 글자 옆의 공백을 더블클릭하면 이벤트 핸들러 코드가 자동추가 [본문으로]