1강. Model/View 개념

0. 학습 목표
→ Model/View 구조의 역할, 구조 문제, 의존성 문제, 해결 흐름을 단계적으로 이해합니다.
이번 4.1 단계에서는 GUI 프로그램에서 자주 사용되는 Model/View모델/뷰 구조를 학습합니다.
Model/View가 처음에는 어렵게 느껴질 수 있습니다.
이번 글에서는 복잡한 Qt Model 을 바로 다루지 않습니다.
먼저 왜 Model/View 구조가 필요한지를 문제 상황으로 이해하고,
그다음 Model과 View의 역할 분리를 차근차근 살펴봅니다.
| 학습 목표 | 내용 | |
| 1 | Model/View 구조 이해 | Model은 데이터를 관리하고, View는 데이터를 화면에 보여주는 역할이라는 점을 이해합니다. |
| 2 | 구조 문제 이해 | 데이터가 각각의 View 안에 들어가 있으면 같은 데이터를 여러 화면에서 공유하기 어렵다는 점을 이해합니다. |
| 의존성 문제 이해 | View가 데이터를 직접 들고 있으면 화면 코드와 데이터 코드가 강하게 묶여 유지보수가 어려워질 수 있음을 이해합니다. |
|
| 3 | Model 분리 이해 | 데이터를 View 밖으로 꺼내 Model에서 중앙 관리하는 구조를 이해합니다. |
| View 분리 이해 | View는 데이터를 직접 소유하지 않고, Model의 데이터를 화면에 표시하는 역할에 집중한다는 점을 이해합니다. |
이번 단계의 핵심
Model/View 구조는 데이터를 저장하는 부분과 데이터를 보여주는 화면을 분리하는 구조입니다.
Model은 데이터를 관리하고, View는 화면 표시를 담당합니다.
1. Model/View 구조란?
→ Model과 View가 각각 어떤 역할을 담당하는지 먼저 이해합니다.
1.1 Model과 View의 기본 의미
Model/View 구조는 GUI 프로그램에서 데이터 관리와 화면 표시를 나누는 방식입니다.
이름만 보면 어려워 보이지만, 역할을 나누어 보면 단순합니다.
Model
↓
데이터를 저장하고 관리하는 역할
View
↓
데이터를 화면에 보여주는 역할
Model은 데이터를 가지고 있습니다.
View는 Model에 있는 데이터를 가져와 사용자에게 보여줍니다.
따라서 Model/View 구조에서는 View가 데이터를 직접 소유하지 않습니다.
중요한 점
View는 데이터를 보여주는 화면이고, Model은 데이터를 관리하는 저장소입니다.
이 둘을 분리하면 같은 데이터를 여러 화면에서 함께 사용할 수 있습니다.
1.2 간단한 비유로 이해하기
GUI 프로그램에서는 같은 데이터를 여러 화면에서 보여줘야 하는 경우가 많습니다.
예를 들어 로그인한 사용자 데이터는 메인 화면, 설정 화면, 프로필 화면, 알림 화면에서 모두 필요할 수 있습니다.
이때 각 화면이 데이터를 따로 저장하면 문제가 생깁니다.
어느 한 화면에서 데이터가 바뀌어도 다른 화면은 그 변경 사실을 모를 수 있습니다.
사용자 데이터
↓
UserModel
↓
카드 화면
리스트 화면
텍스트 화면
데이터는 하나입니다.
하지만 화면 표현 방식은 여러 개가 될 수 있습니다.
기억할 문장
Model/View 구조에서는 데이터는 하나로 관리하고, 화면 표현 방식은 여러 개로 나눌 수 있습니다.
2. 재사용 문제: 데이터가 View 안에 들어가 있는 구조
→ 기존 스크롤 UI 예제를 통해 데이터가 View 안에 들어간 구조를 확인합니다.
2.1 기존 예제에서 사용한 방식
이전 스크롤 UI 예제에서는 여러 방식으로 데이터를 화면에 표시했습니다.
QScrollArea, QListWidget, QTextEdit은 모두 스크롤 가능한 화면을 만들 수 있는 위젯입니다.

| 방식 | 데이터를 넣는 방법 |
| QScrollArea | QLabel을 만들어 레이아웃에 직접 추가했습니다. |
| QListWidget | addItem()으로 항목을 직접 추가했습니다. |
| QTextEdit | append()로 로그 텍스트를 직접 추가했습니다. |
이 방식은 간단한 화면을 만들 때는 편리합니다.
하지만 데이터가 View 내부에 들어간다는 공통점이 있습니다.
2.2 QScrollArea: QLabel 안에 데이터가 들어감
QScrollArea 기반 화면에서는 QLabel을 직접 만들어 레이아웃에 추가했습니다.
label = QLabel("항목 1")
content_layout.addWidget(label)
이 코드에서는 표시할 문자열이 QLabel 안에 직접 들어갑니다.
즉, 데이터 저장소와 화면 표시가 분리되어 있지 않습니다.
QScrollArea
↓
content_layout
↓
QLabel("항목 1")
QLabel("항목 2")
QLabel("항목 3")
데이터가 QLabel 안에 들어간 상태
구조 문제
QLabel에 직접 들어간 데이터는 다른 View에서 쉽게 공유하기 어렵습니다.
2.3 QListWidget: 내부 항목으로 데이터가 들어감
QListWidget 기반 화면에서는 addItem()으로 항목을 추가했습니다.
self.list_widget.addItem("항목 1")
self.list_widget.addItem("항목 2")
self.list_widget.addItem("항목 3")
QListWidget은 항목을 쉽게 추가할 수 있는 편리한 위젯입니다.
하지만 addItem()으로 추가한 데이터는 QListWidget 내부 항목으로 관리됩니다.
QListWidget
↓
내부 항목 저장 구조
↓
"항목 1"
"항목 2"
"항목 3"
구조 문제
QListWidget 내부에 들어간 항목 데이터는 다른 View와 자연스럽게 공유하기 어렵습니다.
2.4 QTextEdit: 내부 문서에 데이터가 들어감
QTextEdit 기반 화면에서는 append()로 로그를 추가했습니다.
self.log_textedit.append("로그 1")
self.log_textedit.append("로그 2")
self.log_textedit.append("로그 3")
append()로 추가한 텍스트는 QTextEdit 내부 문서에 저장됩니다.
화면에 보여주기는 쉽지만, 원본 데이터를 다른 View와 공유하기는 어렵습니다.
QTextEdit
↓
내부 Document
↓
로그 1
로그 2
로그 3
구조 문제
로그 데이터가 QTextEdit 내부에 직접 저장되면, 다른 View에서 같은 로그 데이터를 재사용하기 어렵습니다.
2.5 구조 문제 정리
세 방식의 공통 문제는 데이터가 View 내부에 들어가 있다는 점입니다.
| View | 데이터 위치 | 구조 문제 |
| QScrollArea | QLabel 같은 자식 위젯 안 | 다른 View와 공유하기 어렵습니다. |
| QListWidget | QListWidget 내부 항목 | 다른 View와 공유하기 어렵습니다. |
| QTextEdit | QTextEdit 내부 문서 | 다른 View와 공유하기 어렵습니다. |
QScrollArea ← 데이터가 QLabel 안에 있음
QListWidget ← 데이터가 QListWidget 안에 있음
QTextEdit ← 데이터가 QTextEdit 안에 있음
↓
View마다 데이터를 따로 들고 있는 구조
이번 장의 핵심
View 안에 데이터가 들어가면 화면을 빠르게 만들 수는 있지만, 같은 데이터를 여러 View에서 공유하기 어렵습니다.
3. 의존성 문제: View가 데이터를 소유
→ 같은 데이터를 여러 화면에서 사용할 때 View와 데이터가 강하게 묶이는 문제를 이해합니다.
3.1 의존성이란?
의존성이란 한 코드가 다른 코드에 얼마나 강하게 묶여 있는지를 의미합니다.
GUI 프로그램에서는 View가 데이터를 직접 들고 있을 때 의존성이 강해질 수 있습니다.
View
├── 화면 표시 코드
└── 데이터 저장 코드
화면과 데이터가 한 곳에 섞여 있음
처음에는 간단해 보입니다.
하지만 화면이 늘어나고, 같은 데이터를 여러 View에서 사용하기 시작하면 문제가 커집니다.
참고
의존성이 강하다는 것은 한쪽 코드를 바꾸면 다른 쪽 코드도 함께 영향을 받기 쉽다는 뜻입니다.
3.2 사용자 정보 예시로 보기
예를 들어 로그인한 사용자 정보가 있다고 가정하겠습니다.
user = {
"name": "홍길동",
"email": "hong@example.com",
"role": "관리자"
}
이 사용자 정보는 한 화면에서만 필요한 것이 아닙니다.
메인 화면, 설정 화면, 프로필 화면, 알림 화면에서 모두 필요할 수 있습니다.
| 화면 | 표시해야 하는 정보 |
| 메인 화면 | 홍길동 님 환영합니다. |
| 설정 화면 | 현재 권한: 관리자 |
| 프로필 화면 | 이메일: hong@example.com |
| 알림 화면 | 사용자 이름 또는 권한에 따라 알림 표시 |
user 데이터
↓
메인 화면
설정 화면
프로필 화면
알림 화면
같은 데이터를 여러 View에서 사용해야 함
즉, 같은 데이터를 여러 View에서 공유해야 하는 상황입니다.
3.3 각 View가 데이터를 직접 들고 있는 구조
아래 코드는 각 View가 userInfo를 직접 들고 있는 예시입니다.
class MainView(QWidget):
def __init__(self, userInfo):
super().__init__()
self.userInfo = userInfo
label = QLabel(f"{self.userInfo['name']} 님 환영합니다")
class ProfileView(QWidget):
def __init__(self, userInfo):
super().__init__()
self.userInfo = userInfo
label = QLabel(self.userInfo["email"])
이 코드는 처음에는 괜찮아 보입니다.
MainView도 userInfo를 받고, ProfileView도 userInfo를 받기 때문입니다.
하지만 View가 많아지면 각 View가 각 데이터를 따로 들고 있는 구조가 됩니다.
MainView
└── self.userInfo
ProfileView
└── self.userInfo
SettingView
└── self.userInfo
NotificationView
└── self.userInfo
View마다 userInfo를 들고 있는 구조입니다.
하나의 View에서 userInfo가 변경되어도 다른 View는 그 변경 사실을 자동으로 알 수 없습니다.
의존성 문제
View가 데이터를 직접 들고 있으면 데이터 변경을 여러 View에 동시에 반영하기 어렵습니다.
또한 View 코드와 데이터 코드가 강하게 묶여 유지보수가 어려워질 수 있습니다.
3.4 데이터 변경 시 생기는 문제
예를 들어 사용자의 이메일이 바뀌었다고 가정하겠습니다.
user["email"] = "new@example.com"
이때 ProfileView는 새 이메일을 보여줘야 합니다.
알림 화면도 새 사용자 정보를 기준으로 동작해야 할 수 있습니다.
하지만 각 View가 데이터를 따로 들고 있다면, 모든 View를 직접 찾아서 갱신해야 합니다.
사용자 정보 변경
↓
MainView도 갱신해야 함
ProfileView도 갱신해야 함
SettingView도 갱신해야 함
NotificationView도 갱신해야 함
↓
화면이 많아질수록 관리가 어려워짐
기억할 문장
데이터가 View에 흩어져 있으면, 데이터 변경을 추적하고 반영하기 어렵습니다.
4. 해결 방법: Model 분리와 View 분리
→ 데이터를 Model로 분리하고, View는 화면 표시 역할에 집중하도록 구조를 바꿉니다.
4.1 먼저 문제 구조 다시 보기
기존 방식에서는 View가 데이터를 직접 들고 있었습니다.
view_1 ←── data
view_2 ←── data
view_3 ←── data
이 구조에서는 데이터가 View에 종속됩니다.
즉, View가 바뀌면 데이터 관리 방식도 함께 영향을 받을 수 있습니다.
| 문제 | 설명 |
| 데이터 중복 | 여러 View가 비슷한 데이터를 각각 들고 있을 수 있습니다. |
| 변경 반영 어려움 | 한 View에서 데이터가 바뀌어도 다른 View가 자동으로 알기 어렵습니다. |
| 유지보수 어려움 | View가 많아질수록 데이터 수정 코드가 여러 곳에 흩어질 수 있습니다. |
| 의존성 증가 | 화면 코드와 데이터 코드가 강하게 묶입니다. |
문제 구조
View가 데이터를 직접 가지면, 데이터가 화면 코드에 묶입니다.
4.2 해결 1: Model을 분리한다
첫 번째 해결은 데이터를 View 밖으로 꺼내는 것입니다.
그리고 데이터를 저장하고 관리하는 별도의 객체를 만듭니다.
이 객체를 Model이라고 생각하면 됩니다.
view_1 ←─┐
view_2 ←── model ←─ data
view_3 ←─┘
이 구조에서는 데이터가 View 안에 들어가지 않습니다.
모든 View는 Model을 통해 같은 데이터를 봅니다.
class UserModel:
def __init__(self):
self.user = {
"name": "홍길동",
"email": "hong@example.com",
"role": "관리자"
}
def get_name(self):
return self.user["name"]
def get_email(self):
return self.user["email"]
def get_role(self):
return self.user["role"]
def set_email(self, email):
self.user["email"] = email
UserModel은 사용자 정보를 한 곳에서 관리합니다.
이제 사용자 정보는 여러 View에 흩어져 있지 않고, UserModel 안에 모입니다.
Model 분리의 핵심
데이터를 View 안에 넣지 않고, Model에서 중앙 관리합니다.
데이터가 한 곳에 모이면 여러 View가 같은 데이터를 함께 사용할 수 있습니다.
4.3 해결 2: View는 화면 표시 역할만 맡는다
두 번째 해결은 View의 역할을 줄이는 것입니다.
View는 데이터를 직접 저장하지 않고, Model에서 필요한 데이터를 가져와 화면에 보여주기만 합니다.
class MainView(QWidget):
def __init__(self, user_model):
super().__init__()
self.user_model = user_model
label = QLabel(f"{self.user_model.get_name()} 님 환영합니다")
class ProfileView(QWidget):
def __init__(self, user_model):
super().__init__()
self.user_model = user_model
label = QLabel(self.user_model.get_email())
MainView와 ProfileView는 더 이상 user 딕셔너리를 직접 관리하지 않습니다.
대신 같은 UserModel을 전달받고, 그 Model의 데이터를 화면에 표시합니다.
UserModel
├── name: 홍길동
├── email: hong@example.com
└── role: 관리자
MainView → UserModel의 name 표시
ProfileView → UserModel의 email 표시
SettingView → UserModel의 role 표시
같은 Model을 바라보지만, 각 View가 보여주는 방식은 다를 수 있습니다.
View 분리의 핵심
View는 데이터를 직접 소유하지 않습니다.
View는 Model의 데이터를 화면에 표시하는 역할에 집중합니다.
4.4 실제 Qt Model/View와의 관계
위의 UserModel 예시는 Model/View 개념을 이해하기 위한 단순 예시입니다.
실제 Qt에서는 더 전문적인 Model 클래스를 사용할 수 있습니다.
| Qt Model 클래스 | 역할 |
| QAbstractItemModel | Qt Model/View 구조의 기본이 되는 추상 Model 클래스입니다. |
| QStringListModel | 문자열 리스트 데이터를 Model로 다룰 때 사용할 수 있습니다. |
| QStandardItemModel | 일반적인 표, 트리, 리스트 데이터를 표현할 때 사용할 수 있습니다. |
| QFileSystemModel | 파일 시스템 데이터를 Model로 제공할 때 사용할 수 있습니다. |
참고
이번 단계에서는 QAbstractItemModel을 직접 구현하지 않습니다.
우선 데이터를 View 밖으로 분리하고, View는 Model의 데이터를 표시한다는 핵심 개념에 집중합니다.
5. Model/View 방식 비교
→ 데이터 위치, 역할 분리, 의존성 관점에서 두 방식을 비교합니다.
5.1 구조 비교
지금까지 살펴본 내용을 기준으로 기존 방식과 Model/View 방식을 비교해 보겠습니다.
가장 큰 차이는 데이터가 어디에 저장되는가입니다.
| 구분 | 기존 방식 | Model/View 방식 |
| 데이터 위치 | View 내부 | Model 내부 |
| View 역할 | 데이터 저장과 화면 표시를 함께 담당 | 데이터를 화면에 보여주는 역할 담당 |
| Model 역할 | 없거나 약함 | 데이터를 중앙에서 관리함 |
| 데이터 공유 | 어려움 | 쉬움 |
| 화면 추가 | 화면마다 데이터 처리 코드가 중복될 수 있음 | 같은 Model을 바라보는 View만 추가하면 됨 |
| 유지보수 | 화면이 많아질수록 복잡해짐 | 역할이 분리되어 관리하기 쉬움 |
기존 방식에서는 View가 데이터를 직접 가지고 있습니다.
반면 Model/View 방식에서는 데이터를 Model에 두고, View는 그 데이터를 화면에 보여주기만 합니다.
기존 방식
View 1 ←── data
View 2 ←── data
View 3 ←── data
각 View가 데이터를 따로 들고 있음
Model/View 방식
View 1 ←─┐
View 2 ←── Model ←── data
View 3 ←─┘
하나의 Model을 여러 View가 함께 바라봄
5.2 의존성 관점에서 비교
기존 방식은 View와 데이터가 강하게 묶이는 구조입니다.
Model/View 방식은 데이터 관리와 화면 표시를 분리하는 구조입니다.
| 관점 | 기존 방식 | Model/View 방식 |
| 의존성 | View와 데이터가 강하게 묶입니다. | Model과 View의 역할이 분리됩니다. |
| 수정 영향 | 데이터 수정이 화면 코드에 영향을 줄 수 있습니다. | 데이터 수정은 Model 중심으로 관리할 수 있습니다. |
| 확장 | 화면이 늘어나면 데이터 처리 코드도 늘어날 수 있습니다. | 새 View를 추가해도 같은 Model을 사용할 수 있습니다. |
# 기존 방식 (화면과 데이터가 한 곳에 섞여 있음)
View
├── 화면 코드
└── 데이터 코드
# Model/View 방식 (역할이 나누어져 있음)
Model
└── 데이터 관리
View
└── 화면 표시
중요한 점
Model/View 구조의 핵심은 View를 없애는 것이 아닙니다.
View는 화면을 담당하고, Model은 데이터를 담당하도록 역할을 분리하는 것입니다.
5.3 같은 Model, 다른 View
Model/View 구조를 사용하면 같은 데이터를 여러 View에서 다르게 보여줄 수 있습니다.
예를 들어 같은 사용자 데이터를 카드 형태, 리스트 형태, 텍스트 형태로 보여줄 수 있습니다.
같은 Model
↓
CardView
ListView
TextView
데이터는 하나
표시 방식은 여러 개
즉, 데이터는 하나만 관리하고 화면 표현 방식만 여러 개로 나눌 수 있습니다.
기억할 문장
Model/View 구조에서는 데이터는 하나로 관리하더라도, 화면 표현 방식은 여러 개로 보여 줄 수 있습니다.
6. 정리
→ Model/View 구조의 핵심 흐름을 마지막으로 정리합니다.
이번 단계에서는 Model/View 구조의 기본 개념을 살펴보았습니다.
핵심은 데이터를 View 안에 저장하지 않고, Model이라는 구조로 별도 관리하는 것입니다.
기존 방식
↓
View 안에 데이터 저장
↓
데이터 공유와 변경 반영이 어려움
Model/View 방식
↓
Model이 데이터 관리
↓
View가 화면 표시
↓
같은 데이터를 여러 View에서 함께 사용 가능
이번 단계의 핵심 개념을 다시 정리하면 다음과 같습니다.
| 개념 | 정리 |
| Model | 데이터를 저장하고 관리하는 역할입니다. |
| View | Model의 데이터를 화면에 보여주는 역할입니다. |
| 구조 문제 | 데이터가 View 안에 들어가 있으면 여러 View와 공유하기 어렵습니다. |
| 의존성 문제 | View와 데이터가 강하게 묶이면 유지보수가 어려워질 수 있습니다. |
| Model 분리 | 데이터를 View 밖으로 꺼내 Model에서 중앙 관리합니다. |
| View 분리 | View는 데이터를 직접 소유하지 않고 화면 표시 역할에 집중합니다. |
이번 단계의 핵심
Model/View 구조는 데이터를 저장하는 부분과 데이터를 보여주는 화면을 분리하는 구조입니다.
Model은 데이터를 관리하고, View는 화면 표시를 담당합니다.
기억할 문장
데이터는 Model에 두고, 화면 표시는 View가 담당합니다.
참고. 공식 문서로 확인하기
→ 공식 문서에서 Model/View 구조와 관련 클래스를 확인합니다.
1. 공식 문서 참고 표
이번 단계에서 살펴본 Model/View 구조는 Qt for Python 공식 문서에서도 확인할 수 있습니다.
공식 문서에서는 Model/View 아키텍처가 데이터와 데이터를 표현하는 방식을 분리하여 더 유연한 구조를 만들 수 있다고 설명합니다.
| 구분 | 공식 문서 | 확인할 내용 |
| Model/View Programming |
Qt for Python - Model/View Programming | Qt의 Model/View 아키텍처가 데이터와 표현 방식을 분리하는 구조임을 확인할 수 있습니다. |
| QAbstractItemModel | PySide6.QtCore.QAbstractItemModel | Qt의 Model/View 프레임워크에서 기본 Model 역할을 하는 클래스를 확인할 수 있습니다. |
| QListWidget | PySide6.QtWidgets.QListWidget | QListWidget이 항목 기반 리스트 위젯이라는 점을 확인할 수 있습니다. |
| QTextEdit | PySide6.QtWidgets.QTextEdit | QTextEdit이 텍스트를 표시하고 편집하는 위젯이며 내부 문서와 관련된 기능을 가진다는 점을 확인할 수 있습니다. |
2. 이번 예제와 공식 문서 연결
| 이번 글의 내용 | 공식 문서와 연결되는 의미 |
| Model은 데이터 저장소 | Qt의 Model/View 구조에서 Model은 View가 사용할 데이터를 제공하는 역할을 합니다. |
| View는 화면 표시 | View는 Model의 데이터를 사용자에게 보여주는 역할을 합니다. |
| 데이터와 화면 분리 | 데이터 관리와 표시 방식을 분리하면 같은 데이터를 여러 View에서 유연하게 사용할 수 있습니다. |
| QListWidget과 QTextEdit | 편리한 위젯이지만 데이터 공유 구조를 설계하려면 Model/View 관점을 함께 이해해야 합니다. |
3. 정리 흐름도
공식 문서 기준으로 정리하면 다음과 같습니다.
데이터
↓
Model
↓
View
↓
사용자에게 화면으로 표시
즉, 이번 단계는 Model/View 구조에서 데이터와 화면 표시를 분리하는 가장 기본적인 흐름을 이해하는 단계입니다.