AddressBook.zip
0.01MB

자 전시간에 이어서 이제 주소록을 위해 ListView를 구성해 보자.  상업용 프로그램에서  리스트뷰는 일련의 정형화된 데이터를 표의 형태로 표시해 주기때문에 아마도 버튼류나 입력을 제외하고 가장 많이 사용될 것이다. 리스트뷰를 설명하기 위해서는 Model / View 에 대해서 알아야 하나 일단 먼저 화면을 구성후 설명 하겠다. 

  • ListView 구성요소

ListView 는 엑셀에서 보든이 표의 타이틀에 해당하는 header 와 일정한 형식의 데이터들이 컬럼으로 구분되어 반복되도록 표현하는 데이터를 표현하는 delegate 라는 속성을 가지고 있다. 

위 코드를 실행하면 아래 화며이 나온다. header 영역이 녹색으로 표시됨을 알 수 있다. 어 근데 왜 데이터 영역은 파란색으로 보이지 않지? 데이터를 넣지 않았으니 당연하지 하면 개발자로서의 논리적인 감각이 있으니 정진하시라.

 

  • ListModel

자 이제 뭐라도 데이터를 넣어서 표시해보자. 실무에서는 이부분을 C++로 데이터를 만들어 넣지만 지금 거기까지 가기에는 아직 갈길이 멀다. C++로 데이터를 만들어 연동 전에 디자인이 잘 되었는지 확인하기 위해 QML 안에서 데이터를 생성해 보자. 아까 View / Model의 관계를 설명해야 한다고 했는데 아주 일부분만 먼저 말해야 겠다.

List형식으로 데이터를 보여주기 위해 QML에서는 ListModel 이라는 component를 제공한다. 일단 주소록의 데이터를 대략 아래와 같이 정의해 보자. qml안에 임의의 위치에서 아래와 같이 정의해보자. 3개의 주소록 정보를 담았다.

그리고 ListView 에서 model이라는 프로퍼티를 추가하고 ListModel의 id를 입력 후 프로그램을 실행해 본다.

짜짠! Header영역과 3개의 데이터를 의미는 3줄의 데이터 영역이 표시되었다.

현재의 구현으로는 ListView는 데이터가 3개라는 것만 알지 어떻게 표현해야 할지는 알지 못한다.

  • header & delegate 세부 디자인

header와 delegate를 위한 디자인을 ListViwe안에서 작성해도 되지만 Component 타입으로 별도 디자인한 후  id로 정의할 수 있으니 이번엔 그렇게 고쳐보자. 아래 코드는 데이터를 위해 Component를 디자인한 것이다. 

 

위 24행에 정의한 listWidth는 별도의 사용자 정의 프로퍼티는 정의한 ListView의 넓이를 가리킨다. 이처럼 미리 정의된 property만 사용하는 것이 아니라 임의의 property를 추가할 수 있다. property를 정의하는 형식은 아래를 같다.

데이터행에서 ListModel에서 정의한 name, age, phoneNumber 를 mode. 을 붙여서 표현하면 ListView가  model 프로퍼티에 연결된 ListModel의 순환하면서 ListElement의 key와 매칭되는 속성을 찾은뒤 값을 읽어 표시한다.

 

이제 Header도 동일하게 디자인 해주자. 각 컬럼의 폭은 데이터와 동일한것이 좋으니 delegate 디자인을 카피해 와서 text만 헤더에 맞게 작성하고 실행해 보자.

이제 ListView 에서 header, delegate를 각각의 id을 선언한 후 실행 해보자. ListView 의 코드가 좀더 간결해졌다.

자. 뭔가 디자인이 구리긴 하지만 Header와 List Data가 출력되는 형식을 갖추었다. 디자인 감각은 없지만 최소한의 구분선이 없으로 뭔가 허전하다. delegate를 디자인 할때 Rectagle로 한번 더 선언한 뒤 margin과 border color를 지정해 보자. anchors.magins  에 값을 넣으면 4방향의 margin 값이 적용되고 상하만 margin을 주고 싶을 경우 topMargin, bottomMaring 에 값을 넣으면 된다. 

그리고 표시되는 라벨 텍스트를 정렬하고, 배경 색상도 지정하면 좀더 괜찮아 보일 것이다. 헤더 영역은 darkgray, 데이터 영역은 "transparet"로 선언하겠다..

실행해 보면 아래와 같다. 처음의 밑밑한 디자인 보자는 좀 나아 보이지만 여전히 상업용으로 쓰기에는 구린 디자인이다. 하지만 그런 부분은 디자이너에게 맡긴다고 생각하고 좀더 기능을 완성해 보자. 

  • User Interaction 

프로그램을 실행했을때 뭔가 그럴싸해 보이지만 데이터행을 선택하거나 마우스가 움직여도 반응이 없다. 마우스가 데이터행을 이동할때마다 뭔가 색상이 변경되어 반응하도록 해보자. delegate의 안쪽 Rectang 에서 MouseArea를 선언하고 마우스 움직임에 따른 색상을 지정한다. onEntered, onExited는 각각 마우스가 영역 안에 진입할때와 빠져 나올때 발생하는 이벤트들이다. hoverEnabled : true 도 잊지 말고 설정해두어야 한다. 기본값이 false여서 영역안에서 마우스의 움직임에 대해서 event가 발생하지 않게된다. 아마 필요없는경우 불필요한 부하는 줄이기 위한 방안인듯 싶다.

자 이제 마우스의 움직임에 따라 lightblue 색상으로 데이터행들이 변경됬다. 이제 사용자 그중 한 행을 클릭했을 때 blue 색상으로 좀더 진하게 선택을 표시하고 선택된 데이터 행은 마우스가 이동해도 blue 색상이 유지되도록 해보자.

새로운 property 인 highlight를 정의해야 한다.

그리고 ListView에 highlight를 추가하여 Component 를 연결한다. 그리고 실행보면 예상처럼 작동되지 않는다. highlight 는 ListView가 가지고 있는 currentIndex 의 값이 변경될때 작동된다. 이제 MouseArea 에 Click이벤트를 추가하여 클릭시 인덱스를 변경해보자. 여기서 원래 c++개발자여서 느끼는 상당히 직관적이지 않은 부분이 있다. currentIndex 는 ListView가지고 있던 속성이라고 이해되지만 index는 어디서 나온것인가? delegate을위해 정의한 rectangle, row, mousearea어디를 봐도 index 속성이 찾을 수 없다. javascrpt 가 실시간으로 실행되면서 ListView의 row가 정의되면 그때 연결되는 변수명인듯 하다. 어찌보면 유연함 이겠지만 이해하면 학습하기는 상단히 까다롭낟. 어쨋건 delegate 안에서 index는 ListView에서 마우스가 위치한 행을 가리켜 준다.

의심스러워서 인덱스가 잘 선택되는지 로그도 남겨보았다. 자 이제 원하는대로 되었는지 실행해보자. 첫행이 블루로 보인다. 하지만 다른 행을 클릭할 경우 블루색상이 잠시 나타났다가 깜빡임을 볼 수 있을 것이다. 내부 메커니즘을 추적할 순 없지만 예상컨데 마우스 클릭에 의해 highlight 색상이 반영되었다가 onEntered 이벤트가 재작동되면서 lightBlue로 변경되는 것 같다. 테스트를 위한 위코드에서 onEntered/onExited를 잠시 주석처리 후 실행해보자.

예상대로 마우스 클릭 시마다 highlight 색상으로 잘 변경됨을 확인하였다. 자 이대로 끝내야 할까? 상업적 수준의 리스트뷰라면 마우스가 이동하면서 자연스럽에 hovering 되는 색상도 나오고 선택했을때 선택 색상도 나와야 할것이다. 좀더 코드를 고쳐보자. 즉 마우스가 행을 진입하거나 빠져나올때 선택된 행인지 판단하여 색상을 다르게 지정하는 것이다. 그리고 진입, 진출이 아니라 클릭했을때도 기존 색상을 투명하게 처리하여 highlight 속성이 작동되도록 처리한다.

자 이제 실행해보면 선택한 행은 blue로 마우스가 행을 이동하면 선택되지 않은 행들은 lightGray에서 lightBlue로 User Interactive하게 변경된다.

  • Scrolling

그럼 ListView의 기본적인 디자인은 끝난는가? 아니다. 지금은 리스트가 3개만 가지고 있다. 실제 프로그램들은 수백, 수천개를 가지고 있으니 테스트를 위한 ListModel의 갯수를 10개로 늘리고 창높이를 조절해 보자. 이렇게 한뒤 실행해도 ListView에서 기본 제공하는 기능으로 마우스 휠로 데이터 행을 이동해볼 수는 있다.

이제 스크롤바가 보이도록 추가하자. ListView는 자체적인 가로와 세로 스크롤바를 위한 속성을 제공한다. ListView 안에 적당한 영역에서 아래와 같이 ScrollBar.vertical 에서 Scrollbar를 선언해 주자. 스크롤바가 보이는 정책도 지정해 줄수 있도 AlwayOn를 항상 보이는 것이고 주석 처리된 AsNeeded는 스크롤바가 필요할 경우에만 보여준다.

자 이제 실행해서 최종적인 모양을 확인해보자, 스크롤링도 되고, 하이라이트, 호버링에 의한 인터랙션까지 모두 작동한다. 

 

디자인만 예쁘게 하면 상업용으로 쓸수 있을까? 아니다 사용자는 아마도 컬럼의 넓이를 조절하고 싶을 수도 있다. 힌트를 주자면 지금까지 해온것처럼 header 디자인 영역에 label 만 있는게 아니라 일정한 선을 세로로 긋도록 하고 그 선을 마우스로 드래깅 할때 header의 column 넓이와 데이터의 comumn 넓이를 조정해 주면된다. 여기까지 잘 따라 왔으면 한번 도전해 보자. 거기까지 되면 상업용으로 쓸수 있을까? 역시 아니다. 사용자는 아마도 헤더의 특정 컬럼을 클릭하면 오름차순이나 내림차순으로 변경하고 싶을지도 모른다. 우린 그저 가장 기본이 되는 유저 액션까지 처리한 것에 불과하지만 이제 GUI를 넘어서는 작업을 할 준비는 되었다.

  • 마무리 하며 다음 연재는?

ListView를 구성하기 위한 필수 속성 header, delegate, model, scrollbar등에 대하여 학습니다. 여긴 없지만 header외에 footer라는 것도 있어 하단의 summary 같은 것이 필요할 경우 정의할 수도 있다고 하니 사이트에서 문서로 공부 바란다. 이번 연재부터 각 연재마다 최종 작업물은 파일로 첨부하겠다.

계속되는 GUI 작업이 지겨웠을 수 있으니 다음시간에는 재미있는 C++ 코딩을 시작해보자 실제 DB나 파일로부터 읽어들였다고 가정한 수백개의 C++ 로 작성된 주소록 데이터를 어떻게  QML에서 불러들여 표시할 수 있는지 또 반대로 GUI에서 추가, 삭제, 편집한 데이타들이 C++의 자료 구조로 저장하는 방법에 대해 익혀보자.

 

 

 

+ Recent posts