PyQt는 Python 언어로 Qt 애플리케이션을 개발할 수 있도록 해주는 강력한 GUI 툴킷입니다. 그 중에서도 데이터 모델을 관리하는 데 매우 유용한 클래스가 QAbstractTableModel
과 QAbstractListModel
입니다. 이들 클래스를 사용하여 커스텀 데이터 모델을 생성함으로써, PyQt에서 복잡한 데이터 구조를 쉽게 표현하고 조작할 수 있습니다. 본 강좌에서는 QAbstractTableModel
과 QAbstractListModel
을 사용하여 커스텀 모델을 만드는 방법을 자세히 알아보겠습니다.
QAbstractTableModel 개요
QAbstractTableModel
은 2차원 데이터 구조를 위한 모델 클래스로, 표 형태의 데이터를 관리하는 데 사용됩니다. 이는 Qt의 MVC (Model-View-Controller) 아키텍처에 따라 데이터와 표시를 분리하는 데 유용합니다. QAbstractTableModel
을 상속하여 새로운 모델을 생성하면, 데이터를 쉽고 효율적으로 표시할 수 있습니다.
QAbstractTableModel의 주요 메소드
rowCount(self, parent=QModelIndex())
: 모델의 행 수를 반환합니다.columnCount(self, parent=QModelIndex())
: 모델의 열 수를 반환합니다.data(self, index: QModelIndex, role=int)
: 특정 인덱스에 해당하는 데이터를 반환합니다.setData(self, index: QModelIndex, value, role=int)
: 특정 인덱스의 데이터를 설정합니다.headerData(self, section, orientation, role=int)
: 헤더 데이터를 반환합니다.flags(self, index: QModelIndex)
: 특정 인덱스의 플래그를 반환합니다.
QAbstractListModel 개요
QAbstractListModel
은 1차원 데이터 구조를 위한 모델 클래스입니다. 리스트 형태의 데이터를 관리하는 데 이상적입니다. 사용자 인터페이스에서 리스트 데이터를 표시해야 할 경우, 이 클래스를 사용하여 커스텀 모델을 쉽게 구현할 수 있습니다.
QAbstractListModel의 주요 메소드
rowCount(self, parent=QModelIndex())
: 모델의 아이템 수를 반환합니다.data(self, index: QModelIndex, role=int)
: 특정 인덱스에 해당하는 데이터를 반환합니다.setData(self, index: QModelIndex, value, role=int)
: 특정 인덱스의 데이터를 설정합니다.flags(self, index: QModelIndex)
: 특정 인덱스의 플래그를 반환합니다.
커스텀 모델 만들기
이제 QAbstractTableModel
와 QAbstractListModel
을 이용해 커스텀 모델을 만드는 예제를 살펴보겠습니다. 먼저 QAbstractTableModel
을 상속한 커스텀 모델을 만들어 보겠습니다.
지속 가능한 데이터 모델 생성: MyTableModel
import sys
from PyQt5.QtCore import QAbstractTableModel, QModelIndex, Qt
from PyQt5.QtWidgets import QApplication, QTableView, QVBoxLayout, QWidget, QPushButton
class MyTableModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data # 데이터를 저장하는 리스트
def rowCount(self, parent=QModelIndex()):
return len(self._data) # 행 수 반환
def columnCount(self, parent=QModelIndex()):
return len(self._data[0]) if self._data else 0 # 열 수 반환
def data(self, index: QModelIndex, role=int):
if role == Qt.DisplayRole:
return self._data[index.row()][index.column()] # 데이터 반환
return None
def setData(self, index: QModelIndex, value, role=int):
if role == Qt.EditRole:
self._data[index.row()][index.column()] = value # 데이터 설정
self.dataChanged.emit(index, index) # 데이터 변경 알림
return True
return False
def headerData(self, section, orientation, role=int):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return f'Column {section + 1}' # 헤더 데이터 반환
else:
return f'Row {section + 1}'
return None
class MyTableView(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My Table Model")
self.resize(500, 300)
layout = QVBoxLayout(self)
self.model = MyTableModel([['Data 1', 'Data 2'], ['Data 3', 'Data 4']])
self.table_view = QTableView(self)
self.table_view.setModel(self.model)
layout.addWidget(self.table_view)
# 수정 버튼
self.button = QPushButton("Edit Cell", self)
self.button.clicked.connect(self.edit_cell)
layout.addWidget(self.button)
def edit_cell(self):
# (0, 0) 위치의 데이터를 변경
self.model.setData(self.model.index(0, 0), "New Data", Qt.EditRole)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyTableView()
window.show()
sys.exit(app.exec_())
위의 예제는 QAbstractTableModel
을 상속받은 MyTableModel
클래스를 정의하고, 초기 데이터 리스트를 전달받아 모델을 생성합니다. 사용자 인터페이스에서 이 모델을 사용하여 데이터를 표시합니다. setData
메소드를 통해 셀 데이터를 수정할 수 있습니다.
리스트형 데이터 모델 생성: MyListModel
이번에는 QAbstractListModel
을 상속받는 커스텀 모델을 만들어 보겠습니다.
from PyQt5.QtCore import QAbstractListModel, Qt
from PyQt5.QtWidgets import QApplication, QListView, QVBoxLayout, QWidget, QPushButton
class MyListModel(QAbstractListModel):
def __init__(self, items):
super().__init__()
self._items = items # 리스트 항목 저장
def rowCount(self, parent=QModelIndex()):
return len(self._items) # 아이템 수 반환
def data(self, index: QModelIndex, role=int):
if role == Qt.DisplayRole:
return self._items[index.row()] # 데이터 반환
return None
def setData(self, index: QModelIndex, value, role=int):
if role == Qt.EditRole:
self._items[index.row()] = value # 데이터 설정
self.dataChanged.emit(index, index) # 데이터 변경 알림
return True
return False
def flags(self, index: QModelIndex):
return Qt.ItemIsEditable # 편집 가능 플래그 설정
class MyListView(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("My List Model")
self.resize(300, 400)
layout = QVBoxLayout(self)
self.model = MyListModel(['Item 1', 'Item 2', 'Item 3'])
self.list_view = QListView(self)
self.list_view.setModel(self.model)
layout.addWidget(self.list_view)
# 수정 버튼
self.button = QPushButton("Edit First Item", self)
self.button.clicked.connect(self.edit_item)
layout.addWidget(self.button)
def edit_item(self):
# 첫 번째 아이템 변경
self.model.setData(self.model.index(0), "New Item 1", Qt.EditRole)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyListView()
window.show()
sys.exit(app.exec_())
이 예제는 QAbstractListModel
을 상속받은 MyListModel
클래스를 정의합니다. 리스트 항목을 처리하고, 사용자가 리스트 아이템을 수정할 수 있는 기능을 제공합니다.
데이터 모델과 사용자 인터페이스 연동
모델과 뷰를 연동하는 것은 PyQt에서 매우 중요합니다. 사용자에게 데이터를 표시할 뿐만 아니라, 데이터를 편집하고 업데이트하는 일련의 작업을 모델과 뷰 간의 원활한 통신을 통해 수행합니다. 이 과정에서 데이터를 변경할 때마다 dataChanged
신호를 발송하여 뷰에 변경 사항을 알려주어야 합니다. 이는 모델이 데이터의 변화를 감지하고 사용자 인터페이스가 최신 상태를 유지하도록 돕습니다.
결론
본 강좌에서는 QAbstractTableModel
과 QAbstractListModel
을 사용하여 커스텀 데이터 모델을 만드는 방법을 배웠습니다. 데이터 모델과 뷰간의 상호작용을 이해하고 이를 통해 복잡한 데이터를 관리하는 방법을 익히는 것은 PyQt 애플리케이션 개발에서 매우 중요한 부분입니다. 이 강좌에서 배운 내용을 바탕으로 여러분은 더 복잡하고 다양한 데이터를 처리하는 모델을 구현할 수 있을 것입니다.
이제 여러분이 커스텀 모델을 만들 능력을 갖추었으니, 다양한 응용 프로그램에서 이 지식을 활용하시기 바랍니다. Happy coding!