如何用QTreeView/QTreeWidget实现Rest API文件夹树GUI及数据模型构建
Hey there! Let's solve this problem where you need to convert a flat list of file paths (from your REST API) into a hierarchical folder tree for both QTreeWidget and QTreeView. I'll walk you through implementations for both widgets, including how to parse the API response and build the tree structure.
First: Parse the API Response
First, let's handle the JSON data from your API. The response is a flat array of objects with name (full path) and size. We'll need to split each path into segments (e.g., /folder1/sub/file3.txt becomes ["folder1", "sub", "file3.txt"]) to build the hierarchy.
Here's how you might fetch and parse the data (using Python's requests for API calls):
import requests import json def fetch_folder_data(): api_url = "YOUR_REST_API_ENDPOINT" response = requests.get(api_url) # Fix the sample JSON (note: your original sample uses semicolons instead of commas—make sure to correct that in actual API response!) data = json.loads(response.text.replace(";", ",")) return data
Option 1: Build Tree with QTreeWidget
You mentioned you already have static data in QTreeWidget, so let's expand that to work with the API data. The key is a helper function that finds or creates parent nodes for each path segment.
Full Implementation Code
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTreeWidget, QTreeWidgetItem, QVBoxLayout, QWidget, QPushButton) import sys class TreeWidgetWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("QTreeWidget Folder Tree") self.resize(400, 500) # Create UI central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) self.tree_widget = QTreeWidget() self.tree_widget.setColumnCount(2) self.tree_widget.setHeaderLabels(["Name", "Size"]) layout.addWidget(self.tree_widget) load_btn = QPushButton("Load from API") load_btn.clicked.connect(self.load_tree_from_api) layout.addWidget(load_btn) def get_or_create_parent(self, parent_item, segment): """Helper to find existing parent item or create a new one""" for i in range(parent_item.childCount()): child = parent_item.child(i) if child.text(0) == segment: return child # Create new item if not found new_item = QTreeWidgetItem([segment]) parent_item.addChild(new_item) return new_item def load_tree_from_api(self): # Clear existing tree self.tree_widget.clear() # Fetch data data = fetch_folder_data() root_item = self.tree_widget.invisibleRootItem() for item in data: full_path = item["name"] size = item["size"] # Split path into segments, ignore empty strings from leading / segments = [s for s in full_path.split("/") if s] current_parent = root_item # Create folders recursively for seg in segments[:-1]: current_parent = self.get_or_create_parent(current_parent, seg) # Add file item file_item = QTreeWidgetItem([segments[-1], size]) current_parent.addChild(file_item) if __name__ == "__main__": app = QApplication(sys.argv) window = TreeWidgetWindow() window.show() sys.exit(app.exec_())
Option 2: Build Tree with QTreeView (using QStandardItemModel)
For QTreeView, we'll use QStandardItemModel to manage the data, which is more flexible for larger datasets or if you need to modify the data later. The logic is similar to QTreeWidget, but we work with model items instead of widget items.
Full Implementation Code
from PyQt5.QtWidgets import (QApplication, QMainWindow, QTreeView, QVBoxLayout, QWidget, QPushButton) from PyQt5.QtGui import QStandardItemModel, QStandardItem import sys class TreeViewWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("QTreeView Folder Tree") self.resize(400, 500) # Create UI central_widget = QWidget() self.setCentralWidget(central_widget) layout = QVBoxLayout(central_widget) self.model = QStandardItemModel() self.model.setHorizontalHeaderLabels(["Name", "Size"]) self.tree_view = QTreeView() self.tree_view.setModel(self.model) layout.addWidget(self.tree_view) load_btn = QPushButton("Load from API") load_btn.clicked.connect(self.load_tree_from_api) layout.addWidget(load_btn) def get_or_create_parent(self, parent_item, segment): """Helper to find existing parent item or create a new one""" for row in range(parent_item.rowCount()): child_item = parent_item.child(row, 0) if child_item.text() == segment: return parent_item.child(row) # Create new folder item (only first column has name, second is empty) folder_name_item = QStandardItem(segment) folder_size_item = QStandardItem("") parent_item.appendRow([folder_name_item, folder_size_item]) return parent_item.child(parent_item.rowCount() - 1) def load_tree_from_api(self): # Clear existing model self.model.clear() self.model.setHorizontalHeaderLabels(["Name", "Size"]) # Fetch data data = fetch_folder_data() root_item = self.model.invisibleRootItem() for item in data: full_path = item["name"] size = item["size"] segments = [s for s in full_path.split("/") if s] current_parent = root_item # Create folders recursively for seg in segments[:-1]: current_parent = self.get_or_create_parent(current_parent, seg) # Add file item (both columns filled) file_name_item = QStandardItem(segments[-1]) file_size_item = QStandardItem(size) current_parent.appendRow([file_name_item, file_size_item]) if __name__ == "__main__": app = QApplication(sys.argv) window = TreeViewWindow() window.show() sys.exit(app.exec_())
Key Notes
- Path Handling: The
split("/")gives us segments, but we filter out empty strings to avoid creating unnecessary root-level empty items (from the leading/in paths). - Helper Function: The
get_or_create_parentfunction is the core—it ensures we don't duplicate folder nodes for the same path segment. - API Data Fix: Your sample JSON uses semicolons instead of commas—make sure your actual API returns valid JSON with commas!
内容的提问来源于stack exchange,提问作者kien bui

