1

I would like to change behavior of Key_Delete for QTableWidget, but because of using Designer I don't want to make any changes in py file with form. So instead of reimplementing QTableWidget like it is this answer: How to implement MousePressEvent for a Qt-Designer Widget in PyQt I do something like this:

class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
    QtGui.QWidget.__init__(self, parent)
    self.ui = Ui_MainWindow()
    self.ui.setupUi(self)

    self.ui.tableWidget.__class__.keyPressEvent = self.test

def test(self,event):
    if event.key() == Qt.Key_Delete:
        print "test"

    return QTableWidget.keyPressEvent(self, event)

The problem is that I don't know how to keep original behavior of other keys than Qt.Key_Delete. I have already changed last line like this:

return QtGui.QTableWidget.keyPressEvent(self, event)
return QtGui.QTableWidget.event(self, event)

but it doesn't work.

Community
  • 1
  • 1
domi
  • 189
  • 1
  • 4
  • 9

1 Answers1

4

First: "but it doesn't work" is usually not descriptive enough. What behavior did you expect? What was the behavior you saw instead? Were there any error messages?

I can easily see a few mistakes in here, though.

  1. You're overriding the method QTableWidget.keyPressEvent, which expects 2 arguments: (QTableWidget instance, event). But in the code you show above, the function you are using to override it only takes 1 argument (the first argument, 'self', does not count since it is automatically supplied).

  2. Since you have set QTableWidget.keyPressEvent = self.test, and you are also trying to call this function from within self.test(), you have created an infinitely recursive function.

  3. When you call QTableWidget.keyPressEvent, the first argument you have passed in (self) is a QMainWindow object. However as I mentioned above, this function expects a QTableWidget as its first argument.

  4. Since you are overriding this method at the class level, ALL QTableWidgets will be forced to use the same keyPressEvent function (this would be very problematic). Instead, you should override just your specific widget's method: self.ui.tableWidget.keyPressEvent = self.test (also note that the signature for tableWidget.keyPressEvent is different from QTableWidget.keyPressEvent)

Example:

from PyQt4 import QtCore, QtGui
app = QtGui.QApplication([])
win = QtGui.QMainWindow()
win.show()

table = QtGui.QTableWidget()
win.setCentralWidget(table)
def test(event):
    if event.key() == QtCore.Qt.Key_Delete:
        print "delete"
    return QtGui.QTableWidget.keyPressEvent(table, event)
table.keyPressEvent = test

Finally, another (possibly cleaner) approach would be to create a subclass of QTableWdget and, within Designer, 'promote' the table widget to your new class.

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Luke
  • 11,374
  • 2
  • 48
  • 61
  • Thank you for your answer! By "but it doesn't work" I meant "I don't know how to keep original behavior of other keys than Qt.Key_Delete". My example, without last return works only with Delete key. So when I press other key in QTableWidget than Delete key nothing happens (the arrow keys don't work). I would like to override this method at the **class** level. So the question is: what should I change in my example code to suppress only Key_Delete event and pass the other events? – domi May 09 '11 at 14:58
  • You can override the class method if you wish, you'll just have to 1) make sure the function you override it with has the correct signature, and 2) store a reference to the original function elsewhere so it can still be called for other keys. I'm curious: why do you want to override at the class level rather than the instance? – Luke May 12 '11 at 15:41
  • Sorry for delay,I wasn't able to comment.Could you tell me how to implement second point using my code?Why override at the class level:two reason-I want to change as minimum as it is possible in code generated by Qt Designer and secondly,I want to "keep" the changed behavior in every QTableWidget I have in my app.I know that is possible with subclassing,but this means extra code and a need of rewriting every properties(set in Qt Designer) from class to subclass. – domi May 28 '11 at 22:37
  • I think you aren't using Designer correctly. There should never be any reason to make changes to the files generated by Designer. What I would do is 1) create a subclass of QTableWidget that includes your event code 2) from within Designer, promote your existing QTableWidgets to the new class. All promoted widgets will use the subclass's event code, and will still have their properties set correctly as specified by Designer. – Luke Jul 03 '11 at 17:11