1

I am making a QtreeWidget with item editable,but the problem is with the Item Editor or QAbstractItemDelegate(might be called like this,not sure).I am unable to change the stylesheet,actually i dont know how to do this.And also i want the selected lines(blue in editor) should be according to my wish.like below pictureenter image description here

here i want that blue selected line upto ".jpg",so that anyone cant change that ".jpg". Only ,one can change upto this".jpg"

Here is my code:

import sys
from PyQt5 import QtCore, QtWidgets

class Window(QtWidgets.QWidget):
    def __init__(self):
        super().__init__()
        self.button = QtWidgets.QPushButton('Edit')
        self.button.clicked.connect(self.edittreeitem)
        self.tree = QtWidgets.QTreeWidget()
        self.tree.setStyleSheet('background:#333333;color:grey')
        layout = QtWidgets.QVBoxLayout(self)
        layout.addWidget(self.tree)
        layout.addWidget(self.button)
        columns = 'ABCDE'
        self.tree.setColumnCount(len(columns))
        for index in range(50):
            item=QtWidgets.QTreeWidgetItem(
                self.tree, [f'{char}{index:02}.jpg' for char in columns])
            item.setFlags(item.flags()|QtCore.Qt.ItemIsEditable)
    def edittreeitem(self):
        getSelected = self.tree.selectedItems()
        self.tree.editItem(getSelected[0],0)  

if __name__ == '__main__':
    
    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setWindowTitle('Test')
    window.setGeometry(800, 100, 540, 300)
    window.show()
    sys.exit(app.exec_())
Hacker6914
  • 247
  • 1
  • 9
  • From what I understand you want the file extension (it can be another extension like .png, .gif, etc) not editable, am I correct? – eyllanesc Feb 17 '21 at 15:40
  • Yes. And I also want to change stylesheet like background,foreground of that editor. – Hacker6914 Feb 17 '21 at 16:51

1 Answers1

1

You can create your own delegate that only considers the base name without the extension, and then set the data using the existing extension.

class BaseNameDelegate(QtWidgets.QStyledItemDelegate):
    def setEditorData(self, editor, index):
        editor.setText(QtCore.QFileInfo(index.data()).completeBaseName())

    def setModelData(self, editor, model, index):
        name = editor.text()
        if not name:
            return
        suffix = QtCore.QFileInfo(index.data()).suffix()
        model.setData(index, '{}.{}'.format(name, suffix))


class Window(QtWidgets.QWidget):
    def __init__(self):
        # ...
        self.tree.setItemDelegate(BaseNameDelegate(self.tree))

The only drawback of this is that the extension is not visible during editing, but that would require an implementation that is a bit more complex than that, as QLineEdit (the default editor for string values of a delegate) doesn't provide such behavior.

musicamante
  • 41,230
  • 6
  • 33
  • 58
  • If extension will not visible thats okay no problem. And Can you elaborate ur code how to use those 2 methods and change stylesheet like background,border etc.of this editor.?And also I need a signal when editing finished. – Hacker6914 Feb 17 '21 at 16:54
  • 1
    @Hacker6914 just use `editor.setStyleSheet()` in `setEditorData()`. – musicamante Feb 17 '21 at 16:59
  • Oh.I see,those two methods are overrided.that I was wondering how it is being called. – Hacker6914 Feb 17 '21 at 17:15
  • 1
    Overridden methods are functions called from the instance or any object that uses it. In the case of a delegate, it's the view (your `self.tree` instance of QTreeWidget) that calls them when an item is being edited; you can see all methods in the [QStyledItemDelegate](https://doc.qt.io/qt-5/qstyleditemdelegate.html) docs: `createEditor()` creates the editor for the index, `setEditorData()` actually sets the editor data (and it's important that those two aspects are separated), and finally `setModelData()` sets the data back to the model when editing is finished. – musicamante Feb 17 '21 at 17:38
  • I marked ur answer as Acceted Answer. Thank u. One more question- how to get a signal when text is edited?like QLineedit has textedited,editingfinished like signals – Hacker6914 Feb 17 '21 at 18:05
  • @Hacker6914 what do you need that for? – musicamante Feb 17 '21 at 18:10
  • this method is used for visual only.but behind the scene i also need to rename the file.suppose i listed a directory in treewidget when one rename here ,at the same time original file also has to be renamed.so i need a signal,otherwise how can i do that behind – Hacker6914 Feb 17 '21 at 18:16
  • @Hacker6914 that has nothing to do with the delegate's editor (nor it should): if you're using a QFileSystemModel, you should ensure that you called [`setReadOnly(False)`](https://doc.qt.io/qt-5/qfilesystemmodel.html#readOnly-prop), otherwise if you're using a custom model, you need to correctly implement `setData(index, value, role=QtCore.Qt.EditRole)` in it: the delegate's `setModelData()` is what takes (and always should take) care of that, since it's what actually calls the model's `setData()`. – musicamante Feb 17 '21 at 18:22
  • that setData() will automatically rename the file?cause i am using treewidget i manually entered data and its properties like size,type,datemodified into tree. i want signal like editing done(says) as same as inbuilt clicked/doubleclicked signals.Is there any inbuilt signal which will notify after editing? like i found https://doc.qt.io/qt-5/qtreewidget.html#itemChanged – Hacker6914 Feb 17 '21 at 18:40
  • 1
    Sorry, I just realized that you're using a QTreeWidget. You could try to connect to the [`itemChanged`] signal **after** creating the tree structure, but, the reality is that it would only make things more ugly and buggy. The *good* suggestion would be to implement your own tree structure, the *easier* one is to use a subclass of QStandardItemModel (and implement its `setData()`); in both cases, you need to use QTreeView, not QTreeWidget. – musicamante Feb 17 '21 at 18:50
  • yes,i checked that is the correct signal what i have searched for.I need to use `self.tree.itemChanged.connect(self.somemethod) and method will will have 2 parameter 1.item 2. columnn and then i have to use in that method item.text(column no.) to get the edited text of that column.` – Hacker6914 Feb 17 '21 at 19:00