Search code examples
pythonpyqtpyqt4qtablewidget

How to protect the cells changing in tablewidget when using itemdelegate and signal from liswidget?


I have the code where i can start editing cell in tablewidget and double click on names in list widget to add it to the cell. But when I do this on second cell both the cells are changing .How to protect cell from changing, the code is as follows

from functools import partial
from PyQt4 import QtCore, QtGui


class StyledItemDelegate(QtGui.QStyledItemDelegate):
    textChanged = QtCore.pyqtSignal(int, int, str)
    #editingFinished = QtCore.pyqtSignal()

    def createEditor(self, parent, option, index):
        editor = super(StyledItemDelegate, self).createEditor(
            parent, option, index
        )
        if isinstance(editor, QtGui.QLineEdit):
            editor.textChanged.connect(
               partial(self.textChanged.emit, index.row(), index.column())
            )
            #editor.editingFinished.connect(self.editingFinished)
        return editor


class Widget(QtGui.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.table_widget = QtGui.QTableWidget(4, 4)
        self.table_widget.setHorizontalHeaderLabels(("Name", "1", "2", 
                      "3"))
        delegate = StyledItemDelegate(self.table_widget)
        delegate.textChanged.connect(self.filter)
        #delegate.editingFinished.connect(self.clear_filter)
        self.table_widget.setItemDelegate(delegate)

        self.list_widget = QtGui.QListWidget()



        hlay = QtGui.QHBoxLayout(self)
        hlay.addWidget(self.table_widget)
        hlay.addWidget(self.list_widget)

        for letter1 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
            for letter2 in "ABCDEFGHIJKLMNOPQRSTUVWXYZ":
                text = letter1 + letter2
                it = QtGui.QListWidgetItem(text)
                self.list_widget.addItem(it)

    @QtCore.pyqtSlot(int, int, str)
    def filter(self, row, column, text):
        print(row, column)
        self.clear_filter()
        for r in range(self.list_widget.count()):
            it = self.list_widget.item(r)
            # filter algorithm
            is_showing = text in it.text()
            # Hide the row if necessary
            it.setHidden(not is_showing)      
        self.list_widget.itemDoubleClicked.connect(
                           lambda:self.nameselected(row,column))

    @QtCore.pyqtSlot()
    def clear_filter(self):
        for r in range(self.list_widget.count()):
            it = self.list_widget.item(r)
            it.setHidden(False)

    def nameselected(self,row,column):
        name=self.list_widget.currentItem().text()
        print(name,row,column)
        #self.table_Widget.blockSignals(True)
        self.table_widget.setItem(row,column, 
                      QtGui.QTableWidgetItem(name))
        #self.table_Widget.blockSignals(False)

if __name__ == "__main__":
    import sys

    app = QtGui.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

let's assume I entered 'A' in first cell the listwidget has the all the names startiing with 'A' when i double click on 'AA'in listwidget, the first cell has text 'AA'. when i type 'B' in second cell, listwidget has the all the names startiing with 'B' when i double click on 'BA' in listwidget, the second cell should have text'BA'. But here both the cells are set to 'BA'.how to protect other cells from changing.


Solution

  • The problem comes from the fact that you are connecting to the self.nameselected slot each time a new filter is applied. You can easily see it if you change the filter more than once: whenever you double click an item in the list view, it prints the nameselected's slot output more than once.

    You could use try and disconnect the itemDoubleClicked signal each time the filter is applied, but even that is not a good solution (you might need some other connection from that signal).

    Just connect the itemDoubleClicked signal to nameselected in the __init__, and then change that function like this:

    def nameselected(self):
        name=self.list_widget.currentItem().text()
        tableIndex = self.table_widget.currentIndex()
        self.table_widget.setItem(tableIndex(), tableIndex(), 
                      QtGui.QTableWidgetItem(name))
    

    If you don't want to do this (for example, to avoid wrong index if the user has clicked on another item in the table by mistake), just keep an internal reference to the last "edited" item index and use that in the nameselected function.