이번 포스팅에서는 윈도우 파일 탐색기의 왼쪽 프래임에서 볼 수 있는 폴더 트리를 만들어 보겠습니다. 폴더 트리는
위 탐색기 캡쳐에서 왼쪽 프래임에 있는 것 입니다. 전체 파일/폴더의 구조를 보여줍니다. 이 폴더 트리를 이용하여 파일/폴더의 구조를 파악하거나 파일/폴더를 선택할 수 도 있습니다.
오늘 만들 GUI의 전체 코드는 아래와 같습니다.
import sys
from PyQt5.QtWidgets import *
class QTreeView(QTreeView):
def __init__(self):
super(QTreeView, self).__init__()
def edit(self, index, trigger, event):
return False
class QLineEdit(QLineEdit):
def __init__(self):
super(QLineEdit, self).__init__()
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
data = event.mimeData()
urls = data.urls()
if (urls and urls[0].scheme() == 'file'):
event.acceptProposedAction()
def dropEvent(self, event):
data = event.mimeData()
urls = data.urls()
if (urls and urls[0].scheme() == 'file'):
filepath = str(urls[0].path())[1:]
self.setText(filepath)
class Main(QDialog):
def __init__(self):
super().__init__()
self.init_ui()
def init_ui(self):
layout = QVBoxLayout()
root_path = "C:/"
self.model_file_system = QFileSystemModel()
self.model_file_system.setRootPath(root_path)
self.model_file_system.setReadOnly(False)
self.tree_view = QTreeView()
self.tree_view.setModel(self.model_file_system)
self.tree_view.setRootIndex(self.model_file_system.index(root_path))
self.tree_view.doubleClicked.connect(lambda index : self.item_double_clicked(index))
self.tree_view.setDragEnabled(True)
self.tree_view.setColumnWidth(0, 300)
lineedit = QLineEdit()
layout.addWidget(self.tree_view)
layout.addWidget(lineedit)
self.setLayout(layout)
self.resize(800, 500)
self.show()
def item_double_clicked(self, index):
print(self.model_file_system.filePath(index))
if __name__ == '__main__':
app = QApplication(sys.argv)
main = Main()
sys.exit(app.exec_())
위 코드를 실행하면, 다음과 같은 UI를 얻을 수 있습니다. QVBoxLayout을 이용하여 두개이 위젯을 배치한 것인데, 위에는 QTreeView위젯, 그리고 아래에는 평범한 QLineEdit 위젯 입니다. QTreeView위젯을 통해서 파일/폴더를 탐색하고, 원하는 파일(의 경로)를 아래 QLineEdit에 드래그-앤-드롭drag-and-drop 하여 옮길 것 입니다.
위 코드에서 새롭게 소개되는 부분을 설명하겠습니다.
'''
QFileSystemModel를 생성하고, 설정
'''
root_path = "C:\Windows"
self.model_file_system = QFileSystemModel()
self.model_file_system.setRootPath(root_path)
self.model_file_system.setReadOnly(False)
'''
QTreeView 위젯을 생성하고 설정
'''
self.tree_view = QTreeView()
self.tree_view.setModel(self.model_file_system)
self.tree_view.setRootIndex(self.model_file_system.index(root_path))
self.tree_view.doubleClicked.connect(lambda index : self.item_double_clicked(index))
### 파일/폴더의 이름을 드래그 할 수 있도록 설정
self.tree_view.setDragEnabled(True)
### QTreeView의 0 번째 컬럼의 크기를 300 으로 설정
self.tree_view.setColumnWidth(0, 300)
폴터 탐색기는 QTreeView위젯을 통해 구현됩니다.
QTreeView 위젯을 생성하기에 앞서, 어떤 구조의 파일/폴더 시스템을 QTreeView를 통해서 보여줄 것 인가를 지정해야 합니다. 이는 QFileSystemModel를 통해서 할 수 있는데요, QFileSystemModel 클래스를 생성하고, 루트 경로를 설정합니다. 간단하게 .setRootPath(루트경로) 메서드를 사용합니다.
그 다음은 QTreeView 위젯을 생생해 줍니다.
그리고 앞에서 만든 QFileSysteModel을 QTreeView에 세팅해 줍니다. QFileSystemModel에서 정의한 파일 시스템 모델을 QTreeView를 통해 디스플레이 합니다. QTreeView 위젯의 루트 경로를 위와 같이 설정하면 됩니다.
그 다음에 있는 doubleClicked.connect 메서드를 사용한 부분은, QTreeView의 파일이나 폴더의 이름이 더블 클릭 되었을 때, 어떤 Slot을 실행시킬 것인가를 정의해 주는 것 입니다. 원하는 함수를 slot으로 연결하면 되는데, 이번 예제에서는 선택된 파일/폴더의 index 값을 활용하는 것을 해보도록 하겠습니다.
setDragEnabled(True)를 이용하여 파일/폴더가 드래그 될 수 있도록 설정할 수 있고, setColumnWidth(0, 300)을 이용하여 0번째 컬럼의 가로 방향 크기를 300으로 고정해 주었습니다. 0 자리에 원하는 숫자(컬럼의 순서)를 300자리에 원하는 가로 길이를 넣어주면 됩니다.
def item_double_clicked(self, index):
print(self.model_file_system.filePath(index))
doubleClicked.connet() 시그널에 연결되는 slot의 함수 입니다. QTreeView의 파일/폴더가 더블 클릭이 되면, 해당 파일/폴더의 index를 전달하게 되고, item_double_clicked 함수에서는 index를 파일/폴더의 경로로 바꾸어 출력하게 됩니다. 즉, QFileSystemModel 클래스의 .filePath(index) 메서드를 실행하면, QTreeView에서 더블 클릭 된(정확히는 QTreeView가 보여게되는 QFileSystemModel에서 선택된) 파일/폴더의 경로를 참조하게 됩니다.
더블 클릭된 파일/폴더의 경로를 알게 되었으니, 이를 이용하여 원하는 동작을 추가할 수 있습니다. 파일이나 폴더를 실행한다든지 할 수 있습니다.
코드의 맨 앞부분에는 QTreeView 클래스를 오버라이딩 하는 것이 나오는데,
class QTreeView(QTreeView):
def __init__(self):
super(QTreeView, self).__init__()
def edit(self, index, trigger, event):
return False
QTreeView 위젯의 edit 메서드를 위와 같이 수정해 주었습니다. 기본적으로 QTreeView의 파일/폴더 이름이 더블 클릭 되면, 파일/폴더의 이름을 변경할 수 있도록 파일/폴더 이름이 편집 모드로 바뀌게 됩니다. 그러나, 이번에 우리가 만들 GUI에서는 파일/폴더의 이름을 더블 클릭하면, 원하는 기능이 작동 될 수 있도록 (원하는 slot에 signal을 줄 수 있도록) 하고 싶기 때문에, 위와 같이 오버라이딩 해 준 것 입니다.
그 다음 부분에는 QLineEdit을 오버라이딩 하는 것이 나오는데,
class QLineEdit(QLineEdit):
def __init__(self):
super(QLineEdit, self).__init__()
self.setAcceptDrops(True)
def dragEnterEvent(self, event):
data = event.mimeData()
urls = data.urls()
if (urls and urls[0].scheme() == 'file'):
event.acceptProposedAction()
def dropEvent(self, event):
data = event.mimeData()
urls = data.urls()
if (urls and urls[0].scheme() == 'file'):
filepath = str(urls[0].path())[1:]
self.setText(filepath)
위 코드에서도 볼 수 있듯, QLineEdit이 드롭을 받을 수 있도록 록 한 것 입니다. QTreeView의 파일/폴더를 드래그 해서, QLineEdit에 드롭하여 QLineEdit에 파일/폴더 이름가 쓰일 수 있도록 할 것 입니다.
그렇게 하기 위해서는 위와 같이 dragEnterEvent와 dropEvent를 오버라이딩 해야하는데, 말 그대로 QLineEdit에 drag와 drop 이벤트가 발생했을 때, 이를 어떻게 처리하면 되는지에 대한 설정입니다.
QLineEdit에 드래그, 드롭 이벤트를 설정하지 않는다면 (즉, 클래스 오버라이딩을 하지 않는 기본 QLineEdit을 사용한다면)
위와 같이 파일/폴더 이름을 드래그 하여 QLineEdit위에 놓았을 때, 금지 표시가 뜨게 됩니다. 즉, QLineEdit에 해당 폴더/파일 이름을 드롭할 수 없다는 것 입니다.
그러나, 위 코드와 같이 드래그와 드롭 이벤트가 발생시, 어떻게 처리할 것인가를 설정해 준다면,
위와 같이 파일/폴더의 이름을 QLineEdit에 드롭 할 수 있습니다. 그리고 QLineEdit에는 파일/폴더의 경로가 쓰여지게 됩니다.
폴더 트리에서 파일/폴더의 이름을 드래그-앤-드롭하여 선택 한 뒤, 해당 파일/폴더를 추가적인 과정을 거쳐 쉽게 사용할 수 있습니다.
파일이나 폴더의 경로를 설정할 때에는 지난 포스팅에서 본 바 있는 QFileDialog.getOpenFileName를 이용하여 파일/폴더 선택 대화창 이용할 수 있지만, QTreeView는 한 번에 파일/폴더의 구조를 보여 준다는 장점이 있습니다. 필요에 따라서 두 위젯 중 효율적으로 GUI를 구현할 수 있는 위젯을 선택하면 됩니다.
'PyQt GUI' 카테고리의 다른 글
PyQt GUI (19) 윈도우 아이콘 속성창과 동일한 대화창 만들기 (2) | 2022.06.17 |
---|---|
PyQt GUI (18) 괜찮은 테마 소개 : qt_material (4) | 2022.03.07 |
PyQt GUI (16) 테이블 위젯(QTableWidget)으로 표 표시, 수정, 저장하기 (0) | 2022.02.15 |
PyQt GUI (15) 리스트 아이템(list item) 드래그-앤-드롭(drag and drop) 이용하기 (1) | 2021.10.08 |
PyQt GUI (14) 그래프 라이브러리 Matplotlib을 GUI에 포함하기(embeding) (0) | 2021.10.04 |