5

Now I can process all key presses in my QTableWidget in a function eventFilter() (after calling of myTable->viewport()->installEventFilter(this); in the constructor).

The only place where this doesn't work is editable cell while editing (because it grabs all key presses). To fix it I can't call installEventFilter() for each item in the table, because these items are not QObjects (and also I can't use connect for putting of my processing of key presses).

The only solution I have is to put QLineEdits in these cells and to use event filter to catch key presses while editing. But is it possible to solve it using only standard items? (i.e. only QTableWidgetItem with a flag Qt::ItemIsEditable)

Also I can call grabKeyboard() for my QTableWidget. In this case I'll have all key presses (even while editing of cells by user), but it blocks edit box (i.e. user can't input anything). May be it is possible to fix broken edit boxes after calling of grabKeyboard() for the table?

Ilya
  • 4,583
  • 4
  • 26
  • 51
  • Can you implement another class, subclassing `QTableWidgetItem`, in order to have all the functions of `QTableWidgetItem` and your own functions to get the behavior you want? – IAmInPLS Apr 14 '16 at 10:22
  • Yes, I can implement another class, but I don't understand how to override processing of key presses in this case. – Ilya Apr 14 '16 at 11:07
  • "because it grabs all key presses". You do get key releases though. Wonder what is doing the grabbing. Maybe there is a good reason? – spinkus Apr 19 '16 at 15:31
  • @S.Pinkus The dream was to catch key presses silently (i.e. without breaking of existent processes in editabal cell). And those words about `grabKeyboard()` were only to explain why I expect that it is possible to solve this problem. – Ilya Apr 20 '16 at 07:18

4 Answers4

2

This so quite ease to achieve. Just subclass QStyledItemDelegate override createEditor method like this:

QWidget *AlterEditorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    QWidget *result = QStyledItemDelegate::createEditor(parent, option, index);
    result->installEventFilter(new YourEventFilter(result));
    return result;
}

Than replace delegate for your QTableWidget.

Or even better instead subclassing create proxy class which accepts original QAbstractItemDelegate (more writing but much more universal and can be composed with other modifications).

AlterEditorProxyDelegate::AlterEditorProxyDelegate(QAbstractItemDelegate *original, QObject *parent)
    : QAbstractItemDelegate(parent)
    , original(original)
{}

QWidget *AlterEditorProxyDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    QWidget *result = original->createEditor(parent, option, index);
    result->installEventFilter(new YourEventFilter(result));
    return result;
}

// other methods which invokes respective methods for `original` style. 
Marek R
  • 32,568
  • 6
  • 55
  • 140
1

Since QTableWidgetItem has no function keyEvent() that you can overload this is not possible.

What you have to do is set a delegate with custom editor factory that produces widgets where keyEvent is overloaded.

Goswin von Brederlow
  • 11,875
  • 2
  • 24
  • 42
  • Thank you for your answer! I am not completely sure that there are no simplier solution. For instance, I can call `grabKeyboard()` for my `QTableWidget`. After it I'll have all key presses (even while editing of cells by user), but also that edit box will not work as it is expected. – Ilya Apr 12 '16 at 10:35
1

But is it possible to solve it using only standard items? (i.e. only QTableWidgetItem with a flag Qt::ItemIsEditable)

Not really. In Qt4 QTableWidget leaks KeyRelease events from the cell editor, but exploiting that would be an ugly hack.

May be it is possible to fix broken edit boxes after calling of grabKeyboard() for the table?

I once tried doing that and then posting the events to QTableWidget but ran into trouble as well.

The proper thing to do is to create your own delegate and install event filter in createEditor function. You can do something like this:

class FilterDelegate : public QStyledItemDelegate
{
public:
    FilterDelegate(QObject *filter, QObject *parent = 0) :
        QStyledItemDelegate(parent), filter(filter)
    { }

    virtual QWidget *createEditor(QWidget *parent,
                                  const QStyleOptionViewItem &option,
                                  const QModelIndex &index) const
    {
        QWidget *editor = QStyledItemDelegate::createEditor(parent, option, index);
        editor->installEventFilter(filter);
        return editor;
    }

private:
    QObject *filter;
};

Then your MainWindow constructor would look something like this:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    setupUi(this);

    tableWidget->setItemDelegate(new FilterDelegate(this));
    tableWidget->installEventFilter(this);
}

And your event filter:

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::KeyPress)
    {
        // do something
    }
    return QMainWindow::eventFilter(obj, event);
}
  • Thank you. As far as I understand the line `tableWidget->installEventFilter(this);` is not necessary. Do you agree? – Ilya Apr 20 '16 at 07:41
  • @Ilya, if you only want to capture presses from the cell editors widgets, then yes, you are right. – Super-intelligent Shade Apr 20 '16 at 14:38
  • As far as I understand we need to do `tableWidget->viewport()->installEventFilter(this);` to capture any other key presses in this table (not `tableWidget->installEventFilter(this);`) – Ilya Apr 21 '16 at 10:07
  • It worked for me when I installed it on the `tableWidget`. You can try it both ways and see which one works. – Super-intelligent Shade Apr 21 '16 at 13:52
1

ANOTHER ALTERNATIVE:

You can install event filter on the QApplication object and capture all events. This is a bit of an overkill if you ask me, but it would work for a small application and requires minimal code.

All you have to do is:

qApp->installEventFilter(this);

And:

bool MainWindow::eventFilter(QObject *obj, QEvent *event)
{
    if(event->type() == QEvent::KeyPress)
    {
        // do something
    }
    return QMainWindow::eventFilter(obj, event);
}