如何在可编辑的QTableWidgetItem中捕获按键?

5
现在我可以在eventFilter()函数中处理QTableWidget中的所有按键(在构造函数中调用myTable->viewport()->installEventFilter(this)之后)。
唯一不能正常工作的地方是当编辑可编辑单元格时,它将捕获所有按键。为了解决这个问题,我不能为表中的每个项目调用installEventFilter(),因为这些项目不是QObject(并且我也无法使用connect来处理按键事件)。
我唯一的解决办法是在这些单元格中放置QLineEdit,并使用事件过滤器在编辑时捕获按键事件。但是是否可能仅使用标准项目来解决它?(即仅使用带有标志Qt::ItemIsEditableQTableWidgetItem
此外,我可以为我的QTableWidget调用grabKeyboard()。在这种情况下,我将获得所有按键(即使用户正在编辑单元格),但它会阻止编辑框(即用户无法输入任何内容)。或许可以在为表格调用grabKeyboard()之后修复破碎的编辑框?

你能否实现另一个类,继承QTableWidgetItem,以便拥有所有QTableWidgetItem的函数和你自己的函数,从而获得所需的行为? - IAmInPLS
是的,我可以实现另一个类,但我不明白如何在这种情况下重写按键处理。 - Ilya
因为它捕获了所有按键操作,但你可以获取到释放的按键。不知道是什么在进行捕获。也许有一个很好的原因? - spinkus
@S.Pinkus 的梦想是静默地捕获按键(即在可编辑单元格中不中断现有进程)。而关于 grabKeyboard() 的那些话只是为了解释为什么我认为可以解决这个问题。 - Ilya
4个回答

2
这个很容易实现。只需要继承 QStyledItemDelegate 并重写 createEditor 方法,就像这样:

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;
}

替换代理以适应您的QTableWidget。

或者更好的方法是,而不是子类化,创建一个接受原始QAbstractItemDelegate的代理类(需要更多编写,但更加通用,并且可以与其他修改组合使用)。

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. 

1
但仅使用标准项(即仅使用带有Qt :: ItemIsEditable标志的QTableWidgetItem)解决它是否可能?实际上不行。在Qt4中,QTableWidget从单元格编辑器泄漏KeyRelease事件,但利用这一点将是一个丑陋的hack。
也许可以在为表格调用grabKeyboard()后修复损坏的编辑框吗?
我曾尝试过这样做,然后将事件发布到QTableWidget中,但也遇到了麻烦。
正确的做法是创建自己的委托并在createEditor函数中安装事件过滤器。您可以像这样做:
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;
};

那么你的 MainWindow 构造函数应该长这样:

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

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

你的事件过滤器:

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

谢谢。据我所知,tableWidget->installEventFilter(this); 这行代码并不必要。你同意吗? - Ilya
@Ilya,如果你只想捕获单元格编辑器小部件的按键,则是的,你是正确的。 - Super-intelligent Shade
据我所了解,我们需要执行 tableWidget->viewport()->installEventFilter(this); 来捕获此表格中的任何其他按键操作(而不是 tableWidget->installEventFilter(this);)。 - Ilya
当我将其安装在“tableWidget”上时,它对我起作用。您可以尝试两种方法,看哪个有效。 - Super-intelligent Shade

1

另一种选择:

您可以在 QApplication 对象上安装事件过滤器并捕获所有事件。如果您问我,这有点过度,但对于小型应用程序来说,它可以起作用,并且需要最少的代码。

您需要做的就是:

qApp->installEventFilter(this);

并且:

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

1

由于QTableWidgetItem没有可以重载的function keyEvent(),所以这是不可能的。

您需要设置一个代理,使用自定义编辑器工厂来生成重载了keyEvent的小部件。


谢谢您的回答!我并不完全确定是否没有更简单的解决方案。例如,我可以为我的QTableWidget调用grabKeyboard()。这样一来,我就可以获得所有按键(即使用户正在编辑单元格),但是编辑框也将无法按预期工作。 - Ilya

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接