728x90

1. 학습 목표

더보기
  1. 2개의 뷰(QTreeView/QListView)
    1개의 모델(QFileSystemModel) 사용 구조 이해

  2. QFileSystemModel이 “모델(Model)” 역할을 하며,
    실제 파일/폴더 데이터는 여기에만 저장된다는 점 이해하기

  3. QTreeView, QListView는 “뷰(View)”로서
    모델의 데이터를 “각자의 방식으로” 보여줄 뿐이라는 점 이해하기

  4. 하나의 Model 을 여러 View가 공유할 수 있고,
    선택/루트 인덱스만 바꿔서 다른 화면 효과를 낼 수 있다는 것 체감하기

  5. 트리에서 선택된 폴더에 따라 다른 뷰의 내용에 반영되는 동작을 통해
    “같은 모델, 다른 View, 다른 표현” 구조를 익히기

 

2. 프로젝트 구조 만들기

더보기
2View1Model_Demo/
 ├─ main.py        # 실행 진입점 (QApplication 생성 + 메인 위젯 표시)
 └─ widget.py      # 하나의 QFileSystemModel(모델)을
                   # - QTreeView (폴더 트리)
                   # - QListView (선택된 폴더 안의 파일/폴더 목록)
                   # 두 개의 View가 함께 공유하는 예제 위젯.
main.py
0.00MB
widget.py
0.00MB

 

3. 메인 위젯 코드 작성 (widget.py)

: 6.11 QScrollArea 사용 구조와 비교

더보기
# widget.py

import sys

from PySide6.QtCore import QDir
from PySide6.QtWidgets import (
    QWidget, QSplitter,
    QFileSystemModel, QTreeView, QListView,
    QVBoxLayout
)


class Widget(QWidget):
    """
    하나의 QFileSystemModel(모델)을
    - QTreeView (폴더 트리)
    - QListView (선택된 폴더 안의 파일/폴더 목록)
    두 개의 View가 함께 공유하는 예제 위젯.
    """
    def __init__(self, parent=None):
        super().__init__(parent)

        # [1] 기본 창 설정
        self.setWindowTitle("Model/View 데모 - QTreeView + QListView")
        self.resize(800, 400)

        # [2] 공통 모델 생성 (파일 시스템 모델)
        self.model = QFileSystemModel(self)
        # Data(현재 작업 디렉토리를 루트 경로) 설정
        root_path = QDir.currentPath()
        self.model.setRootPath(root_path)

        # [3] 스플리터 생성 (왼쪽 트리, 오른쪽 리스트)
        splitter = QSplitter(self)

        # --- (1) TreeView 설정 ---
        self.tree_view = QTreeView(splitter)
        self.tree_view.setModel(self.model)
        # 트리뷰 루트 인덱스 설정
        self.tree_view.setRootIndex(self.model.index(root_path))
        # 폴더만 보이게 하고 싶다면 옵션들 조정 가능 (예: self.tree_view.setRootIsDecorated(True) 등)

        # --- (2) ListView 설정 ---
        self.list_view = QListView(splitter)
        self.list_view.setModel(self.model)
        self.list_view.setRootIndex(self.model.index(root_path))

        # [4] 트리에서 선택이 바뀌면, 리스트 뷰도 같이 변경되도록 연결
        # selectionModel()은 "선택 상태"를 관리하는 모델
        self.tree_view.selectionModel().currentChanged.connect(
            self.on_tree_current_changed
        )

        # [5] 전체 레이아웃
        layout = QVBoxLayout(self)
        layout.addWidget(splitter)
        self.setLayout(layout)

    # 슬롯 함수: 트리에서 선택된 폴더에 맞춰 리스트뷰 갱신
    def on_tree_current_changed(self, current, previous):
        """
        트리에서 선택이 바뀔 때마다 호출됨.
        - current : 현재 선택된 QModelIndex
        - previous: 이전에 선택되어 있던 QModelIndex
        """
        # current가 디렉토리이면, 그 폴더를 리스트뷰의 루트로 사용
        if self.model.isDir(current):
            self.list_view.setRootIndex(current)
        else:
            # 파일을 클릭한 경우 → 그 파일이 속한 부모 폴더를 리스트에 표시
            parent_index = current.parent()
            self.list_view.setRootIndex(parent_index)
# 프로그램 시작 시 첫 항목 자동 선택을 해제하고 싶을 때 추가

from PySide6.QtCore import QTimer, QModelIndex

    QTimer.singleShot(0, self._clear_initial_selection)

    def _clear_initial_selection(self):
        sel_model = self.tree_view.selectionModel()
        if sel_model is not None:
            sel_model.clearSelection()  # 선택 상태 제거
        self.tree_view.setCurrentIndex(QModelIndex())  # current index 도 무효화

 

 

3.1 모델 생성 – QFileSystemModel

        # [2] 공통 모델 생성 (파일 시스템 모델)
        self.model = QFileSystemModel(self)
        # Data(현재 작업 디렉토리를 루트 경로) 설정
        root_path = QDir.currentPath()
        self.model.setRootPath(root_path)
  • QFileSystemModel 은 디스크의 폴더/파일 구조를 Model로 표현하는 Qt의 준비된 모델 클래스입니다.
  • setRootPath()로 “어디부터 보여줄지”를 지정합니다.
    • 여기서는 QDir.currentPath() → 현재 작업 폴더
  • 이 객체 변수 model 안에 실제 파일/폴더 정보가 담기고,
    그 정보를 여러 View 에서 동시에 읽어갈 수 있음.
Model/View 개념 포인트

- QFileSystemModel은 파일/폴더 정보(데이터)를 가진 Model 객체이고,
- 나중에 여러 View가 이 모델을 공유하면서 서로 다른 방식으로 같은 데이터를 보여줄 수 있습니다.

 


 

3.2 두 개의 View에 동일 모델 연결

 

3.2.1 왼쪽 뷰

  • QTreeView, 트리형 폴더 구조 뷰
self.tree_view = QTreeView(splitter)
self.tree_view.setModel(self.model)
self.tree_view.setRootIndex(self.model.index(root_path))
  • setModel(self.model)
    • 앞에서 만든 파일 시스템 모델을 이 뷰에 연결
    • TreeView 가 (파일 시스템 model 을 사용해서) data 를 표시하겠다.
    • view ← model ← data 
  • setRootIndex(...)
    → 트리의 최상위로 어떤 폴더를 보여줄지 결정.

 

 

3.2.2 오른쪽 뷰

  • QListView, 리스트형 목록 뷰
self.listView = QListView(self.splitter)
self.listView.setModel(self.model)
self.listView.setRootIndex(self.model.index(root_path))
  • setModel(self.model)
    • 앞에서 만든 파일 시스템 모델을 이 뷰에 연결
    • QListView는 한 줄짜리 리스트 형태로 데이터를 보여주는 뷰입니다.
    • ListView 가 (파일 시스템 model 을 사용해서) data 를 표시하겠다.
    • view ← model ← data 
핵심

- self.model 객체는 단 하나 같은 모델을 공유
- QTreeView, QListView 둘 다 setModel(self.model)로 연결
- 두 View는 “같은 데이터를 다른 모양으로 보여주는” 역할만 함
- 데이터는 모델 하나, 표현은 여러 뷰로 다양하게

 


 

4. 선택 변경

 

4.1 시그널

self.treeView.selectionModel().currentChanged.connect(
    self.on_tree_current_changed
)
  • treeView.selectionModel()은
    → View의 어떤 항목이 선택되었는지 선택 상태 를 관리하는 모델입니다.
  • currentChanged 시그널
    • 트리에서 항목을 클릭하여 현재 선택이 바뀔 때마다 발생합니다.
  • on_tree_current_changed 슬롯 함수에 연결해
    • 트리에서 선택한 폴더가 바뀌면
    • 오른쪽 리스트가 그 폴더의 내용으로 바뀌고,
    • 콘솔에 한글로 경로를 출력하도록 합니다.

 

 

4.2 슬롯 함수 – on_tree_current_changed

def on_tree_current_changed(self, current, previous):
    if self.model.isDir(current):
        self.list_view.setRootIndex(current)
    else:
        parent_index = current.parent()
        self.list_view.setRootIndex(parent_index)
  • current는 새로 선택된 항목의 QModelIndex 입니다.
  • self.model.isDir(current) 로
    선택된 항목이 “폴더인지, 파일인지” 구분 가능
  • 폴더면 → 그 폴더 내용을 리스트 뷰에 보여줌
  • 파일이면 → 그 파일이 들어있는 부모 폴더를 리스트 뷰에 보여줌

 

4. 실행 진입점 작성 (main.py)

더보기
# main.py
import sys
from PySide6.QtWidgets import QApplication

from widget import Widget


def main():
    # [1] QApplication 생성
    app = QApplication(sys.argv)

    # [2] 메인 위젯 생성
    window = Widget()
    window.show()

    # [3] 이벤트 루프 실행
    sys.exit(app.exec())


if __name__ == "__main__":
    main()

 

5. 추가 실습 과제

: (1) QTableView를 추가하여 3개의 뷰로 확장하기

더보기

 

 

목표: QTableView를 추가하여 3개의 뷰로 확장하기

  • 지금 있는 QTreeView QListView에 추가로
    QTableView를 하나 더 배치하여동일한 QFileSystemModel을 공유하는 3중 뷰 만들기
# widget.py 힌트 코드

from PySide6.QtWidgets import QTableView  # 상단 import에 추가

# __init__ 안에서
# --- (3) QTableView 설정 ---
self.table_view = QTableView(splitter)
self.table_view.setModel(self.model)
self.table_view.setRootIndex(self.model.index(root_path))

# on_tree_current_changed 안에서
if self.model.isDir(current):
    self.list_view.setRootIndex(current)
    self.table_view.setRootIndex(current)   # ← 추가
else:
    parent_index = current.parent()
    self.list_view.setRootIndex(parent_index)
    self.table_view.setRootIndex(parent_index)    # ← 추가

 

 

파일

widget.py
0.00MB