Artem072
Artem072

Reputation: 133

How to implement buttons in a delegate PyQt

I am making a program for translating text (see screenshot)

screenshot

I have three classes

class for displaying a window that edits item :

class StyleDelegate(QStyledItemDelegate):
        def __init__(self, parent=None):
            super(StyleDelegate, self).__init__()
        def createEditor(self, widget, style, index):
            self.mainWidget = QWidget(widget)
            self.line = QLineEdit() # line for input text 
            self.delButton= QPushButton('❌')  # button for delete current item
            self.trnButton = QPushButton('➕')  # button for make translation text in another QListView
            self.qhbLayout = QHBoxLayout()
            self.qhbLayout.addWidget(self.line)
            self.qhbLayout.addWidget(self.delButton)
            self.qhbLayout.addWidget(self.trnButton)
            self.mainWidget.setLayout(self.qhbLayout)
            return self.mainWidget
        # there is still a lot of code in this place

class for storing, adding, deleting and editing data:

    class TranslateListModel(QAbstractListModel):
        def __init__(self, parent=None):
            super(TranslateListModel, self).__init__()
            self.words = ['1', '2', '3', '4']

        def removeItem(self, index):
            self.beginRemoveRows(index, index.row(), index.row())
            del self.words[index.row()]
            self.endRemoveRows()
            return True
        # there is still a lot of code in this place

main class of the program:

class QTranslate(QtWidgets.QDialog, log.Ui_Dialog):
     def __init__(self):
        super().__init__()
        self.originalModel = TranslateListModel() 
        self.translateModel = TranslateListModel() 

        self.styleDelegate = StyleDelegate()

        self.originalLV.setModel(self.originalModel) 
        #QListView from Ui_Dialog

        self.translateLV.setModel(self.translateModel)
        #QListView from Ui_Dialog

        self.originalLV.setItemDelegate(self.styleDelegate)
        self.translateLV.setItemDelegate(self.styleDelegate)
    # there is still a lot of code in this place

How to implement buttons to delete the current item and change the translation in another QListView using QStyledItemDelegate? I cannot access these buttons outside the StyleDelegate class to associate them with the methods of the TranslateListModel class.

Upvotes: 0

Views: 1475

Answers (1)

musicamante
musicamante

Reputation: 48384

A possible solution is to create signals for the delegate and connect them to the functions that will delete or add items, then emit those signals when the buttons are clicked:

class StyleDelegate(QStyledItemDelegate):
    deleteRequested = QtCore.pyqtSignal(int)
    translateRequested = QtCore.pyqtSignal(int)

    def __init__(self, parent=None):
        super(StyleDelegate, self).__init__()
    def createEditor(self, widget, style, index):
        # note: I removed the "self" references as they're unnecessary
        mainWidget = QWidget(widget)
        line = QLineEdit()
        delButton= QPushButton('❌')
        trnButton = QPushButton('➕')
        qhbLayout = QHBoxLayout()
        qhbLayout.addWidget(line)
        qhbLayout.addWidget(delButton)
        qhbLayout.addWidget(trnButton)
        mainWidget.setLayout(qhbLayout)
        delButton.clicked.connect(
            lambda _, row=index.row(): self.deleteRequested.emit(row))
        trnButton.clicked.connect(
            lambda _, row=index.row(): self.translateRequested.emit(row))
        return mainWidget


class QTranslate(QtWidgets.QDialog, log.Ui_Dialog):
    def __init__(self):
        # ...
        self.originalLV.setItemDelegate(self.styleDelegate)
        self.styleDelegate.deleteRequested.connect(self.deleteRow)
        self.styleDelegate.translateRequested.connect(self.translateRow)

    def deleteRow(self, row):
        # ...

    def translateRow(self, row):
        # ...

Note that you should always use an unique delegate instance for each view, as explained in the documentation:

Warning: You should not share the same instance of a delegate between views. Doing so can cause incorrect or unintuitive editing behavior since each view connected to a given delegate may receive the closeEditor() signal, and attempt to access, modify or close an editor that has already been closed.

Upvotes: 1

Related Questions