QTableWidget 은 엑셀처럼 셀 형태로 데이터를 관리하기 위해 사용하는 위젯입니다. 많은 데이터를 다룰 때 사용하는 위젯으로 평소에 사용법을 알아 두시는 것이 좋습니다. QTableWidget 의 기본 사용법과 데이터 추가/삭제, Checkbox 위젯 추가 등 여러가지 구현 방법들을 알아보겠습니다.
1. 기본 생성
▼ 테이블 위젯은 QtWidgets 패키지의 QTableWidget 클래스를 사용해서 생성합니다. QTableWidget 의 행과 열의 개수는 setRowCount() 와 setColumnCount() 로 지정합니다. 그리고 테이블의 크기는 다른 위젯과 마찬가지로 resize(width, height) 함수로 조절했습니다.
#-*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidget
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 윈도우 설정
self.setGeometry(200, 100, 400, 400) # x, y, w, h
self.setWindowTitle('QTableWidget Sample Window')
# QTableWidget
self.tablewidget = QTableWidget(self)
self.tablewidget.resize(400, 400)
self.tablewidget.setRowCount(3) # 행 개수
self.tablewidget.setColumnCount(3) # 열 개수
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
▼ 코드를 실행한 결과는 다음과 같습니다. 현재는 아무런 데이터도 들어가 있지 않은 빈 상태입니다.
2. 데이터 추가 및 수정하기
▼ 다음은 비어 있는 테이블 위젯의 셀을 채워보겠습니다. 데이터를 입력하기 위해서는 QTableWidget 각 셀에 QTableWidgetItem 객체를 추가해야 합니다. 첫 번째 데이터 입력 방법은 QTableWidgetItem 객체를 생성하면서 생성자의 인수 값으로 텍스트를 넘기는 것입니다. QTableWidgetItem 객체가 들어갈 테이블의 위치는 setItem() 의 첫 번째와 두 번째 행/열 번호로 지정합니다.
from PyQt5.QtWidgets import QTableWidget, QTableWidgetItem
# QTableWidget 에 데이터 추가하기
self.insert_data()
def insert_data(self):
self.tablewidget.setItem(0, 0, QTableWidgetItem("1행 1열"))
self.tablewidget.setItem(0, 1, QTableWidgetItem("1행 2열"))
self.tablewidget.setItem(1, 0, QTableWidgetItem("2행 1열"))
self.tablewidget.setItem(1, 1, QTableWidgetItem("2행 2열"))
▼ 코드를 실행한 결과값은 다음과 같습니다. 행/열로 지정한 번호에 QTableWidgetItem 객체로 셀에 데이터를 채워 넣었습니다.
▼ 두 번째는 QTableWidgetItem 의 setText() 함수를 사용해서 셀에 텍스트를 입력하는 방법입니다. 그 전에 모든 셀에는 setItem() 함수로 QTableWidgetItem() 객체를 추가해야 합니다.
for i in range(0, self.rowcount):
for j in range(0, self.colcount):
self.tablewidget.setItem(i, j, QTableWidgetItem())
self.tablewidget.item(0, 1).setText("1행 2열")
self.tablewidget.item(0, 2).setText("1행 3열")
3. 셀 수정 가능하게 변경
▼ 테이블 내의 셀에 입력된 값을 수정하지 못하게 읽기 모드로 바꾸는 옵션이 setEditTriggers(QAbstractItemView.NoEditTriggers) 입니다. 이것은 기본값입니다. 코드를 실행하지 않아도 기본적으로 읽기 모드입니다.
from PyQt5.QtWidgets import QTableWidget, QAbstractItemView
self.tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
▼ 다시 편집모드로 바꾸고 싶다면 setEditTriggers() 함수의 옵션값을 QAbstractItemView.AllEditTriggers 로 변경해야 합니다. 옵션을 적용한 후 실행해서 셀을 더블클릭 합니다. 셀의 값은 수정 및 삭제 가능한 상태가 되었습니다.
from PyQt5.QtWidgets import QTableWidget, QAbstractItemView
self.tablewidget.setEditTriggers(QAbstractItemView.AllEditTriggers)
4. 테이블 데이터 조회하기
▼ 특정 위치의 셀 값을 조회하는 함수는 QTableWidget.item(row, column) 입니다. 조회하고 싶은 특정 셀의 행과 열 번호를 2개의 인수값으로 입력합니다. QTableWidget.item(row, column) 함수 실행으로 QTableWidgetItem 객체를 반환합니다. 그리고 QTableWidgetItem.text() 함수로 셀 안에 텍스트 값을 반환합니다.
data = self.tablewidget.item(0, 1)
print(data.text())
▼ 다음은 위의 코드를 응용해서 모든 셀 정보를 출력해 보겠습니다. 그러기 위해서는 테이블의 행과 열의 개수를 알아야 합니다. QTableWidget 의 rowCount(), columnCount() 함수를 이용합니다. 행과 열의 개수만큼 이중 반복문을 돌면서 데이터 값을 콘솔에 출력합니다.
# 데이터 조회
rowcount = self.tablewidget.rowCount()
colcount = self.tablewidget.columnCount()
for i in range(0, rowcount):
for j in range(0, colcount):
data = self.tablewidget.item(i, j)
if data is not None:
print(data.text())
else:
print('blank')
▼ 테이블의 모든 데이터를 콘솔에 출력한 결과는 다음과 같습니다.
5. 체크 박스 넣기
▼ QTableWidget 에는 각 셀에 위젯 컨트롤을 삽입할 수 있습니다. 테이블에서 제일 많이 쓰일 만한 체크 박스인 QChcekBox 위젯을 넣어보겠습니다. 함수는 setCellWidget() 을 사용합니다. 첫 번째, 두 번째 인수는 행/열 번호입니다. 세 번째에 QCheckBox 위젯 객체를 입력합니다.
from PyQt5.QtWidgets import QTableWidget, QCheckBox
self.chbox1 = QCheckBox()
self.chbox2 = QCheckBox()
self.tablewidget.setCellWidget(0, 0, self.chbox1)
self.tablewidget.setCellWidget(1, 0, self.chbox2)
▼ 다음은 QCheckBox 의 check 여부를 확인하는 stateChanged 시그널을 연결합니다. 시그널 실행함수에는 체크 박스로부터 전달 받은 state 값을 콘솔에 출력합니다.
# checkbox 시그널 연결
self.chbox1.stateChanged.connect(self.check_state_checkbox1)
self.chbox2.stateChanged.connect(self.check_state_checkbox2)
# check box state 변경 함수
def check_state_checkbox1(self, state):
print('chbox1 : ' + str(state))
def check_state_checkbox2(self, state):
print('chbox2 : ' + str(state))
▼ 실행한 결과는 다음과 같습니다. stateChanged 의 시그널에서 전달받은 state 정수 값은 0 과 2 이므로, 체크 여부를 확인할 수 있습니다.
6. 내림차순, 오름차순 정렬하기
▼ 테이블 위젯의 헤더 부분을 클릭하면 해당 열의 값을 분석해서 오름차순/내림차순으로 정렬하는 기능이 있습니다. QTableWiget 의 함수 setSortingEnabled() 를 이용해서 사용 유무를 세팅합니다. 기본값은 False 이며, True 로 넘기면 열 정렬이 가능합니다. 현재 QTableWiget 의 Sorting 가능 여부는 isSortingEnabled() 로 판단합니다.
# Sorting 가능한지 여부를 판단한다.
if not self.tablewidget.isSortingEnabled():
self.tablewidget.setSortingEnabled(True)
▼ setSortingEnabled() 함수로 설정을 변겨앟고 상단 레이블 영역을 클릭해 보세요. 오름차순, 내림차순 순으로 행이 나열됩니다.
7. 열 사이즈 수정하기
▼ 열 사이즈를 수정하는 방법은 여러가지가 있습니다. 여기서 소개할 방법은 두 가지입니다. 컨텐츠 크기에 맞게 자동으로 수정되도록 설정하거나 직접 크기를 입력해서 조절하는 방법입니다. 컨텐츠 크기에 맞게 자동 수정 함수는 QTableWidget 의 resizeColumnToContents() 와 resizeRowToContents() 로 행과 열을 나누어서 설정합니다. 함수의 파라미터로 행/열 번호를 입력합니다.
# 자동으로 수정하기
self.tablewidget.resizeColumnToContents(1)
self.tablewidget.resizeRowToContents(1)
▼ 다음은 사이즈를 직접 조절하는 방법입니다. QTableWidget 의 horizontalHeader() 함수로 QHeaderView 객체를 리턴받아 resizeSection() 함수로 조절합니다. 함수의 첫 번째 인수는 열 번호이며, 두 번째가 열 사이즈입니다.
from PyQt5.QtWidgets import QHeaderView
# 사이즈로 수정하기
header = self.tablewidget.horizontalHeader()
header.resizeSection(0, 10)
8. 데이터 정렬하기
▼ QTableWidget 의 셀 내부에 데이터를 정렬하는 함수는 QTableWidgetItem 의 setTextAlignment() 함수입니다. 인수로 들어갈 플래그는 셀에서의 위치를 나타내는 값입니다.
self.tablewidget.item(0, 2).setTextAlignment(Qt.AlignVCenter | Qt.AlignRight)
self.tablewidget.item(1, 2).setTextAlignment(Qt.AlignVCenter | Qt.AlignLeft)
▼ 플래그 종류는 다음과 같습니다. 가로와 세로로 구분되어 있습니다. 두 플래그를 조합해서 데이터를 정렬합니다.
▼ 결과는 다음과 같습니다. 해당 셀의 위치는 오른쪽과 왼쪽으로 배치가 되었습니다.
9. 이벤트 시그널 구현하기
▼ 다음은 QTableWidget 제공하는 시그널을 이용해서 함수를 구현해 보겠습니다. 자주 사용하는 시그널의 종류는 아래와 같습니다.
- cellChanged : Cell의 내용이 바뀌었을 때 이벤트 발생
- currentCellChanged : 선택된 Cell 이 바뀌었을 때 이벤트 발생
- cellClicked : Cell 이 클릭 되었을 때 이벤트 발생
▼ 셀의 값이 변경되었을 때 발생하는 cellChanged 시그널에 cellchanged_event() 함수를 연결했습니다. 시그널로부터 행과 열 번호를 넘겨 받습니다. 함수는 이벤트가 발생한 셀에 들어가 있는 값을 읽어와서 콘솔에 출력합니다.
# 테이블 이벤트 지정
self.tablewidget.cellChanged.connect(self.cellchanged_event)
# 셀의 내용이 바뀌었을 때 이벤트
def cellchanged_event(self, row, col):
data = self.tablewidget.item(row, col)
print("cellchanged_event 발생 : ", data.text())
▼ 다음은 셀의 포커스가 바뀌었을 때 발생하는 currentCellChanged 시그널을 구현했습니다. 시그널로부터 전달받은 값은 현재 행/열 번호와 이전 포커스가 있던 행/열 번호를 받을 수 있습니다. 시그널에 연결된 함수에서는 전달받은 행/열 번호에 해당하는 셀 값을 콘솔에 출력합니다.
self.tablewidget.currentCellChanged.connect(self.currentcellchanged_event)
# 선택한 셀이 바뀌면 발생하는 이벤트
def currentcellchanged_event(self, row, col, pre_row, pre_col):
current_data = self.tablewidget.item(row, col) # 현재 선택 셀 값
pre_data = self.tablewidget.item(pre_row, pre_col) # 이전 선택 셀 값
if pre_data is not None:
print("이전 선택 셀 값 : ", pre_data.text())
else:
print("이전 선택 셀 값 : 없음")
print("현재 선택 셀 값 : ", current_data.text())
▼ 다음은 셀 클릭과 더블클릭 시그널인 cellClicked 와 cellDoubleClicked 을 구현한 내용입니다. 두 시그널 모두 행과 열 번호를 넘겨받을 수 있습니다. 행과 열 번호를 이용해서 셀 값을 가져와서 콘솔에 출력합니다.
# 테이블 이벤트 지정
self.tablewidget.cellClicked.connect(self.cellclicked_event)
self.tablewidget.cellDoubleClicked.connect(self.celldoubleclicked_event)
# 셀 더블클릭 때 발생하는 이벤트
def celldoubleclicked_event(self, row, col):
data = self.tablewidget.item(row, col)
print("셀 더블클릭 셀 값 : ", data.text())
# 셀 선택할 때 발생하는 이벤트
def cellclicked_event(self, row, col):
data = self.tablewidget.item(row, col)
print("셀 클릭 셀 값 : ", data.text())
▼ 지금까지 구현한 모든 내용이 들어가 있는 전체 소스는 아래와 같습니다.
#-*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import QMainWindow, QApplication, QTableWidget, \
QTableWidgetItem, QAbstractItemView, QTextEdit, QPushButton
from PyQt5.Qt import Qt
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
# 윈도우 설정
self.setGeometry(200, 100, 400, 400) # x, y, w, h
self.setWindowTitle('QTableWidget Sample Window')
# QTableWidget
self.tablewidget = QTableWidget(self)
self.tablewidget.resize(400, 200)
self.tablewidget.setRowCount(3) # 행 개수
self.tablewidget.setColumnCount(3) # 열 개수
self.tablewidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.edit = QTextEdit(self)
self.edit.move(10, 210)
self.btn = QPushButton(self)
self.btn.setText('0, 0 셀 입력')
self.btn.move(120, 210)
# QTableWidget 에 데이터 추가하기
self.insert_data()
# 수정 가능한 필드
# self.tablewidget.setEditTriggers(QAbstractItemView.AllEditTriggers)
# 데이터 조회
rowcount = self.tablewidget.rowCount()
colcount = self.tablewidget.columnCount()
for i in range(0, rowcount):
for j in range(0, colcount):
data = self.tablewidget.item(i, j)
if data is not None:
print(data.text())
else:
print('blank')
# self.tablewidget.item(0, 0).setText('1111')
# 테이블 이벤트 지정
self.tablewidget.cellChanged.connect(self.cellchanged_event)
self.tablewidget.currentCellChanged.connect(self.currentcellchanged_event)
self.tablewidget.cellClicked.connect(self.cellclicked_event)
self.tablewidget.cellDoubleClicked.connect(self.celldoubleclicked_event)
# 셀 더블클릭 때 발생하는 이벤트
def celldoubleclicked_event(self, row, col):
data = self.tablewidget.item(row, col)
print("셀 더블클릭 셀 값 : ", data.text())
# 셀 선택할 때 발생하는 이벤트
def cellclicked_event(self, row, col):
data = self.tablewidget.item(row, col)
print("셀 클릭 셀 값 : ", data.text())
# 선택한 셀이 바뀌면 발생하는 이벤트
def currentcellchanged_event(self, row, col, pre_row, pre_col):
current_data = self.tablewidget.item(row, col) # 현재 선택 셀 값
pre_data = self.tablewidget.item(pre_row, pre_col) # 이전 선택 셀 값
if pre_data is not None:
print("이전 선택 셀 값 : ", pre_data.text())
else:
print("이전 선택 셀 값 : 없음")
print("현재 선택 셀 값 : ", current_data.text())
# 셀의 내용이 바뀌었을 때 이벤트
def cellchanged_event(self, row, col):
data = self.tablewidget.item(row, col)
print("cellchanged_event 발생 : ", data.text())
def insert_data(self):
self.tablewidget.setItem(0, 0, QTableWidgetItem("1행 1열"))
self.tablewidget.setItem(0, 1, QTableWidgetItem("1행 2열"))
self.tablewidget.setItem(1, 0, QTableWidgetItem("2행 1열"))
self.tablewidget.setItem(1, 1, QTableWidgetItem("2행 2열"))
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())