Make QTreeview's Column Editable in Pyside

1.1k views Asked by At

How can I make the second column of the QTreeView editable so the user can change the name?

enter image description here

import sys
import os
import random
from PySide import QtGui, QtCore

class ID_Asset(object):
    def __init__(self, buffer_id=0, name='', nodes=[]):
        self.buffer_id = buffer_id
        self.name = name if name else 'unknown'
        self.nodes = nodes if nodes is not None else []
        self.color = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))

        self.randomize_color()

    def randomize_color(self):
        r = random.randrange(0, 255)
        g = random.randrange(0, 255)
        b = random.randrange(0, 255)

        self.color = QtGui.QBrush(QtGui.QColor(r, g, b, 255))


class ObjectIDManager(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(ObjectIDManager, self).__init__(parent)

        self.TITLE = 'Object ID Manager'
        self.VERSION = "1.0.0" # MAJOR.MINOR.PATCH
        self.resize(270, 500)
        self.setWindowTitle(self.TITLE + " | " + self.VERSION)
        self.init_ui()

    def init_ui(self):

        # variables
        self.assets = []
        self.handlers = []

        self.items_model = QtGui.QStandardItemModel()
        self.ui_items = QtGui.QTreeView()
        # self.ui_items.setAlternatingRowColors(True)
        self.ui_items.setSortingEnabled(True)
        self.ui_items.setAllColumnsShowFocus(True)
        self.ui_items.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.ui_items.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
        self.ui_items.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui_items.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.ui_items.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        # self.ui_items.customContextMenuRequested.connect(self.open_menu)
        self.ui_items.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.ui_items.setModel(self.items_model)
        self.ui_items.setRootIsDecorated(False)

        gbox = QtGui.QGridLayout()
        gbox.setContentsMargins(10, 10, 10, 10)
        gbox.addWidget(self.ui_items)

        # main layout
        main_widget = QtGui.QWidget()
        main_widget.setLayout(gbox)
        self.setCentralWidget(main_widget)

        # signals
        self.initialize()

    # functions
    def initialize(self):
        self.process_model()

    def process_model(self):
        model = self.ui_items.model()
        model.clear()
        headers = ['ID', 'Name', 'Used', 'Color']
        model.setHorizontalHeaderLabels(headers)

        self.collect_assets()

        for x in self.assets:
            model.insertRow(0)

            # Append object
            model.setData(model.index(0, 0), x, role=QtCore.Qt.UserRole)
            model.setData(model.index(0, 0), x.buffer_id)
            model.setData(model.index(0, 1), x.name)
            model.setData(model.index(0, 2), len(x.nodes))
            model.setData(model.index(0, 3), x.color, QtCore.Qt.BackgroundRole)

            # item = model.itemFromIndex(model.index(0,0))

        self.ui_items.sortByColumn(0, QtCore.Qt.AscendingOrder)

    def collect_assets(self):
        ids = {
            0: ['a','b','c'],
            1: ['a','b','c','j'],
            30: ['b','c'],
            45: ['a',],
            60: ['a','b','c','d','e','f']
        }

        self.assets = []

        for key, value in ids.items():
            new_asset = ID_Asset(buffer_id=key, nodes=value)
            self.assets.append(new_asset)

        return self.assets

# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = ObjectIDManager()
    window.show()
    app.exec_()
1

There are 1 answers

0
eyllanesc On BEST ANSWER

You should not use:

{Your QTreeView}.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)

since you can not edit any item.

You must place the editable property element by element, that is, {your QStandardItem}.setEditable({your value}).

In your case add:

model.item(0, 0).setEditable(False)
model.item(0, 1).setEditable(True)
model.item(0, 2).setEditable(False)
model.item(0, 3).setEditable(False)

after of

...
model.setData(model.index(0, 0), x, role=QtCore.Qt.UserRole)
model.setData(model.index(0, 0), x.buffer_id)
model.setData(model.index(0, 1), x.name)
model.setData(model.index(0, 2), len(x.nodes))
model.setData(model.index(0, 3), x.color, QtCore.Qt.BackgroundRole)
....

Complete code:

import sys
import os
import random
from PySide import QtGui, QtCore

class ID_Asset(object):
    def __init__(self, buffer_id=0, name='', nodes=[]):
        self.buffer_id = buffer_id
        self.name = name if name else 'unknown'
        self.nodes = nodes if nodes is not None else []
        self.color = QtGui.QBrush(QtGui.QColor(0, 0, 0, 255))

        self.randomize_color()

    def randomize_color(self):
        r = random.randrange(0, 255)
        g = random.randrange(0, 255)
        b = random.randrange(0, 255)

        self.color = QtGui.QBrush(QtGui.QColor(r, g, b, 255))


class ObjectIDManager(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(ObjectIDManager, self).__init__(parent)

        self.TITLE = 'Object ID Manager'
        self.VERSION = "1.0.0" # MAJOR.MINOR.PATCH
        self.resize(270, 500)
        self.setWindowTitle(self.TITLE + " | " + self.VERSION)
        self.init_ui()

    def init_ui(self):

        # variables
        self.assets = []
        self.handlers = []

        self.items_model = QtGui.QStandardItemModel()
        self.ui_items = QtGui.QTreeView()
        # self.ui_items.setAlternatingRowColors(True)
        self.ui_items.setSortingEnabled(True)
        self.ui_items.setAllColumnsShowFocus(True)
        # self.ui_items.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers)
        self.ui_items.header().setResizeMode(QtGui.QHeaderView.ResizeToContents)
        self.ui_items.setSelectionBehavior(QtGui.QAbstractItemView.SelectRows)
        self.ui_items.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection)
        self.ui_items.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        # self.ui_items.customContextMenuRequested.connect(self.open_menu)
        self.ui_items.sortByColumn(0, QtCore.Qt.AscendingOrder)
        self.ui_items.setModel(self.items_model)
        self.ui_items.setRootIsDecorated(False)

        gbox = QtGui.QGridLayout()
        gbox.setContentsMargins(10, 10, 10, 10)
        gbox.addWidget(self.ui_items)

        # main layout
        main_widget = QtGui.QWidget()
        main_widget.setLayout(gbox)
        self.setCentralWidget(main_widget)

        # signals
        self.initialize()

    # functions
    def initialize(self):
        self.process_model()

    def process_model(self):
        model = self.ui_items.model()
        model.clear()
        headers = ['ID', 'Name', 'Used', 'Color']
        model.setHorizontalHeaderLabels(headers)

        self.collect_assets()

        for x in self.assets:
            model.insertRow(0)
            # Append object
            model.setData(model.index(0, 0), x, role=QtCore.Qt.UserRole)
            model.setData(model.index(0, 0), x.buffer_id)
            model.setData(model.index(0, 1), x.name)
            model.setData(model.index(0, 2), len(x.nodes))
            model.setData(model.index(0, 3), x.color, QtCore.Qt.BackgroundRole)

            model.item(0, 0).setEditable(False)
            model.item(0, 1).setEditable(True)
            model.item(0, 2).setEditable(False)
            model.item(0, 3).setEditable(False)




            # item = model.itemFromIndex(model.index(0,0))

        self.ui_items.sortByColumn(0, QtCore.Qt.AscendingOrder)

    def collect_assets(self):
        ids = {
            0: ['a','b','c'],
            1: ['a','b','c','j'],
            30: ['b','c'],
            45: ['a',],
            60: ['a','b','c','d','e','f']
        }

        self.assets = []

        for key, value in ids.items():
            new_asset = ID_Asset(buffer_id=key, nodes=value)
            self.assets.append(new_asset)

        return self.assets

# Main
# -----------------------------------------------------------------------------
if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = ObjectIDManager()
    window.show()
    app.exec_()

Output:

enter image description here