Как отловить нажатия клавиш в редактируемом QTableWidgetItem?

5

Теперь я могу обрабатывать все нажатия клавиш в моей QTableWidget в функции eventFilter() (после вызова myTable->viewport()->installEventFilter(this); в конструкторе).

Единственное место, где это не работает, - редактируемая ячейка при редактировании (потому что она захватывает все нажатия клавиш). Чтобы исправить это, я не могу вызвать installEventFilter() для каждого элемента таблицы, потому что эти элементы не являются QObject (а также я не могу использовать connect для ввода моей обработки нажатия клавиш).

Единственное решение, которое у меня есть, - это положить QLineEdit в эти ячейки и использовать фильтр событий для захвата нажатия клавиш во время редактирования. Но можно ли разрешить его, используя только стандартные элементы? (т.е. только QTableWidgetItem с флагом Qt::ItemIsEditable)

Также я могу вызвать grabKeyboard() для моего QTableWidget. В этом случае у меня будут все нажатия клавиш (даже при редактировании ячеек пользователем), но он блокирует окно редактирования (т.е. Пользователь не может вводить ничего). Может быть, можно исправить сломанные поля редактирования после вызова grabKeyboard() для таблицы?

  • 0
    Можете ли вы реализовать другой класс, QTableWidgetItem подклассы QTableWidgetItem , чтобы иметь все функции QTableWidgetItem и ваши собственные функции для получения желаемого поведения?
  • 0
    Да, я могу реализовать другой класс, но я не понимаю, как переопределить обработку нажатий клавиш в этом случае.
Показать ещё 2 комментария
Теги:
qt
qtablewidget
qtablewidgetitem

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

Но можно ли его решить, используя только стандартные элементы? (т.е. только QTableWidgetItem с флагом Qt:: ItemIsEditable)

Не совсем. В Qt4 QTableWidget утечка KeyRelease событий из редактора ячейки, но использование этого было бы уродливым взломом.

Может быть, можно исправить сломанные поля редактирования после вызова 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);
}
  • 0
    Спасибо. Насколько я понимаю строка tableWidget->installEventFilter(this); не обязательно. Ты согласен?
  • 0
    @Ilya Илья, если вы хотите захватывать нажатия только из виджетов редакторов ячеек, тогда да, вы правы.
Показать ещё 2 комментария
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 не имеет функции keyEvent(), которую вы можете перегрузить, это невозможно.

Что вам нужно сделать, это установить делегат с настраиваемым редактором factory, который создает виджеты, где keyEvent перегружен.

  • 0
    Спасибо за ваш ответ! Я не совсем уверен, что не существует более простого решения. Например, я могу вызвать grabKeyboard() для моего QTableWidget . После этого у меня будут все нажатия клавиш (даже при редактировании ячеек пользователем), но также и это поле редактирования не будет работать так, как ожидается.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню