用于浏览资源的 Maya UI 无法传播多个列表?

问题描述 投票:0回答:1

我正在使用 python 在 Maya 中创建一个脚本,旨在导航本地目录文件夹。

我被要求使其导航的方式是使用一组列表,每个列表代表不同的目录级别。

enter image description here

现在选择第一个列表[类型],它会正确传播第二个列表

给我这个反馈 在列表 0 上单击的项目 已接收列:0,当前列索引:0 正确的栏目 不是最后一栏 选定的目录:D:\WORKSPACE ew_folder结构 D\ASSETS\PROPS 是目录

但是当我单击第二个列表上的某个项目时,它似乎根本没有响应。 在列表 1 上单击的项目 已接收列:0,当前列索引:1

我很困惑。

  • 我尝试将其剥离回一个更基本的脚本,当您单击列表中的某个项目时,只需将数字添加到每个列表中,这效果很好。
  • 重新引入目录导航,这又出错了。
  • 我尝试将 os.path.join 更改为 os.path.normpath()
  • 我尝试引入检查来告诉我选择的目录,但它在单击第二个列表时什么也没告诉我。
  • 我尝试更改项目单击功能,并根据与哪个列表交互将其分成新功能。
  • 甚至向chat gtp寻求帮助,但它只是失去了理智。
import os
import maya.cmds as cmds
from PySide2 import QtWidgets, QtGui

class AssetBrowser(QtWidgets.QWidget):
    def __init__(self, asset_dir, parent=None):
        super(AssetBrowser, self).__init__(parent)
        self.asset_dir = asset_dir
        self.levels = 6  # Number of levels to display
        self.list_titles = ["Type", "Category", "Asset", "LOD", "User", "Scene"]  # List titles
        self.file_lists = []  # List to store file list widgets for each level
        self.initUI()

    def initUI(self):
        self.setWindowTitle('Asset Browser')
        layout = QtWidgets.QVBoxLayout(self)

        # Adding the image
        image_label = QtWidgets.QLabel()
        pixmap = QtGui.QPixmap(r"D:\WORKSPACE\safeBank\images\safeBank_logoTitle_v001.png")
        image_label.setPixmap(pixmap)
        layout.addWidget(image_label)

        # Add frame for project settings
        project_frame = QtWidgets.QFrame()
        project_frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        project_layout = QtWidgets.QHBoxLayout(project_frame)
        layout.addWidget(project_frame)

        # Add button to set project directory
        self.set_project_button = QtWidgets.QPushButton("Set Project")
        self.set_project_button.clicked.connect(self.setProjectDirectory)
        project_layout.addWidget(self.set_project_button)

        # Add line edit for displaying selected folder path
        self.folder_path_lineedit = QtWidgets.QLineEdit()
        self.folder_path_lineedit.setReadOnly(True)
        project_layout.addWidget(self.folder_path_lineedit)

        # Create a layout for the lists
        lists_layout = QtWidgets.QHBoxLayout()
        layout.addLayout(lists_layout)

        # Create frames for each list
        for i in range(self.levels):
            frame = QtWidgets.QFrame()
            frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
            frame_layout = QtWidgets.QVBoxLayout(frame)
            lists_layout.addWidget(frame)

            # Add title label
            title_label = QtWidgets.QLabel(self.list_titles[i])
            frame_layout.addWidget(title_label)

            # Create the file list widget
            file_list_widget = QtWidgets.QTreeWidget()
            file_list_widget.setHeaderHidden(True)
            frame_layout.addWidget(file_list_widget)

            # Connect itemClicked signal to unique itemClicked method for each list
            file_list_widget.itemClicked.connect(lambda item, col, index=i: self.itemClicked(item, col, index))

            self.file_lists.append(file_list_widget)

        # Add feedback field
        feedback_field = QtWidgets.QLabel()
        layout.addWidget(feedback_field)
        self.feedback_field = feedback_field

        # Set initial project directory
        self.setProjectDirectory(self.asset_dir)

        self.populateFileLists(self.asset_dir)

    def populateFileLists(self, directory):
        for level, file_list_widget in enumerate(self.file_lists):
            file_list_widget.clear()
            if os.path.exists(directory) and os.listdir(directory):  # Check if directory exists and is not empty
                self.populateDirectory(directory, file_list_widget)
                directory = os.path.join(directory, os.listdir(directory)[0])  # Go down a level
            else:
                break  # Stop populating lists if directory is empty or doesn't exist

    def populateDirectory(self, directory, file_list_widget):
        for item_name in sorted(os.listdir(directory)):
            item_path = os.path.join(directory, item_name)
            item = QtWidgets.QTreeWidgetItem(file_list_widget)
            item.setText(0, item_name)
            if os.path.isdir(item_path):
                item.setIcon(0, QtGui.QIcon.fromTheme("folder"))

    def itemClicked(self, item, column, index):
        print(f"Item clicked on list {index}")
        print(f"Received column: {column}, Current column index: {index}")

        if column == index:  # Only proceed if the click is in the correct column
            selected_directory = self.asset_dir

            # Build the path based on the selected folders in the previous columns
            for level in range(index + 1):
                selected_directory = os.path.join(selected_directory, self.file_lists[level].currentItem().text(0))
                print(f"Selected directory: {selected_directory}")

            if os.path.isdir(selected_directory):
                # Update the path for the next column
                self.populateFileList(selected_directory, self.file_lists[index + 1])  # Populate next column
                self.feedback_field.setText(selected_directory)  # Display selected directory in feedback field
            else:
                print(f"Selected directory is not valid: {selected_directory}")

    def populateFileList(self, directory, file_list_widget):
        file_list_widget.clear()
        self.populateDirectory(directory, file_list_widget)

    def setProjectDirectory(self, directory=None):
        if directory is None:
            directory = QtWidgets.QFileDialog.getExistingDirectory(self, "Select Project Directory")
        if directory:
            self.asset_dir = directory
            self.folder_path_lineedit.setText(directory)
            cmds.workspace(directory, openWorkspace=True)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication.instance() or QtWidgets.QApplication(sys.argv)
    asset_dir = r"D:\WORKSPACE\new_folderStructure\GF\3D\ASSETS"
    asset_browser = AssetBrowser(asset_dir)
    asset_browser.show()
    sys.exit(app.exec_())
python maya pyside2 qtgui qtwidgets
1个回答
0
投票

column
中的
itemClicked()
参数是错误的,最重要的是因为它引用了单击的QTreeWidget的列,它与QTableView类似,可以显示多列。
您只显示一列,因此该值将始终为
0
,这就是
if column == index:
只能在 first QTreeWidget 中工作的原因:该列始终为 0,第一个 QTreeWidget 具有
index
0 .

只需删除该比较即可解决问题:

    def itemClicked(self, item, column, index):
        selected_directory = self.asset_dir

        for level in range(index + 1):

        ... etc.

请注意,为此目的使用 QTreeWidget 是完全没有意义的,因为您从未使用过 QTreeView 的主要功能,即显示层次结构。

由于您也从未使用多于一列,因此更准确的选择是使用 QListWidget。

class AssetBrowser(QWidget):
    ...
    def initUI(self):
        ...
        for i in range(self.levels):
            ...
            file_list_widget = QListWidget()
            frame_layout.addWidget(file_list_widget)

            file_list_widget.itemClicked.connect(
                lambda item, index=i: self.itemClicked(item, index))

            self.file_lists.append(file_list_widget)

    ...

    def populateDirectory(self, directory, file_list_widget):
        for item_name in sorted(os.listdir(directory)):
            item_path = os.path.join(directory, item_name)
            item = QListWidgetItem(item_name, file_list_widget)
            if os.path.isdir(item_path):
                item.setIcon(QIcon.fromTheme("folder"))

    def itemClicked(self, item, index):
        selected_directory = self.asset_dir

        for level in range(index + 1):
            selected_directory = os.path.join(selected_directory, 
                self.file_lists[level].currentItem().text())

        if os.path.isdir(selected_directory):
            self.populateFileList(selected_directory, 
                self.file_lists[index + 1])
            self.feedback_field.setText(selected_directory)

        # you should always clear the remaining lists
        for list_view in self.file_lists[index + 2:]:
            list_view.clear()

还有一个重要的问题。默认情况下,如果给定路径超出“根”路径,

populateFileLists
会自动“填充”剩余视图;从用户体验的角度来看,这是错误的,因为它不会向用户显示其列表中当前选择的目录,并且您还按字母顺序对内容进行任意排序,这与
os.listdir(directory)[0]
和中使用的常规顺序不一致文件浏览器。

更合适的实现应该是:

    def populateFileLists(self, directory):
        prev_file_list = None
        for level, file_list_widget in enumerate(self.file_lists):
            file_list_widget.clear()
            if os.path.isdir(directory):
                self.populateDirectory(directory, file_list_widget)
                if prev_file_list:
                    match = prev_file_list.findItems(
                        os.path.basename(directory), Qt.MatchExactly)
                    if match:
                        prev_file_list.setCurrentItem(match[0])
                prev_file_list = file_list_widget
                for entry in sorted(os.listdir(directory)):
                    entry = os.path.join(directory, entry)
                    if os.path.isdir(entry):
                        directory = entry
                        break
                else:
                    break
            else:
                break

最后,在访问文件系统时,使用 QTreeWidget 或 QListWidget 等低级类会使事情变得有点麻烦并且容易出现错误/bug。

QFileSystemModel 通过文件系统提供了更合适的接口,应该考虑改为。
实现这一点需要进一步的努力,但也确保了更准确的文件系统和对象逻辑管理。我强烈建议遵循这条道路,如果您在尝试实现它时发现问题,请发布另一个问题。

© www.soinside.com 2019 - 2024. All rights reserved.