# 모델/뷰/컨트롤러 설계(Python)

MessageDialog
Sebastian Pölsterl
sebp@k-d-w.org 2011
Marta Maria Casetti
mmcasetti@gmail.com 2012
조성호
shcho@gnome.org 2017-2019.

# MessageDialog

# 개요

TreeView 와 ComboBox 위젯은 모델/뷰/컨트롤러 디자인을 기반으로 만들었습니다. 모델(`Gtk.TreeModel` 구현체는 보통 `Gtk.TreeStore` 또는 `Gtk.ListStore` 입니다)은 데이터를 저장하고, 뷰(예를 들어 `Gtk.TreeView`, `Gtk.ComboBox`, `Gtk.ComboBoxText`가 있습니다)는 바뀐 알림을 보여주고 모델 내용을 보여줍니다. 마지막으로 Controller는 모델의 상태를 (`append()` 또는 `remote()` 같은 모델 구현체의 일부 메서드로) 바꾸며, 이 바꾼 내용의 뷰를 (`"changed"` 같은 시그널)로 알립니다.

# 모델

`Gtk.TreeModel`의 주요 구현체 두가지에 대한 차이점은 `Gtk.ListStore`에 하위 요소 없이 데이터 한 줄이 있지만, `Gtk.TreeStore`에는 데이터 한 줄이 들어있고, 각 줄에 하위 줄(이 하위 줄에 하위 줄을 또 넣을 수 있습니다)이 있습니다.

모델의 데이터는 TreeIter나 열 인덱스, `Gtk.TreeIter`, `Gtk.TreePath`를 사용하여 가져오거나 수정할 수 있습니다.

파이썬 내장 목록 객체에서 마찬가지로 값을 가져오거나 설정할 수많은 행 갯수를 가져올 `len()`을 사용하거나 슬라이스를 사용할 수 있습니다. 아니면 `append()` 메서드에서 새로 삽입한 행 위치를 가리키는 `Gtk.TreeIter` 인스턴스를 반환합니다. 또한 `get_iter()`를 호출하여 `Gtk.TreeIter`를 가져올 수 있습니다.

각각의 노드는 하위 노드를 둘 수 없어 `Gtk.ListStore`에 한 계층만 넣을 수 있기에, 각 노드의 경로는 접근하고자 하는 행의 인덱스입니다. `Gtk.TreeStore`의 경우 경로는 인덱스 목록 또는 문자열입니다. 문자열로 된 모양새는 쉼표로 구분한 숫자 목록입니다. 각 숫자는 해당 레벨의 오프셋입니다. 따라서 `"0"`번째 경로는 최상위(루트) 노드이며, `"2:4"` 경로는 세번째 노드의 다섯번째 하위 노드입니다.

`Gtk.TreeModel`에 쓸만한 메서드:

`get_iter(path)`는 `path`를 가리키는 `Gtk.TreeIter` 인스턴스를 반환합니다. 콜론으로 구분한 숫자 목록 또는 튜플 값을 넣습니다. 예를 들어 `"10:4:0"` 문자열은 `(10, 4, 0)` 튜플과 동일하며, 두 값으로 루트로부터 11번째 떨어진 하위 노드를 가리키도록 깊이 3의 경로를 만듭니다. 11번째의 하위 노드는 5번째 노드, 5번째 하위 노드는 첫번째 노드입니다.

`iter_next(treeiter)`는 현재 레벨의 treeiter를 따르는 노드를 가리키는 `Gtk.TreeIter` 인스턴스를 반환하거나 다음 iter가 없으면 `Node` 합니다.

`iter_has_child(treeiter)`는 `treeiter`에 하위 구성요소가 있으면 `True`를, 그렇지 않으면 `False`를 반환합니다.

`iter_children(treeiter)` `treeiter`의 첫 하위 노드를 가리키는 `Gtk.TreeIter` 인스턴스를 반환합니다. `treeiter`에 하위 노드가 없으면 `None`을 반환합니다.

`get_iter_first()`는 트리(경로의 `"0"`번째)의 첫 Iterator를 가리키는 `Gtk.TreeIter` 인스턴스를 반환하며 트리가 비어있을 경우는 `None`을 반환합니다.

`Gtk.ListStore`에 쓸만한 메서드:

`append(row)`는 리스트 스토어에 각각의 열에 대한 목록 값이 될 수 있는 새 `row`를 붙입니다. `row` 값은 생략하거나 `None` 값을 넣을 수 있으며, 어떨 때는 빈 row를 붙일 수 있습니다. 메서드에서는 붙인 row를 가리키는 `Gtk.TreeIter`를 반환합니다.

`remove(iter)`는 `Gtk.ListStore`의 `iter`를 제거하며, iter 값이 유효하면 `True`를, 그렇지 않으면 `False`를 반환합니다. 제거하고 나면 `iter`를 다음 유효 행이 되도록 설정합니다.

`Gtk.TreeStore`에 쓸만한 메서드:

`append(parent, row)`는 트리 스토어에 새 행을 붙입니다. `parent`는 올바른 Gtk.TreeIter여야 합니다. 상위 요소가 `None`이면, 상위 요소의 마지막 하위 요소 다음에 새 행을 붙이며, 상위요소가 `None`이 아니면, 최상위 레벨에 행을 붙입니다. `row`은 각 열에 대한 값 목록이거나, 생략하거나, `None`값일 수 있습니다. 마지막의 경우 빈 행을 붙입니다. 메서드는 붙인 행을 가리키는 `Gtk.TreeIter`를 반환합니다.

`remove(iter)`는 `Gtk.ListStore`의 `iter`를 제거하며, iter 값이 유효하면 `True`를, 그렇지 않으면 `False`를 반환합니다. 제거하고 나면 `iter`를 다음 유효 행이 되도록 설정합니다.

# 뷰: TreeView의 경우

트리뷰는 하위 구성 요소와 상위 항목을 트리로 보여줍니다. 예시를 보려면 이 예제를 참고하십시오.

`Gtk.TreeViewColumn`는 수직 방향 열을 모아 보여줄 때 사용합니다.

`Gtk.TreeView`에 쓸만한 메서드:

`set_model(model)`은 이 트리뷰의 모델을 설정합니다. 이 트리뷰가 이미 모델 세트을 들고 있다면, 새 모델을 설정하기 전에 제거랍니다. 모델이 `None` 상태라면 이전 모델의 설정을 해제합니다.

`get_model()`은 이 트리 뷰의 기반 모델을 반환합니다. 모델이 없으면 `None`을 반환합니다.

`append_column(column)`은 열 목록에 `column`을 추가합니다.

`get_selection()`은 트리뷰 관련 `Gtk.TreeSelection`을 가져옵니다.

`Gtk.TreeViewColumn`에 쓸만한 메서드:

`add_attribute(renderer, attribute, value)`는 이 열에 속성 매핑을 추가합니다. `attribute`는 `value`에서 설정할 `renderer`의 매개변수입니다.

`pack_start(renderer, expand)`는 이 열의 시작 부분에 `renderer`를 패킹합니다. `expand` 값이 `False`면, `renderer`는 필요한 만큼보다 적은 공간을 할당합니다. 활용하지 않은 공간은 expand 값이 `True`인 각각의 셀을 균등하게 나눕니다.

`pack_end(renderer, expand)`는 열의 마지막 부분의 `renderer`를 추가합니다. `expand`값이 `False`면, `renderer`는 필요한 만큼보다 적은 공간을 할당합니다. 활용하지 않은 공간은 expand 값이 `True`인 각각의 셀을 균등하게 나눕니다.

`set_sort_column_id(sort_column_id)`는 정렬할 (뷰의) 열 기준으로 모델 열을 설정합니다. 열 헤더를 누를 수 있게 합니다.

`set_sort_indicator(setting)`는 열 헤더에 작은 화살표를 나타낼 지 여부를 설정합니다. `setting` 값은 `True`(화살표가 나타남) 또는 `False`일 수 있습니다.

`set_sort_order(order)`는 어떤 열을 정렬할 지 정렬 기준을 바꿉니다. `order` 값은 `Gtk.SortType.ASCENDING` 또는 `Gtk.SortType.DESCENDING` 일 수 있습니다.

# 뷰: ComboBox의 경우

`Gtk.ComboBox` 는 드롭 다운 메뉴의 항목 섹션을 허용합니다. 예시는 이 예제를 참고하십시오. 텍스트 방식의 목록을 선택한다면 더 단순한 `Gtk.ComboBoxText`를 활용할 수 있습니다. `Gtk.ComboBox` 와 `Gtk.ComboBoxText`에는 항목을 넣을 수 있습니다.

`Gtk.ComboBox`에 쓸만한 메서드:

`new_with_entry()` 정적 메서드에서는 항목으로 비어있는 새 `Gtk.ComboBox` 를 만들며, `new_with_model(model)` 정적 메서드에서는 `model`로 초기화 한 새 모델로 만듭니다. 그리고 `new_with_model_and_entry(model)` 정적 메서드는 이 두가지 경우를 모두 수행합니다.

`get_active_iter()`는 현재 활성 항목을 가리키는 `Gtk.TreeIter`를 반환합니다. 활성 항목이 없으면 `None`을 반환합니다.

`set_model(model)` 는 콤보 상자의 모델을 `model`로 설정하며, 이전에 설정한 모델(이 있다면) 설정을 해제합니다. `model` 값이 `None`이면, 이미 있던 모델 설정을 해제합니다. 참고로 이 함수는 셀 렌더러 자체를 지우지 않습니다.

`set_entry_text_column(text_column)`은 문자열을 가져올 콤보 상자 모델 열을 `text_column`으로 설정합니다. 이 콤보 상자 모델의 `text_column`은 `str` 형식이어야합니다(이 콤보 상자의 “has-entry” 속성을 True로 설정했을 때만 해당합니다).

`set_wrap_width(width)` 함수는 콤보 박스의 줄바꿈 너비를 `width`로 설정합니다. 줄바꿈 너비는 기본적으로 그리드에 팝업을 두고자 할 때 원하는 열 갯수입니다.

`Gtk.ComboBoxText`에 쓸만한 메서드:

`new_with_entry()` 정적 메서드는 비어있는 새 `Gtk.ComboBoxText`를 항목을 넣어 만듭니다.

`append_text(text)`는 콤보 박스에 저장한 문자열 목록에 `text`를 추가합니다.

`get_active_text()`는 콤보 박스의 현재 활성 문자열을 반환하거나 선택한 항목이 없을 경우는 `None`을 반환합니다. 콤보 박스에 항목이 있다면 이 함수는 항목의 내용을 반환합니다(꼭 목록 항목일 필요는 없습니다).

# 뷰: CellRenderer의 경우

다양한 형식의 `Gtk.CellRenderer`를 활용하여 데이터를 그리는 뷰입니다.

`Gtk.CellRenderer` 구현체와 쓸만한 메서드:

`Gtk.CellRendererText` - 셀에 텍스트를 보여줍니다.

`Gtk.CellRendererToggle` - 토글 단추 또는 라디오 단추를 셀에 보여줍니다 쓸만한 메서드는:

`set_active(setting)` - 셀 렌더러를 활성 처리하거나 비활성 처리합니다.

`get_active()` - 셀 렌더러 활성화 혀부를 반환합니다.

`set_radio(radio)` - radio가 참이면 셀 렌더러는 라디오 토글을 나타냅니다(예: 그룹 단위로 상호 배타적으로 토글). `False` 값을 설정하면 확인 상자로 나타냅니다(단독 부울린 옵션).

`get_radio()` - 확인 상자 대신 라디오 토글을 보여줄 지 여부를 반환합니다.

`Gtk.CellRendererPixbuf` - 셀 그림을 보여줍니다

`Gtk.CellRendererCombo` - 셀 텍스트를 보여줍니다만 `Gtk.CellRendererText`는 텍스트를 편집할 간단한 항목을 제공하지만 `Gtk.CellRendererCombo` 에는 텍스트를 편집할 `Gtk.ComboBox` 위젯도 들어있습니다. 관련 Gtk.Entry 위젯을 넣든 아니든 사용할 수 있으며, “has-entry” 속성 값에 따라 다릅니다.

`Gtk.CellRendererProgress` - 셀에서 진행 표시줄처럼 숫자 값을 나타냅니다. 진행 표시줄의 상단 텍스트로 표시할 수 있습니다

`Gtk.CellRendererSpinner` - 셀에서 스핀 움직임 동작을 나타냅니다

`Gtk.CellRendererSpin` - 셀에서 스핀 단추를 나타냅니다

`Gtk.CellRendererAccel`- 셀에서 키보드 바로 가기 키를 나타냅니다

# 컨트롤러: Selection

대부분 프로글매에서는 데이터를 표시할 뿐만 아니라 사용자로부터 입력 이벤트를 받아 처리합니다. 이 때, 간단하게 선택 객체 참조를 가져온 후 `"changed"` 시그널에 연결합니다.

select = tree.get_selection() select.connect("changed", on_tree_selection_changed)

그 다음 선택한 행 데이터를 가져오려면:

def on_tree_selection_changed(selection): model, treeiter = selection.get_selected() if treeiter != None: print "You selected", model[treeiter][0]

`Gtk.TreeSelection`에 쓸만한 메서드:

`set_mode(type)`는 다음 중 선택 형식을 설정합니다

`Gtk.SelectionMode.NONE` - 가능하면 아무것도 선택하지 않음

`Gtk.SelectionMode.SINGLE` - 한 개 이하로 선택할 수 있음

`Gtk.SelectionMode.BROWSE` - 정확히 요소 한개만 선택합니다. 검색 동작 초기 또는 진행 단계인 경우, 아무것도 선택하지 않을 수도 있습니다. 다른 요소를 선택할 때를 제외하고는 현재 선택한 요소의 선택 상태를 해제할 수 없도록 강제합니다.

`Gtk.SelectionMode.MULTIPLE` - 몇가지든 선택할 수 있습니다. 항목을 누를 때마다 선택 상태를 바꿉니다. Ctrl키로 선택 갯수를 늘릴 수 있고, Shift키로 현재 선택한 항목 부터 다음 선택한 하위 항목까지 쭉 선택할 수 있습니다. 일부 위젯에서는 눌러서 끄는 방식으로 일정 범위 항목을 선택할 수 있습니다.

`get_selected()`는 현재 모델을 의미하는 `model`과 현재 선택한 행을 가리키는 `Gtk.TreeIter`인 `treeiter` 또는 아무 행도 선택하지 않았을 경우 None 값이 들어가는 `(model, treeiter)` 튜플을 반환합니다. 이 메서드는 선택 모드를 `Gtk.SelectionMode.MULTIPLE`로 선택했을 때는 동작하지 않습니다. 이 경우, 선택한 행의 `Gtk.TreePath` 안스턴스 목록을 반환하는 `get_selected_rows()`를 대신 사용하십시오.

# 참고 자료

GtkTreeModel

GtkTreeView

GtkTreeViewColumn

GtkComboBox

GtkCellRenderer