개발/Qt
[PyQt] 트리 뷰(QTreeView)에 콤보박스(QComboBox) 추가하기
LifeCoding
2021. 11. 3. 11:15
트리뷰에 콤보박스를 추가해서 옵션을 선택하도록 하는 방법입니다.
- 일부 아이템에만 우측에 콤보박스 추가
- 버튼을 누르면 현재 선택된 아이템의 정보를 보여줌
결과 화면 :
설명 :
- 파일에서 데이터를 읽어와 treeView에 아이템을 추가합니다.(한 row에 아이템 2개씩 추가)
- 콤보박스가 없는 row : [정보가 있는 item, 빈 item] 두개 추가
- 콤보박스가 있는 row : [정보가 있는 item, 콤보박스의 초기값을 가지는 item] 두개 추가
- 콤보 박스를 추가 하고 싶은 아이템을 구분하기 위해, 데이터 파일에서 #count가 있으면 콤보 박스를 생성하게 했습니다.(콤보박스 초기값이 count)
- ComboBox를 보여줄 수 있는 Delegate를 만듭니다.
- column 1에 위의 combo box용 delegate를 설정해 줍니다.
self.treeView.setItemDelegateForColumn(1, ComboDelegate(self, ["count", "1", "2", "3"]))
전체 소스 코드 :
TreeView.py
from PyQt5.QtWidgets import QDialog, QTreeView, QStyledItemDelegate, QComboBox, QWidget, QApplication, \
QStyleOptionComboBox, QVBoxLayout, QPushButton, QLabel, QItemDelegate, QStyle
from PyQt5.QtGui import QStandardItem, QStandardItemModel
from PyQt5.QtCore import Qt, QVariant
class TreeViewDialog(QDialog):
def __init__(self):
QDialog.__init__(self)
self.treeView = QTreeView(self)
self.model = TreeModel()
self.treeView.setModel(self.model)
self.treeView.setHeaderHidden(True)
self.treeView.setItemDelegateForColumn(1, ComboDelegate(self, ["count", "1", "2", "3"]))
self.treeView.setCurrentIndex(self.model.index(0, 0))
self.treeView.setColumnWidth(0, 300)
self.treeView.expandAll()
self.treeView.clicked.connect(self.treeViewClicked)
self.button = QPushButton(self)
self.button.setText("Show selected item")
self.button.clicked.connect(self.onButtonClicked)
self.label = QLabel(self)
self.label.setText("...")
vBox = QVBoxLayout(self)
vBox.addWidget(self.treeView)
vBox.addWidget(self.button)
vBox.addWidget(self.label)
self.setLayout(vBox)
self.resize(500, 300)
def onButtonClicked(self):
indexes = self.treeView.selectedIndexes()
txt = ''
for index in indexes:
txt += '{},'.format(index.data())
self.label.setText(txt)
def treeViewClicked(self, index):
if not index.isValid():
return
print('row {}, col {}'.format(index.row(), index.column()))
class TreeModel(QStandardItemModel):
def __init__(self):
super(TreeModel, self).__init__()
self.readData()
def readData(self):
rootParentItem = self.invisibleRootItem()
roots = set()
item = None
with open('data.txt', 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines:
line = line.strip()
subs = line.split(">")
category = subs[0]
if category not in roots:
item = self.appendChild(category, rootParentItem, category)
roots.add(category)
if len(subs) > 1:
name = subs[1]
self.appendChild(name, item, name)
def appendChild(self, title, parentItem, toolTip = None):
item2 = None
if '#count' in title:
item2 = TreeItem('count', "")
title = title.replace("#count", "")
else:
item2 = TreeItem('', '')
item2.setEditable(False)
item = TreeItem(title, toolTip)
item.setData(title)
item.setEditable(False)
parentItem.appendRow([item, item2])
return item
class TreeItem(QStandardItem):
def __init__(self, text, toolTip):
QStandardItem.__init__(self)
self.setText(text)
self.setToolTip(toolTip)
class ComboDelegate(QStyledItemDelegate):
def __init__(self, owner, items):
super(ComboDelegate, self).__init__(owner)
self.items = items
def createEditor(self, parent, option, index):
self.editor = QComboBox(parent)
self.editor.addItems(self.items)
return self.editor
def paint(self, painter, option, index):
if index.data(Qt.DisplayRole) == '': # 빈 아이템이면 콤보박스 안보임
QStyledItemDelegate.paint(self, painter, option, index)
else: # 값이 있는 아이템이면 콤보박스 보임
value = index.data(Qt.DisplayRole)
style = QApplication.style()
opt = QStyleOptionComboBox()
opt.text = str(value)
opt.rect = option.rect
style.drawComplexControl(QStyle.CC_ComboBox, opt, painter)
QStyledItemDelegate.paint(self, painter, option, index)
def setEditorData(self, editor, index):
value = index.data(Qt.DisplayRole)
num = self.items.index(value)
editor.setCurrentIndex(num)
if index.column() == 1:
editor.showPopup()
def setModelData(self, editor, model, index):
value = editor.currentText()
model.setData(index, QVariant(value), Qt.DisplayRole)
def updateEditorGeometry(self, editor, option, index):
editor.setGeometry(option.rect)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
treeview = TreeViewDialog()
treeview.show()
sys.exit(app.exec_())
data.txt
Fruits>Apple#count
Fruits>Banana#count
Fruits>Grape
Vegetables>Tomato#count
Vegetables>Cucumber#count