PyQt5

PyQt5 -- QTableWidget 사용 고급 예제 ; checkbox 넣기, 숫자나 widget으로 정렬, checked row 구하기

자유프로그램 2017. 7. 18. 00:21
반응형

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_()




반응형