Python 如何基于作为输入的列表对QTreeView中的列进行正确排序

Python 如何基于作为输入的列表对QTreeView中的列进行正确排序,python,pyqt,pyqt5,qtreeview,Python,Pyqt,Pyqt5,Qtreeview,基本上,我显示的是一个包含20列的QTreeView。我希望用户重新排列列并按下保存按钮,将排序作为列表存储在ini文件中。启动程序时,我想根据ini文件中的设置对列重新排序 我将原始colum订单作为列表存储在“list_origin”中。 所需的顺序在“列表\自定义”中。 例如 现在的问题是,当我使用model headers moveSection()命令移动列时,原始索引有时不再正确,因为这些列可能会插入其中,从而丢失它们的原始位置索引 请参见下面的示例:按下“将列重新排列为日期/主题/

基本上,我显示的是一个包含20列的QTreeView。我希望用户重新排列列并按下保存按钮,将排序作为列表存储在ini文件中。启动程序时,我想根据ini文件中的设置对列重新排序

我将原始colum订单作为列表存储在“list_origin”中。 所需的顺序在“列表\自定义”中。 例如

现在的问题是,当我使用model headers moveSection()命令移动列时,原始索引有时不再正确,因为这些列可能会插入其中,从而丢失它们的原始位置索引

请参见下面的示例:按下“将列重新排列为日期/主题/发件人”按钮将创建不需要的列顺序。如何根据列表按所需顺序排列柱

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# file: treeView_FindCol.py

import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
def find_col_by_name(tree_obj, col_name: str) -> int:
    """ Returns found column position as integer, else -1 """
    pos_found: int = -1
    model = tree_obj.model()
    if model:
        for col in range(model.columnCount()):
            header = model.headerData(col, Qt.Horizontal, Qt.DisplayRole)
            if str(header) == col_name:
                pos_found = col
    return pos_found
def find_col_by_index(tree_obj, col_index: int) -> int:
    """ Returns found column position as integer, else -1 """
    pos_found: int = -1
    model = tree_obj.model()
    header = tree_obj.header()

    pos_found = header.visualIndex(col_index)
    header_txt = model.headerData(pos_found, Qt.Horizontal, Qt.DisplayRole)

    return pos_found

class App(QWidget):
    FROM, SUBJECT, DATE = range(3)

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 Treeview Example - pythonspot.com'
        self.left = 800
        self.top = 200
        self.width = 640
        self.height = 240
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        pushButton = QPushButton("Rearrange cols to Date/Subject/From")

        groupBox = QGroupBox("Inbox")
        treeView = QTreeView()
        treeView.setRootIsDecorated(False)
        treeView.setAlternatingRowColors(True)

        pushButton.clicked.connect(lambda: self.rearrange_column_layout(treeView))

        dataLayout = QHBoxLayout()
        dataLayout.addWidget(treeView)
        dataLayout.addWidget(pushButton)

        groupBox.setLayout(dataLayout)

        model = self.createMailModel(self)
        treeView.setModel(model)
        self.addMail(model, 'service@github.com', 'Your Github Donation','03/25/2017 02:05 PM')
        self.addMail(model, 'support@github.com', 'Github Projects','02/02/2017 03:05 PM')
        self.addMail(model, 'service@phone.com', 'Your Phone Bill','01/01/2017 04:05 PM')
        self.addMail(model, 'service@abc.com', 'aaaYour Github Donation','03/25/2017 02:05 PM')
        self.addMail(model, 'support@def.com', 'bbbGithub Projects','02/02/2017 03:05 PM')
        self.addMail(model, 'service@xyz.com', 'cccYour Phone Bill','01/01/2017 04:05 PM')

        mainLayout = QVBoxLayout()
        mainLayout.addWidget(groupBox)
        self.setLayout(mainLayout)

        self.show()

    def createMailModel(self,parent):
        model = QStandardItemModel(0, 3, parent)
        model.setHeaderData(self.FROM, Qt.Horizontal, "From")
        model.setHeaderData(self.SUBJECT, Qt.Horizontal, "Subject")
        model.setHeaderData(self.DATE, Qt.Horizontal, "Date")
        return model

    def addMail(self,model, mailFrom, subject, date):
        model.insertRow(0)
        model.setData(model.index(0, self.FROM), mailFrom)
        model.setData(model.index(0, self.SUBJECT), subject)
        model.setData(model.index(0, self.DATE), date)

    def rearrange_column_layout(self, treeView):
        print("restore_column_layout() called.")

        list_custom: list = ['Date', 'Subject', 'From']
        list_origin: list = []
        model = treeView.model()
        header = treeView.header()
        col_count = model.columnCount()
        for col_search_index in range(col_count):
            col_found = header.visualIndex(col_search_index)
            header_txt = model.headerData(col_search_index, Qt.Horizontal, Qt.DisplayRole)
            list_origin.append(header_txt)
        print(f"{list_origin=}")
        print(f"{list_custom=}")
        pos_custom: int = 0
        pos_origin_last: int = 0
        for item_custom in list_custom:
            pos_origin: int = 0
            for item_origin in list_origin:
                if item_custom == item_origin:
                    msg_txt = f"moving col '{item_origin}' from {pos_origin} to {pos_custom}."
                    print(msg_txt)
                    QMessageBox.information(self, f"{item_origin}", msg_txt)
                    header.moveSection(pos_origin, pos_custom)
                    pos_origin_last = pos_origin
                pos_origin += 1
            pos_custom += 1


if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = App()
    sys.exit(app.exec_())
我想根据输入列表设置列顺序

“列表来源”包含原始顺序的标题名称,例如。 list_origin=['From','Subject','Date']

“列表\自定义”是我的QTreeView中所需的列顺序,例如。 list_custom=['Date'、'Subject'、'From']

现在,我正在迭代自定义列表,并希望使用header moveSection()放置基于此位置的列

所以算法基本上是:

步骤1:从自定义列表的索引0开始,它是“日期”

步骤2:从来源列表中获取“日期”的位置,即2

步骤3:调用移动部分(2,0)

跟踪输出:

将列“日期”从2移动到0

将列“主题”从1移动到1

正在将列“从”从0移动到2


但无论如何,结果是“From”/“Subject”/“Date”(!),而不是期望的“Date”/“Subject”/“From”。

逻辑是在迭代时获取每个元素的索引,因为循环中的视觉顺序在变化:

def rearrange_column_layout(self, treeView):
    to_list = ["Date", "Subject", "From"]

    header = treeView.header()
    model = treeView.model()
    for i, c in enumerate(to_list[:-1]):
        from_list = [
            model.headerData(header.logicalIndex(visual_index), Qt.Horizontal)
            for visual_index in range(header.count())
        ]
        j = from_list.index(c)
        header.moveSection(j, i)

逻辑是在迭代时获取每个元素的索引,因为视觉顺序在循环中发生变化:

def rearrange_column_layout(self, treeView):
    to_list = ["Date", "Subject", "From"]

    header = treeView.header()
    model = treeView.model()
    for i, c in enumerate(to_list[:-1]):
        from_list = [
            model.headerData(header.logicalIndex(visual_index), Qt.Horizontal)
            for visual_index in range(header.count())
        ]
        j = from_list.index(c)
        header.moveSection(j, i)

我不理解你的问题,请更好地解释你的句子:原始索引在操作过程中无效,因为右侧的一些列可能会插入到左侧。这还不够:
def reareat\u column\u layout(self,treeView):header=treeView.header().moveSection(0,2)
谢谢你的提问。也许你知道一种更简单的方法来做这件事。。。基本上,我显示的是一个包含20列的QTreeView。我希望用户重新排列列并按下保存按钮,将排序作为列表存储在ini文件中。启动程序时,我想根据ini文件中的设置对列重新排序。您有XY问题(我想在某些情况下我已经解释了该问题的类型,请参阅),我可以尝试实现您在评论中指出的目标,但不幸的是,这不是您的问题所表明的,如果你重新制定,我会尽力帮助你谢谢你的关心。我已经尽力做到尽可能精确,并重新制定了问题。我不理解你的问题,请更好地解释你的句子:原始索引在操作过程中无效,因为右侧的某些列可能会插入左侧。这还不够:
def reareat\u column\u layout(self,treeView):header=treeView.header().moveSection(0,2)
谢谢你的提问。也许你知道一种更简单的方法来做这件事。。。基本上,我显示的是一个包含20列的QTreeView。我希望用户重新排列列并按下保存按钮,将排序作为列表存储在ini文件中。启动程序时,我想根据ini文件中的设置对列重新排序。您有XY问题(我想在某些情况下我已经解释了该问题的类型,请参阅),我可以尝试实现您在评论中指出的目标,但不幸的是,这不是您的问题所表明的,如果你重新制定,我会尽力帮助你谢谢你的关心。我已经尽我最大的努力做到尽可能精确,并重新提出了这个问题。非常感谢,这确实有效!“逻辑是在迭代时获得每个元素的索引”-这真是天才!非常感谢,这确实有效!“逻辑是在迭代时获得每个元素的索引”-这真是天才!