PyQt treeview 双击编辑文本
PyQt treeview edit text on doubleclick
所以我一直在尝试实现一个适当的 TreeView,它根据用户输入显示目录和文件 - 我允许用户递归或以其他方式将目录和文件添加到他的 "project",之后我创建了我自己的项目内容树视图。
现在,我的问题是,尽管我在这个主题上发现的大多数文档和其他问题似乎都想禁用树视图项目的可编辑性,但我正在尝试(但失败了)找到一种方法来启用它。我希望用户能够双击树视图任何列中的任何单元格,然后编辑其内容。有人知道怎么做吗?
下面是我用来在 tabView 小部件中生成选项卡的代码,之后我添加了 TreeView。 TreeView 的项目稍后通过 AddParent 和 AddChild 方法添加。
class treeTab(QtWidgets.QWidget):
def __init__(self,core,main,label):
super (treeTab,self).__init__()
self.label = label
self.core = core
self.sizes = core.UISizes
self.tab_sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding)
self.tree = QtWidgets.QTreeWidget(self)
self.tree.setColumnCount(len(self.sizes.projectTreeColumnLabels))
self.tree.setHeaderLabels(self.sizes.projectTreeColumnLabels)
self.tree.setSizePolicy(self.tab_sizePolicy)
self.tree_layout = QtWidgets.QGridLayout()
self.tree_layout.objectName = self.label + "TreeGridLayout"
self.tree.setLayout(self.tree_layout)
self.treeroot = self.tree.invisibleRootItem()
self.tree.setSelectionMode(Qt.QAbstractItemView.ContiguousSelection)
def addParent(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
item.setExpanded (True)
return item
def addChild(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setText(1,data.print_tags())
item.setText(2,data.category.name)
item.setText(3,data.format)
item.setCheckState (column, QtCore.Qt.Unchecked)
item.setFlags(item.flags() or QtCore.Qt.ItemIsEditable)
return item
你搞糊涂了binary operators and Boolean operators。布尔运算符(例如 and
和 or
)与布尔值(例如 True
和 False
)一起使用以生成单个 True
或 False
计算表达式后。
但是,标志不是布尔值。它们是 2 的幂的整数(或只设置了一位的二进制数),因此它们可以组合成一个整数,表示每个标志是启用还是禁用。例如,2 在二进制中表示为 0b010
。 4表示为0b100
。如果按位或将它们放在一起,则会得到 0b110
,表示设置了等于 2 的标志和等于 4 的标志。但是等于 1 的标志未设置(0b110
中的 0
)。
简而言之,您应该使用按位或运算符设置标志 (|
):
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
所以我设法解决了这个问题 - 最后证明它非常简单:)
为了创建一个 'editable' treeView 项目,您可以在其中双击特定项目的文本来编辑它,您只需将项目的特定列中包含的小部件更改为QLineEdit 小部件,在按下回车键后自行删除。代码如下所示:
这是将双击事件连接到获取当前所选项目并将其替换为 QLineEdit 小部件的方法的代码:
self.tree.itemDoubleClicked.connect(self.editItem)
def editItem(self,*args):
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
edit = QtWidgets.QLineEdit()
edit.returnPressed.connect(lambda*_:self.project.setData(column,edit.text(),itm,column,self.tree))
edit.returnPressed.connect(lambda*_:self.update())
self.tree.setItemWidget(itm,column,edit)
特别注意以下代码的组合:
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
此代码实际上为您提供了当前所选项目的行和列,如果您想单独编辑列项目,这将非常有用。
现在您会问自己为什么要将这么多参数传递给 'setData' 方法:这纯粹是为了我的特定项目,所以不用担心。 'returnPressed' 事件只需要连接到正确的方法来处理它包含的任何数据,然后删除它自己。在我的代码中,它看起来像这样:
def setData(self,dataTypeIndex,data,item,column,tree):
if dataTypeIndex == 0:
# filename
self.name = data
elif dataTypeIndex == 1:
# tags
data = data.split(",")
self.tags = []
for tag in data:
self.tags.append(Tag(tag))
elif dataTypeIndex == 2:
# category
self.category.name = data
tree.setItemWidget(item,column,None)
最后一行代码 ( tree.setItemWidget(item,column,None) ) 是 QlineEdit 没有父级的地方,因此被有效地删除了。
所以我一直在尝试实现一个适当的 TreeView,它根据用户输入显示目录和文件 - 我允许用户递归或以其他方式将目录和文件添加到他的 "project",之后我创建了我自己的项目内容树视图。
现在,我的问题是,尽管我在这个主题上发现的大多数文档和其他问题似乎都想禁用树视图项目的可编辑性,但我正在尝试(但失败了)找到一种方法来启用它。我希望用户能够双击树视图任何列中的任何单元格,然后编辑其内容。有人知道怎么做吗?
下面是我用来在 tabView 小部件中生成选项卡的代码,之后我添加了 TreeView。 TreeView 的项目稍后通过 AddParent 和 AddChild 方法添加。
class treeTab(QtWidgets.QWidget):
def __init__(self,core,main,label):
super (treeTab,self).__init__()
self.label = label
self.core = core
self.sizes = core.UISizes
self.tab_sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding,QtWidgets.QSizePolicy.Expanding)
self.tree = QtWidgets.QTreeWidget(self)
self.tree.setColumnCount(len(self.sizes.projectTreeColumnLabels))
self.tree.setHeaderLabels(self.sizes.projectTreeColumnLabels)
self.tree.setSizePolicy(self.tab_sizePolicy)
self.tree_layout = QtWidgets.QGridLayout()
self.tree_layout.objectName = self.label + "TreeGridLayout"
self.tree.setLayout(self.tree_layout)
self.treeroot = self.tree.invisibleRootItem()
self.tree.setSelectionMode(Qt.QAbstractItemView.ContiguousSelection)
def addParent(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setChildIndicatorPolicy(QtWidgets.QTreeWidgetItem.ShowIndicator)
item.setExpanded (True)
return item
def addChild(self, parent, column, title, data):
item = QtWidgets.QTreeWidgetItem(parent, [title])
item.setData(column, QtCore.Qt.UserRole, data)
item.setText(1,data.print_tags())
item.setText(2,data.category.name)
item.setText(3,data.format)
item.setCheckState (column, QtCore.Qt.Unchecked)
item.setFlags(item.flags() or QtCore.Qt.ItemIsEditable)
return item
你搞糊涂了binary operators and Boolean operators。布尔运算符(例如 and
和 or
)与布尔值(例如 True
和 False
)一起使用以生成单个 True
或 False
计算表达式后。
但是,标志不是布尔值。它们是 2 的幂的整数(或只设置了一位的二进制数),因此它们可以组合成一个整数,表示每个标志是启用还是禁用。例如,2 在二进制中表示为 0b010
。 4表示为0b100
。如果按位或将它们放在一起,则会得到 0b110
,表示设置了等于 2 的标志和等于 4 的标志。但是等于 1 的标志未设置(0b110
中的 0
)。
简而言之,您应该使用按位或运算符设置标志 (|
):
item.setFlags(item.flags() | QtCore.Qt.ItemIsEditable)
所以我设法解决了这个问题 - 最后证明它非常简单:)
为了创建一个 'editable' treeView 项目,您可以在其中双击特定项目的文本来编辑它,您只需将项目的特定列中包含的小部件更改为QLineEdit 小部件,在按下回车键后自行删除。代码如下所示:
这是将双击事件连接到获取当前所选项目并将其替换为 QLineEdit 小部件的方法的代码:
self.tree.itemDoubleClicked.connect(self.editItem)
def editItem(self,*args):
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
edit = QtWidgets.QLineEdit()
edit.returnPressed.connect(lambda*_:self.project.setData(column,edit.text(),itm,column,self.tree))
edit.returnPressed.connect(lambda*_:self.update())
self.tree.setItemWidget(itm,column,edit)
特别注意以下代码的组合:
itm = self.tree.itemFromIndex(self.tree.selectedIndexes()[0])
column = self.tree.currentColumn()
此代码实际上为您提供了当前所选项目的行和列,如果您想单独编辑列项目,这将非常有用。
现在您会问自己为什么要将这么多参数传递给 'setData' 方法:这纯粹是为了我的特定项目,所以不用担心。 'returnPressed' 事件只需要连接到正确的方法来处理它包含的任何数据,然后删除它自己。在我的代码中,它看起来像这样:
def setData(self,dataTypeIndex,data,item,column,tree):
if dataTypeIndex == 0:
# filename
self.name = data
elif dataTypeIndex == 1:
# tags
data = data.split(",")
self.tags = []
for tag in data:
self.tags.append(Tag(tag))
elif dataTypeIndex == 2:
# category
self.category.name = data
tree.setItemWidget(item,column,None)
最后一行代码 ( tree.setItemWidget(item,column,None) ) 是 QlineEdit 没有父级的地方,因此被有效地删除了。