Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

PyQt4 - How can I store the value of a QTableWidget cell before cellChanged signal is emitted



  • I am writing a program that uses QTableWidget as a front-end for an sqlite database.

    When any cell of the table is changed, it emits a cellChanged signal that updates the database.

    However, I now need to check the new value of the cell against a variable that is stored in the program, and if it goes through, the new value is approved, but if it doesn't, the old value of the cell is restored.

    Here is an example code of what I want to do:

    #!/usr/bin/python3
    import sys
    from PyQt4 import QtCore, QtGui
    
    app = QtGui.QApplication(sys.argv)
    
    table = QtGui.QTableWidget()
    
    def update_db(row, col):
        old_value = SOME_WAY_TO_STORE_THE_OLD_VALUE_OF_THE_CELL
    
        new_value = table.item(row, col).text()
    
        if new_value == VARIABLE:
            pass
        else:
            table.item(row, col).setText(old_value)
    
    table.cellChanged.connect(update_db)
    
    table.show()
    
    sys.exit(app.exec_())
    

    I have found this solution, which relies on subclassing the QStandardItemModel to store the old value of an item in a QTreeView. This would work with the QTableView as well.

    But this solution doesn't work with the QTableWidget, because its setModel() function is a private method, not public.

    The problem is, going back to use the QTableView is going to waste a lot of time for me, as I have already used QTableWidget in a lot of parts of the program.

    One workaround that solves the problem for me in all but one case is using the currentCellChanged signal to call a function that stores the cell's value. This relies on the fact that the user will need to navigate to the cell to be able to change its value.

    However, this won't work if the user decides to change the cell that is already selected.

    Is there a way for me to achieve what I want without going back and replacing all instances of QTableWidget with QTableView.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    So basically, your user can only change to that variable value or keep the current, correct ?



  • Hi @SGaist.. Thank you very much.

    The user isn't even changing to the variable value. I used this bit if new_value == VARIABLE: in the original post just as an example, because I didn't think it will make much difference.

    Seeing that it might do, let me explain more explicitly what I need to do. Initially, when the user inputs the very first data into the cell, as I said, the database is updated, and a file is created named exactly as the text that the user entered.

    Therefore, when the user wants to change that cell again, I would like to show a QMessageBox that confirms if the user actually wants that change or not.

    The variable I mentioned in the original post is basically the user's response to the message box.

    If the user confirms the change, then the original file will be deleted, the new value will be kept, and a new file will be created.

    But if the user doesn't actually want the change to happen, then the old value will be restored.

    So, a more accurate example code would be something like that:

    if user_input == 'yes':
            pass
    else:
            table.item(row, col).setText(old_value)
    

    I hope this clarifies my intent and sorry for any confusion I might have caused.


  • Lifetime Qt Champion

    Then it sounds like you should implement a custom QStyledItemDelegate, do your validation in the setModelData.



  • Thanks for the help @SGaist.. any ideas where I can find good examples of how to use the QStyledItemDelegate with the QTableWidget, as I can't seem to find any.

    Also, someone on StackOverflow suggested implementing an Undo/Redo framework and using it to restore the original value. However, I am not sure if that would work well with what I want to do.

    What do you think?



  • I keep finding examples of how to customize the QStyledItemDelegate, but they are all in c++, and frankly, I know nothing about c++.

    This example, for instance, goes into creating a custom delegate and overriding the setModelData(), but I am not able to translate it into PyQt.

    All I can find is the PyQt class references which, of course, do not explain how to use the delegates in a real scenario.


  • Lifetime Qt Champion

    It's essentially the same, most of the time you have some translation to do from one language to the other, but the logic is exactly the same.


Log in to reply