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

How to catch key presses in editable QTableWidgetItem?

现在我可以在函数 eventFilter() 中处理 QTableWidget 中的所有按键(在构造函数中调用 myTable->viewport()->installEventFilter(this); 之后)。

唯一不起作用的地方是编辑时的 editable 单元格(因为它抓住了所有按键)。要修复它,我不能为 table 中的每个项目调用 installEventFilter(),因为这些项目不是 QObject(而且我不能使用 connect 来放置我对按键的处理)。

我唯一的解决办法是在这些单元格中放入 QLineEdits 并在编辑时使用事件过滤器捕捉按键。但是是否可以仅使用标准项目来解决它? (即只有 QTableWidgetItem 带有标志 Qt::ItemIsEditable

我也可以为我的 QTableWidget 打电话 grabKeyboard()。在这种情况下,我将按下所有按键(即使在用户编辑单元格时),但它会阻止编辑框(即用户无法输入任何内容)。在为 table?

调用 grabKeyboard() 后,是否可以修复损坏的编辑框

由于 QTableWidgetItem 没有可以重载的函数 keyEvent(),因此这是不可能的。

您需要做的是设置一个带有自定义编辑器工厂的委托,该工厂在 keyEvent 过载的情况下生成小部件。

这很容易实现。只需 subclass 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 替换委托。

或者更好的是 subclass 创建代理 class 接受原始 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. 

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

不是真的。在 Qt4 中 QTableWidget 从单元格编辑器中泄漏 KeyRelease 事件,但利用它会是一个丑陋的 hack。

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

我曾经尝试这样做,然后将事件发布到 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);
}

另一种选择:

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

您只需:

qApp->installEventFilter(this);

并且:

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