PyQt는 파이썬을 위한 Qt 애플리케이션 개발 프레임워크로, GUI를 신속하게 개발할 수 있게 해줍니다. 본 강좌에서는 PyQt를 사용하여 데이터를 관리하고 표시하기 위한 커스텀 필터와 정렬 기능을 어떻게 구현할 수 있는지에 대해 자세히 다룰 것입니다. 특히, QTableView
와 QAbstractTableModel
을 활용하여 데이터의 표시, 필터링 및 정렬을 구현하는 방법에 대해 알아볼 것입니다.
1. 기본 개념
PyQt를 활용한 GUI 애플리케이션에서 데이터 관리는 매우 중요합니다. 사용자가 데이터를 쉽게 볼 수 있도록 구현하는 것뿐만 아니라, 데이터를 필터링하고 정렬할 수 있는 강력한 도구를 제공해야 합니다. 이를 위해 다음과 같은 주요 구성 요소를 사용합니다:
QTableView
: 데이터를 테이블 형태로 표시하기 위한 위젯입니다.QAbstractTableModel
: 데이터의 내부 구조를 정의하며, 데이터를 표시하는 방법과 필터링 및 정렬을 관리합니다.- 커스텀 필터 및 정렬 기능: 사용자가 원하는 대로 데이터를 필터링하고 정렬할 수 있게 해주는 기능입니다.
2. QTableView와 QAbstractTableModel 소개
QTableView
는 데이터를 테이블 형식으로 표시하는 데 사용됩니다. 데이터에 대한 다양한 조작과 표시 설정이 가능합니다. QAbstractTableModel
은 데이터를 모델로 관리하는 클래스로, QTableView
와 함께 사용되어야 합니다. 모델은 데이터가 어떻게 저장되고 쿼리되는지를 정의합니다.
2.1 QTableView 설정하기
먼저 간단한 PyQt 애플리케이션을 설정하고 QTableView
를 사용하는 방법을 살펴보겠습니다. 아래의 코드를 확인하십시오:
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QTableView
from PyQt5.QtCore import Qt, QAbstractTableModel, QVariant
class MyModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
def rowCount(self, parent=None):
return len(self._data)
def columnCount(self, parent=None):
return len(self._data[0]) if self._data else 0
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
return QVariant(self._data[index.row()][index.column()])
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return QVariant(f'Column {section + 1}')
else:
return QVariant(f'Row {section + 1}')
if __name__ == "__main__":
app = QApplication(sys.argv)
window = QMainWindow()
window.setWindowTitle('QTableView 예제')
data = [
['Alice', 30],
['Bob', 25],
['Charlie', 35]
]
model = MyModel(data)
table_view = QTableView()
table_view.setModel(model)
layout = QVBoxLayout()
layout.addWidget(table_view)
central_widget = QWidget()
central_widget.setLayout(layout)
window.setCentralWidget(central_widget)
window.resize(400, 300)
window.show()
sys.exit(app.exec_())
이 코드에서는 가장 간단한 형태의 QTableView
와 QAbstractTableModel
을 설정했습니다. MyModel
클래스를 생성하여 데이터를 보유하고, 데이터의 행과 열 개수를 정의하며, 특정 셀의 데이터를 반환하는 간단한 모델을 구현했습니다.
3. 커스텀 필터 만들기
이제 데이터를 필터링할 수 있는 기능을 추가해보겠습니다. 이를 위해 모델에 필터링 기능을 추가하고, QLineEdit
를 사용하여 사용자 입력을 받을 수 있도록 할 것입니다.
3.1 필터 기능 구현
필터 기능을 구현하기 위해 모델 클래스에 필터링 로직을 추가하겠습니다. 사용자가 입력한 필터 문자열 기반으로 데이터를 필터링할 수 있도록 합니다.
class MyModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
self._filtered_data = data
def filterData(self, filter_string):
self.beginResetModel()
if filter_string:
self._filtered_data = [row for row in self._data if filter_string.lower() in row[0].lower()]
else:
self._filtered_data = self._data
self.endResetModel()
def rowCount(self, parent=None):
return len(self._filtered_data)
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
return QVariant(self._filtered_data[index.row()][index.column()])
여기에서 filterData
메서드는 입력된 필터 문자열을 기반으로 데이터를 필터링합니다. beginResetModel
과 endResetModel
메서드를 사용하여 모델의 데이터가 변경되었음을 알립니다.
3.2 QLineEdit 추가하기
이제 필터를 입력할 QLineEdit
를 사용자 인터페이스에 추가하고, 사용자 입력에 따라 필터를 적용할 것입니다.
from PyQt5.QtWidgets import QLineEdit
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTableView 필터링 예제')
self.data = [
['Alice', 30],
['Bob', 25],
['Charlie', 35]
]
self.model = MyModel(self.data)
self.table_view = QTableView()
self.table_view.setModel(self.model)
self.filter_line_edit = QLineEdit()
self.filter_line_edit.setPlaceholderText('이름으로 필터링...')
self.filter_line_edit.textChanged.connect(self.onFilterChanged)
layout = QVBoxLayout()
layout.addWidget(self.filter_line_edit)
layout.addWidget(self.table_view)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def onFilterChanged(self, text):
self.model.filterData(text)
이 코드에서는 QLineEdit
를 추가하고, 사용자가 입력하는 텍스트가 변경될 때마다 onFilterChanged
메서드를 호출하여 모델에 필터를 적용합니다.
4. 데이터 정렬 기능 구현하기
다음으로 데이터를 정렬할 수 있는 기능을 추가해보겠습니다. 사용자가 특정 열을 클릭하면 해당 열의 데이터를 정렬할 수 있도록 합니다.
4.1 정렬 기능을 위한 모델 수정
모델에 정렬 기능을 추가하기 위해 별도의 정렬 메서드를 작성하겠습니다. 이 메서드는 지정된 열을 기준으로 데이터를 오름차순 또는 내림차순으로 정렬합니다.
class MyModel(QAbstractTableModel):
# 기존 코드...
def sort(self, column, order):
self.beginResetModel()
self._filtered_data.sort(key=lambda x: x[column], reverse=(order == Qt.DescendingOrder))
self.endResetModel()
4.2 QTableView에서 정렬 처리하기
이제 QTableView
에서 열 헤더 클릭 시 정렬을 처리할 수 있도록 설정합니다.
self.table_view.setSortingEnabled(True)
self.table_view.horizontalHeader().sectionClicked.connect(self.onHeaderClicked)
def onHeaderClicked(self, index):
current_order = self.table_view.horizontalHeader().sortIndicatorOrder()
new_order = Qt.AscendingOrder if current_order == Qt.DescendingOrder else Qt.DescendingOrder
self.model.sort(index, new_order)
이 코드는 사용자가 열 헤더를 클릭할 때마다 onHeaderClicked
메서드를 호출하여 정렬을 수행합니다.
5. 전체 코드
이제 모든 구성 요소를 통합한 전체 코드를 볼 수 있습니다.
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QTableView, QLineEdit
from PyQt5.QtCore import Qt, QAbstractTableModel, QVariant
class MyModel(QAbstractTableModel):
def __init__(self, data):
super().__init__()
self._data = data
self._filtered_data = data
def filterData(self, filter_string):
self.beginResetModel()
if filter_string:
self._filtered_data = [row for row in self._data if filter_string.lower() in row[0].lower()]
else:
self._filtered_data = self._data
self.endResetModel()
def sort(self, column, order):
self.beginResetModel()
self._filtered_data.sort(key=lambda x: x[column], reverse=(order == Qt.DescendingOrder))
self.endResetModel()
def rowCount(self, parent=None):
return len(self._filtered_data)
def columnCount(self, parent=None):
return len(self._filtered_data[0]) if self._filtered_data else 0
def data(self, index, role=Qt.DisplayRole):
if role == Qt.DisplayRole:
return QVariant(self._filtered_data[index.row()][index.column()])
def headerData(self, section, orientation, role):
if role == Qt.DisplayRole:
if orientation == Qt.Horizontal:
return QVariant(f'Column {section + 1}')
else:
return QVariant(f'Row {section + 1}')
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle('QTableView 필터링 및 정렬 예제')
self.data = [
['Alice', 30],
['Bob', 25],
['Charlie', 35]
]
self.model = MyModel(self.data)
self.table_view = QTableView()
self.table_view.setModel(self.model)
self.table_view.setSortingEnabled(True)
self.table_view.horizontalHeader().sectionClicked.connect(self.onHeaderClicked)
self.filter_line_edit = QLineEdit()
self.filter_line_edit.setPlaceholderText('이름으로 필터링...')
self.filter_line_edit.textChanged.connect(self.onFilterChanged)
layout = QVBoxLayout()
layout.addWidget(self.filter_line_edit)
layout.addWidget(self.table_view)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def onFilterChanged(self, text):
self.model.filterData(text)
def onHeaderClicked(self, index):
current_order = self.table_view.horizontalHeader().sortIndicatorOrder()
new_order = Qt.AscendingOrder if current_order == Qt.DescendingOrder else Qt.DescendingOrder
self.model.sort(index, new_order)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = MainWindow()
window.resize(400, 300)
window.show()
sys.exit(app.exec_())
6. 마무리
본 강좌에서는 PyQt를 사용하여 커스텀 필터와 정렬 기능을 포함한 데이터 테이블을 구현하는 방법에 대해 설명하였습니다. QTableView
와 QAbstractTableModel
을 활용하여 유연하고 강력한 데이터 관리를 할 수 있습니다. 이 예제를 기반으로 다양한 기능을 추가하고 지속적으로 발전시켜 나가길 바랍니다.
앞으로도 PyQt에 대한 다양한 강좌를 연구하고, 기술을 확장해 나가기를 바랍니다. 질문이나 코멘트가 있다면 언제든지 남겨주세요!