본문 바로가기
프로그래밍 관련/PyQt

PyQt - TreeWidget

by 존버매니아.임베디드 개발자 2021. 10. 21.
반응형

1. 위젯관련 공식 레퍼런스 참조

필요한 기능이 있으면 한번 찾아보자.

QTreeWidget Class | Qt Widgets 5.15.6


2. 빠른 사용을 위한 샘플코드

QT Designer 안쓴 버전

import sys
from PyQt5.QtWidgets import *

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUI()

    def setupUI(self):
        self.setGeometry(800, 200, 500, 300)

        #Tree 생성
        self.tree = QTreeWidget(self)
        self.tree.resize(400, 300)        
        self.tree.setColumnCount(4)
        self.tree.setHeaderLabels(["컬럼1","컬럼2","컬럼3","컬럼4"])

        #Tree에 항목추가 (TreeWidgetItem 추가)
        itemA = QTreeWidgetItem(self.tree)
        itemA.setText(0,"0행 0열")
        itemA.setText(1,"0행 1열")
        itemA.setText(2,"0행 2열")
        itemA.setText(3,"0행 3열")

        ChildA=QTreeWidgetItem(itemA)
        ChildA.setText(0,"cild 0행 0열")
        ChildA.setText(1,"cild 0행 1열")
        ChildA.setText(2,"cild 0행 2열")
        ChildA.setText(3,"cild 0행 3열")


        itemB = QTreeWidgetItem(self.tree)
        itemB.setText(0,"1행 0열")
        itemB.setText(1,"1행 1열")
        itemB.setText(2,"1행 2열")
        itemB.setText(3,"1행 3열")     

        itemC = QTreeWidgetItem(self.tree)
        itemC.setText(0,"2행 0열")
        itemC.setText(1,"2행 1열")
        itemC.setText(2,"2행 2열")
        itemC.setText(3,"2행 3열")            
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mywindow = MyWindow()
    mywindow.show()
    app.exec_()

 

QT Designer 사용 버전

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic

#UI파일 연결
#단, UI파일은 Python 코드 파일과 같은 디렉토리에 위치해야한다.
form_class = uic.loadUiType("untitled.ui")[0]

#화면을 띄우는데 사용되는 Class 선언
class WindowClass(QMainWindow, form_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

        itemA = QTreeWidgetItem(self.treeWidget) 
        itemA.setText(0, 'First') 
        itemA.setText(1, 'First1') 

        itemB = QTreeWidgetItem(itemA) 
        itemB.setText(0,'Second') 
        itemB.setText(2,'Second2') 
        
        itemC = QTreeWidgetItem(self.treeWidget) 
        itemC.setText(0, 'Example2_1') 
        itemC.setText(1, 'Example2_2') 
        itemC.setText(2, 'Example2_3') 

        item_fromC =itemC = QTreeWidgetItem(itemC) 
        item_fromC.setText(0,"exam2_1_1") 

if __name__ == "__main__" :
    #QApplication : 프로그램을 실행시켜주는 클래스
    app = QApplication(sys.argv) 

    #WindowClass의 인스턴스 생성
    myWindow = WindowClass() 

    #프로그램 화면을 보여주는 코드
    myWindow.show()

    #프로그램을 이벤트루프로 진입시키는(프로그램을 작동시키는) 코드
    app.exec_()

 

 

예제와 결과물을 보면 굳이 세세한 설명 없이도 이해 가능할 거라 믿는다.

 

setText 뒤에 숫자가 열 번호 인것만 주의하자.

QTreeWidget으로 Tree 테이블 자체를 만들고.

QTreeWidgetItem으로 한줄 한줄 내용을 만들어서 채워넣는 식이다.

 


3. 이미 추가된 데이터의 내용 수정 방법

앞의 예시에서 이어서 설명하자면, 예를 들어 앞의 예시에서 처럼 이미 GUI를 만들어놓은 상태에서,

 

1) Example2_2를 수정하고 싶다면?

 

2) 그리고 만약 위 그림에서 Second <- 여기를 수정하고 싶다면?

(그러니까 최상위 TreeWidgetItem이 아니라 그 자식(하위 트리) 를 수정하고 싶다면??

 

첫번째 문제의 해답은

QTreeWidget.topLevelItem 메소드를 사용하면된다.

   -> 파라미터에 행 번호를 써주면, 해당 행에 위치하는 TreeWidgetItem을 리턴해준다.

두번째 문제의 해답은

QTreeWidgetItem.child 메소드를 사용하면된다.

   -> 자식의 행번호를 입력하면, 해당 위치에 해당되는 TreeWidgetItem을 리턴해준다.

아래는 공식사이트의 메소드 설명임

 

 

 

treeWidget.topLevelItem(index) index는 행 번호를 나타낸다.

만약 여기에 1을 넣는다면 해당 트리 위젯의 1번행 (그러니까 위에서 2번째 행. 왜냐면 첫번째행은 행번호가 0이니까)에 있는 treeWidgetItem을 리턴해준다.

 

그러므로, 우리는 이것을 전달받은 다음 다시 setText를 호출하면 되는 것이다.

 

QTreeWidgetItem.child (index) index는 하위 트리의 row 번호를 나타낸다.

 

그냥 아래 예시코드를 보면 이해 될 듯 

 

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic

#UI파일 연결
#단, UI파일은 Python 코드 파일과 같은 디렉토리에 위치해야한다.
form_class = uic.loadUiType("untitled.ui")[0]

#화면을 띄우는데 사용되는 Class 선언
class WindowClass(QMainWindow, form_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

        itemA = QTreeWidgetItem(self.treeWidget) 
        itemA.setText(0, 'First') 
        itemA.setText(1, 'First1') 

        itemB = QTreeWidgetItem(itemA) 
        itemB.setText(0,'Second') 
        itemB.setText(2,'Second2') 
        
        itemC = QTreeWidgetItem(self.treeWidget) 
        itemC.setText(0, 'Example2_1') 
        itemC.setText(1, 'Example2_2') 
        itemC.setText(2, 'Example2_3') 

        item_fromC =itemC = QTreeWidgetItem(itemC) 
        item_fromC.setText(0,"exam2_1_1") 

#########################################################
        """여기 주목"""
        temp_item = self.treeWidget.topLevelItem(1)
        temp_item.setText(1, "1번행 1번 칼럼 내용 바뀜")

        temp_item.child(0).setText(3,"자식도 바꼈지롱")
####################################################################

if __name__ == "__main__" :
    #QApplication : 프로그램을 실행시켜주는 클래스
    app = QApplication(sys.argv) 

    #WindowClass의 인스턴스 생성
    myWindow = WindowClass() 

    #프로그램 화면을 보여주는 코드
    myWindow.show()

    #프로그램을 이벤트루프로 진입시키는(프로그램을 작동시키는) 코드
    app.exec_()

 

 


4. 특정 칸에 들어있는 데이터를 리턴 받는 방법

위 그림과 같은 트리가 있을 때 예를 들어 

1행 1열의 데이터를 리턴 받고싶다(그림의 경우 Example2_2에 해당)

 

이 때 사용하는 것은

QTreeWidgetItem의 Text 메소드이다.

Text(열번호) 이런식으로 사용한다.

import sys
from PyQt5.QtWidgets import *
from PyQt5 import uic

#UI파일 연결
#단, UI파일은 Python 코드 파일과 같은 디렉토리에 위치해야한다.
form_class = uic.loadUiType("untitled.ui")[0]

#화면을 띄우는데 사용되는 Class 선언
class WindowClass(QMainWindow, form_class) :
    def __init__(self) :
        super().__init__()
        self.setupUi(self)

        itemA = QTreeWidgetItem(self.treeWidget) 
        itemA.setText(0, 'First') 
        itemA.setText(1, 'First1') 

        itemB = QTreeWidgetItem(itemA) 
        itemB.setText(0,'Second') 
        itemB.setText(2,'Second2') 
        
        itemC = QTreeWidgetItem(self.treeWidget) 
        itemC.setText(0, 'Example2_1') 
        itemC.setText(1, 'Example2_2') 
        itemC.setText(2, 'Example2_3') 

        item_fromC =itemC = QTreeWidgetItem(itemC) 
        item_fromC.setText(0,"exam2_1_1") 

#########################################################
        """여기 주목"""
        temp_item = self.treeWidget.topLevelItem(1)
        print(temp_item.text(1))
                
####################################################################

if __name__ == "__main__" :
    #QApplication : 프로그램을 실행시켜주는 클래스
    app = QApplication(sys.argv) 

    #WindowClass의 인스턴스 생성
    myWindow = WindowClass() 

    #프로그램 화면을 보여주는 코드
    myWindow.show()

    #프로그램을 이벤트루프로 진입시키는(프로그램을 작동시키는) 코드
    app.exec_()

위 예제코드에서 """ 여기 주목""" 부분을 보자.

text 메소드로 값을 받아서 print 하도록 코드를 구현하였다.

 

해당 코드를 실행해보면 1행,1열의 데이터이므로 Example2_2 를 출력한다.

 


5. 특정 컬럼, row 숨겼다가/폈다가 하는 방법

1) 컬럼의 경우 좀 더 간단하다.

def setColumnHidden(self, column: int, hide: bool)

위의 메소드를 사용하면 된다.
숨기려는(혹은 숨겼다가 다시 회복하려는) 열의 번호를 적고.
숨길 때는 True, 다시 회복할 때는 false 하면 된다.

QTreeveiw 클래스에 있는 메소드 인데

QTreeWidget 클래스에서도 사용 가능하다.

test=QTreeWidget()
test.setColumnHidden(1,True)

이런식으로 사용가능

2) Row의 경우

Row를 숨길 때는 컬럼과 달리 TreeWidget에서 곧 바로 숨길 수가 없다. 대신에

topLevelItem(행번호)  메소드를 사용해서 숨기려는 행에 해당하는 TreeWidgetItem을 전달 받은 후,

TreeWidgetItem에 속해있는 메소드를 사용한다.

setHidden(True) 이런식으로.

 

import sys
from PyQt5.QtWidgets import *

"""
Tree 생성, 열 숨김/복구,  행 숨김/복구, 행 삭제

"""

class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUI()

    def setupUI(self):
        self.setGeometry(800, 200, 500, 300)

        #Tree 생성
        self.tree = QTreeWidget(self)
        self.tree.resize(400, 300)        
        self.tree.setColumnCount(4)
        self.tree.setHeaderLabels(["컬럼1","컬럼2","컬럼3","컬럼4"])

        #Tree에 항목추가 (TreeWidgetItem 추가)
        itemA = QTreeWidgetItem(self.tree)
        itemA.setText(0,"0행 0열")
        itemA.setText(1,"0행 1열")
        itemA.setText(2,"0행 2열")
        itemA.setText(3,"0행 3열")

        #tree 항목에 자식 추가
        ChildA=QTreeWidgetItem(itemA)
        ChildA.setText(0,"cild 0행 0열")
        ChildA.setText(1,"cild 0행 1열")
        ChildA.setText(2,"cild 0행 2열")
        ChildA.setText(3,"cild 0행 3열")


        itemB = QTreeWidgetItem(self.tree)
        itemB.setText(0,"1행 0열")
        itemB.setText(1,"1행 1열")
        itemB.setText(2,"1행 2열")
        itemB.setText(3,"1행 3열")     

        itemC = QTreeWidgetItem(self.tree)
        itemC.setText(0,"2행 0열")
        itemC.setText(1,"2행 1열")
        itemC.setText(2,"2행 2열")
        itemC.setText(3,"2행 3열")

        
        #버튼들 추가
        self.btn1 = QPushButton("1열 숨김",self)
        self.btn1.setGeometry(400,0,100,50)
        self.btn1.clicked.connect(self.btn_fun1)

        self.btn2 = QPushButton("1열 회복",self)
        self.btn2.setGeometry(400,50,100,50)
        self.btn2.clicked.connect(self.btn_fun2)

        self.btn3 = QPushButton("1행 숨김",self)
        self.btn3.setGeometry(400,100,100,50)
        self.btn3.clicked.connect(self.btn_fun3)

        self.btn4 = QPushButton("1행 복귀",self)
        self.btn4.setGeometry(400,150,100,50)
        self.btn4.clicked.connect(self.btn_fun4)

        self.btn5 = QPushButton("1행 삭제",self)
        self.btn5.setGeometry(400,200,100,50)
        self.btn5.clicked.connect(self.btn_fun5)        

    #1열 숨김
    def btn_fun1(self):
        self.tree.setColumnHidden(1,True)
    #1열 숨김에서 복구
    def btn_fun2(self):
        self.tree.setColumnHidden(1,False)
    #1행 숨김
    def btn_fun3(self):
        self.tree.topLevelItem(1).setHidden(True)
    #1행 숨김에서 복구
    def btn_fun4(self):
        self.tree.topLevelItem(1).setHidden(False)
    #1행 삭제
    def btn_fun5(self):
        self.tree.takeTopLevelItem(1)
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mywindow = MyWindow()
    mywindow.show()
    app.exec_()

6. 특정 Row 삭제 하기

두가지 방법이 있다.

 

1) TreeWidget의 takeTopLevelItem 메소드 사용 

2) 또는 sip 모듈을 import 하여 sip.delete ( 삭제하려는 TreeWidgetItem)

 

tree = QTreeWidget()
tree.takeTopLevelItem(1)

TakeTopLevelItem 으로 행을 지우면

그 뒤에 있는 행들이 자동으로 한칸씩 땡겨서 채워진다.

위 예시의 경우

1번 행을 지우면 뒤에 2행0열이라는 Row가 남는데,

이 Row는 원래 인덱스가 2였지만

1번 행을 삭제하고나면 자동으로 인덱스가 1로 당겨져있다.

그러니까 배열에서 중간에 데이터 한개를 날린 느낌이 아니라

링크드리스트에서 중간에 데이터를 한개 빼낸 느낌이라고 생각하면 된다. 

 

정확히 말하면 이 함수는 그냥 삭제만 하는게 아니라 삭제하면서 해당 아이템위젯의 내용도 return 해준다.

그래서 메소드의 이름이 take 이다.

 

그리고 삭제하는 방법이 하나 더 있다.

이것은 sip라는 모듈을 사용하는 것인데

import sip

sip.delete(지우려는 행에 속하는 TreeWidgetItem)

sip.delete(tree.topLevelItem(지우려는 행))

이런식으로 쓰면 된다. 

 


7. Selection Mode에 대하여

 

Selection Mode란 Tree에서 Row를 고를 때

Row가 하나씩 만 선택되거나, 혹은 여러개를 띄엄띄엄 고를 수 있거나

혹은 연달아서 쭉 고를 수 있거나 하는 식이다.

아래와 같이 메소드를 호출해서 셋팅해준다.

 

 

tree = QTreeWidget()
tree.setSelectionMode(QAbstractItemView.MultiSelection)


class SelectionMode(int):
        NoSelection = ... # type: QAbstractItemView.SelectionMode
        SingleSelection = ... # type: QAbstractItemView.SelectionMode
        MultiSelection = ... # type: QAbstractItemView.SelectionMode
        ExtendedSelection = ... # type: QAbstractItemView.SelectionMode
        ContiguousSelection = ... # type: QAbstractItemView.SelectionMode

각 모드의 상세 설명은 아래와 같음.

 

 


8. 마우스로 선택된 여러개의 행들 삭제하기

import sys
from PyQt5.QtWidgets import *
import sip


class MyWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setupUI()

    def setupUI(self):
        self.setGeometry(800, 200, 500, 300)

        #Tree 생성
        self.tree = QTreeWidget(self)
        self.tree.resize(400, 300)        
        self.tree.setColumnCount(4)
        self.tree.setHeaderLabels(["컬럼1","컬럼2","컬럼3","컬럼4"])
        self.tree.setSelectionMode(QAbstractItemView.ExtendedSelection)

        #Tree에 항목추가 (TreeWidgetItem 추가)
        itemA = QTreeWidgetItem(self.tree)
        itemA.setText(0,"0행 0열")
        itemA.setText(1,"0행 1열")
        itemA.setText(2,"0행 2열")
        itemA.setText(3,"0행 3열")

        #tree 항목에 자식 추가
        ChildA=QTreeWidgetItem(itemA)
        ChildA.setText(0,"cild 0행 0열")
        ChildA.setText(1,"cild 0행 1열")
        ChildA.setText(2,"cild 0행 2열")
        ChildA.setText(3,"cild 0행 3열")


        itemB = QTreeWidgetItem(self.tree)
        itemB.setText(0,"1행 0열")
        itemB.setText(1,"1행 1열")
        itemB.setText(2,"1행 2열")
        itemB.setText(3,"1행 3열")     

        itemC = QTreeWidgetItem(self.tree)
        itemC.setText(0,"2행 0열")
        itemC.setText(1,"2행 1열")
        itemC.setText(2,"2행 2열")
        itemC.setText(3,"2행 3열")

        
        #버튼들 추가
        self.btn1 = QPushButton("선택된 행들 삭제",self)
        self.btn1.setGeometry(400,0,100,50)
        self.btn1.clicked.connect(self.btn_fun1)              

    # 선택된 행들 삭제
    def btn_fun1(self):
        selected_list = self.tree.selectedItems()
        for i in selected_list:
            sip.delete(i)
   
    

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mywindow = MyWindow()
    mywindow.show()
    app.exec_()

주요 메소드는

QTreeWidget의 selectedItems() 메소드이다.

현재 선택된 row들을 list 형태로 리턴해준다. 없으면 NULL을 리턴한다.

1개만 선택돼있어도 리스트 형태로 리턴하는 것에 주의한다.


Tree에 등록된 모든 데이터들 삭제하기

clear() 메소드를 호출하면된다.

반응형