PyQt5 -- QTableWidget 사용 고급 예제 ; checkbox 넣기, 숫자나 widget으로 정렬, checked row 구하기
PyQt5 -- QTableWidget 사용 고급 예제
; checkbox 넣기, 숫자나 widget으로 정렬, checked row 구하기
; checked 여부로 정렬하기
(자동정렬이 아니라, 컬럼 헤더 click시에만 정렬하기...)
** 기본적으로 QTableWidget 의 QTableWidgetItem 항목은 '문자'로 설정되며, 문자 기준으로 정렬하게 된다.
--> 따라서, 아래와 같이 '문자' 기준인 컬럼을 정렬시에는 , 예상과 전혀 다른 정렬이 된다.
--> 이를 해결하기위해, QTableWidgetItem 을 만들때 setData() 메소드 이용하여 '숫자'를 넣어줘야한다.
** 체크 표시된 항목들만 보기위해서는 , CheckBox 만 따로 widget 으로 넣고, 정렬기능도 정해야한다.
--> 정렬기능을 사용자 정의로 사용하기위해서는, QTableWidgetItem 을 상속받아 __lt__( ) 메소드를 직접 구현하면 된다.
--> 이후 widget 이 들어간 cell 에, QTableWidgetItem 항목되 같이 넣으면 됨.
--> 물론, 같은 cell 에 넣고, 서로를 signal & slot 으로 연결하여 정렬을 위한 data 주고 받아야 됨.
--> 이렇게 하면, widget 으로 정렬하는 효과 만들수있다.
** MyFrame 클래스의 __checkbox_change(self, checkvalue) 메소드는 실제는 필요없는 중복되는 메소드임.
--> 단지, signal sender 를 사용하는 예를 보기위함.
---
from PyQt5.QtCore import pyqtSlot, Qt | |
from PyQt5.QtWidgets import * | |
from PyQt5.QtGui import * | |
import time | |
class MyFrame(QWidget): | |
def __init__(self): | |
super().__init__() | |
self.table = QTableWidget(5, 5, self) # row, column | |
self.table.setHorizontalHeaderLabels(["", "종목명", "현재가(문자)", "현재가(숫자)", "거래량"]) | |
data = [ | |
("삼성전자", "200000", 200000, "25000"), | |
("셀트리온", "2100", 2100, "1500"), | |
("현대차", "190000", 190000, "300000"), | |
("기아차", "150000", 150000, "240000") | |
] | |
for idx, (hname, price_str, price, vol) in enumerate(data): | |
# 사용자정의 item 과 checkbox widget 을, 동일한 cell 에 넣어서 , 추후 정렬 가능하게 한다. | |
item = MyQTableWidgetItemCheckBox() | |
self.table.setItem(idx, 0, item) | |
chbox = MyCheckBox(item) | |
# print(chbox.sizeHint()) | |
self.table.setCellWidget(idx, 0, chbox) | |
chbox.stateChanged.connect(self.__checkbox_change) # sender() 확인용 예.. | |
self.table.setItem(idx, 1, QTableWidgetItem(hname)) | |
self.table.setItem(idx, 2, QTableWidgetItem(price_str)) | |
# 숫자를 기준으로 정렬하기 위함. -- default 는 '문자'임. | |
item = QTableWidgetItem() | |
item.setData(Qt.DisplayRole, price) | |
self.table.setItem(idx, 3, item) | |
self.table.setItem(idx, 4, QTableWidgetItem(vol)) | |
self.table.setSortingEnabled(False) # 정렬기능 | |
self.table.resizeRowsToContents() | |
self.table.resizeColumnsToContents() # 이것만으로는 checkbox 컬럼은 잘 조절안됨. | |
self.table.setColumnWidth(0, 15) # checkbox 컬럼 폭 강제 조절. | |
self.table.cellClicked.connect(self._cellclicked) | |
# 컬럼 헤더를 click 시에만 정렬하기. | |
hheader = self.table.horizontalHeader() # qtablewidget --> qtableview --> horizontalHeader() --> QHeaderView | |
hheader.sectionClicked.connect(self._horizontal_header_clicked) | |
vbox = QVBoxLayout(self) | |
vbox.addWidget(self.table) | |
self.setLayout(vbox) | |
def __checkbox_change(self, checkvalue): | |
# print("check change... ", checkvalue) | |
chbox = self.sender() # signal을 보낸 MyCheckBox instance | |
print("checkbox sender row = ", chbox.get_row()) | |
def _cellclicked(self, row, col): | |
print("_cellclicked... ", row, col) | |
def _horizontal_header_clicked(self, idx): | |
""" | |
컬럼 헤더 click 시에만, 정렬하고, 다시 정렬기능 off 시킴 | |
-- 정렬기능 on 시켜놓으면, 값 바뀌면 바로 자동으로 data 순서 정렬되어 바뀌어 헷갈린다.. | |
:param idx --> horizontalheader index; 0, 1, 2,... | |
:return: | |
""" | |
# print("hedder2.. ", idx) | |
self.table.setSortingEnabled(True) # 정렬기능 on | |
# time.sleep(0.2) | |
self.table.setSortingEnabled(False) # 정렬기능 off | |
class MyCheckBox(QCheckBox): | |
def __init__(self, item): | |
""" | |
:param item: QTableWidgetItem instance | |
""" | |
super().__init__() | |
self.item = item | |
self.mycheckvalue = 0 # 0 --> unchecked, 2 --> checked | |
self.stateChanged.connect(self.__checkbox_change) | |
self.stateChanged.connect(self.item.my_setdata) # checked 여부로 정렬을 하기위한 data 저장 | |
def __checkbox_change(self, checkvalue): | |
# print("myclass...check change... ", checkvalue) | |
self.mycheckvalue = checkvalue | |
print("checkbox row= ", self.get_row()) | |
def get_row(self): | |
return self.item.row() | |
class MyQTableWidgetItemCheckBox(QTableWidgetItem): | |
""" | |
checkbox widget 과 같은 cell 에 item 으로 들어감. | |
checkbox 값 변화에 따라, 사용자정의 data를 기준으로 정렬 기능 구현함. | |
""" | |
def __init__(self): | |
super().__init__() | |
self.setData(Qt.UserRole, 0) | |
def __lt__(self, other): | |
# print(type(self.data(Qt.UserRole))) | |
return self.data(Qt.UserRole) < other.data(Qt.UserRole) | |
def my_setdata(self, value): | |
# print("my setdata ", value) | |
self.setData(Qt.UserRole, value) | |
# print("row ", self.row()) | |
if __name__ == '__main__': | |
import sys | |
app = QApplication(sys.argv) | |
frame = MyFrame() | |
frame.setWindowTitle("정렬하기") | |
frame.resize(600, 400) # width, height | |
frame.show() | |
app.exec_() |