如何根据作为输入的列表正确排序 QTreeView 中的列
How to properly order columns in a QTreeView based on a list as input
基本上我显示的是一个有 20 列的 QTreeView。我希望用户 re-arrange 列并按下保存按钮以将排序存储为 ini-file 中的列表。在启动程序时,我想根据 ini-file.
中的设置 re-order 列
我将原始列顺序存储为“list_origin”中的列表。
所需的顺序在“list_custom”中。
例如
list_origin=['From', 'Subject', 'Date']
list_custom=['Date', 'Subject', 'From']
现在的问题是,当我使用 model headers moveSection() 命令移动列时,原始索引有时不再正确,因为列可能会插入中间并因此失去它们的来源位置索引。
请参见下面的示例:按下“将列重新排列为 Date/Subject/From”按钮将创建不需要的列顺序。如何根据 list_custom?
按所需顺序排列列
#!/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" 包含原始顺序的 header 名称,例如
list_origin=['From', 'Subject', 'Date']
"list_custom" 是我的 QTreeView 中列的所需顺序,例如
list_custom=['Date', 'Subject', 'From']
现在我正在遍历自定义列表,并希望使用 header moveSection() 放置基于此位置的列。
所以算法基本上是:
step1: 从自定义列表的索引 0 开始,它是“日期”
step2:从origin列表中获取“Date”的位置,即2。
第三步:调用 moveSection(2,0)
跟踪输出:
将 col 'Date' 从 2 移动到 0。
将 col 'Subject' 从 1 移动到 1。
将 col 'From' 从 0 移动到 2。
但无论如何,结果是“发件人”/“主题”/“日期”(!) 而不是所需的“日期”/“主题”/“发件人”。
由于视觉顺序在循环内发生变化,因此逻辑是在迭代时获取每个元素的索引:
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)
基本上我显示的是一个有 20 列的 QTreeView。我希望用户 re-arrange 列并按下保存按钮以将排序存储为 ini-file 中的列表。在启动程序时,我想根据 ini-file.
中的设置 re-order 列我将原始列顺序存储为“list_origin”中的列表。 所需的顺序在“list_custom”中。 例如
list_origin=['From', 'Subject', 'Date']
list_custom=['Date', 'Subject', 'From']
现在的问题是,当我使用 model headers moveSection() 命令移动列时,原始索引有时不再正确,因为列可能会插入中间并因此失去它们的来源位置索引。
请参见下面的示例:按下“将列重新排列为 Date/Subject/From”按钮将创建不需要的列顺序。如何根据 list_custom?
按所需顺序排列列#!/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" 包含原始顺序的 header 名称,例如 list_origin=['From', 'Subject', 'Date']
"list_custom" 是我的 QTreeView 中列的所需顺序,例如 list_custom=['Date', 'Subject', 'From']
现在我正在遍历自定义列表,并希望使用 header moveSection() 放置基于此位置的列。
所以算法基本上是:
step1: 从自定义列表的索引 0 开始,它是“日期”
step2:从origin列表中获取“Date”的位置,即2。
第三步:调用 moveSection(2,0)
跟踪输出:
将 col 'Date' 从 2 移动到 0。
将 col 'Subject' 从 1 移动到 1。
将 col 'From' 从 0 移动到 2。
但无论如何,结果是“发件人”/“主题”/“日期”(!) 而不是所需的“日期”/“主题”/“发件人”。
由于视觉顺序在循环内发生变化,因此逻辑是在迭代时获取每个元素的索引:
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)