본문으로 바로가기
반응형

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_())
반응형