Arrow
Arrow12 січня 2017 р. 13:53

Отслеживание нажатия клавиш в QTableView

keyPressEvent, QTableView

Подскажите как можно в QTableView реализовать отслеживание нажатия клавиш.

Версия Qt 5.7.

Для решения задачи решил наследоваться от QTableView и переопределить метод keyPressEvent. ниже привожу свой код и подробное описание, что делал.

Файл mtableview.h:

#ifndef MTABLEVIEW_H
#define MTABLEVIEW_H

#include <QObject>
#include <QTableView>
#include <QKeyEvent>

class QTableViewPrivate;

class MTableView : public QTableView
{
public:
    MTableView(QWidget *parent = 0);
    MTableView(QTableViewPrivate &d, QWidget *parent);
signals:
    void keyPressEvent(QKeyEvent *event);
};

#endif // MTABLEVIEW_H

Файл mtableview.cpp:

#include "mtableview.h"

MTableView::MTableView(QWidget *parent):
    QTableView(parent)
{ }

MTableView::MTableView(QTableViewPrivate &d, QWidget *parent)
    : QTableView(d, parent)
{ }

void MTableView::keyPressEvent(QKeyEvent *event)
{
    QTableView::keyPressEvent(event);
}

После чего в дизайнере для элемента QTableView на форме указал "Преобразовать в" и указал свой класс MTableView (все работает)

Ошибки начались при реализации метода keyPressEvent в программе:

connect(ui->lView, &MTableView::keyPressEvent, this, &Wnd::keyPressEvent);
void Wnd::keyPressEvent(QKeyEvent *event)
{
    if(event->key() == Qt::Key_Return)
    {
        on_lView_doubleClicked(ui->lView->currentIndex());
    }
}

Выдает ошибки:

/gcc_64/include/QtCore/qobject.h:-1: In instantiation of 'static QMetaObject::Connection QObject::connect(const typename QtPrivate::FunctionPointer<Func>::Object*, Func1, const typename QtPrivate::FunctionPointer<Func2>::Object*, Func2, Qt::ConnectionType) [with Func1 = void (MTableView::*)(QKeyEvent*); Func2 = void (FManagerWnd::*)(QKeyEvent*); typename QtPrivate::FunctionPointer<Func>::Object = MTableView; typename QtPrivate::FunctionPointer<Func2>::Object = FManagerWnd]':

/gcc_64/include/QtCore/qglobal.h:746: ошибка: static assertion failed: No Q_OBJECT in the class with the signal
 #define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
                                               ^

/gcc_64/include/QtCore/qobject.h:226: in expansion of macro 'Q_STATIC_ASSERT_X'
         Q_STATIC_ASSERT_X(QtPrivate::HasQ_OBJECT_Macro<typename SignalType::Object>::Value,
         ^

Не могу разобраться, что не так.

P.S. Извините за столько текста :)

Рекомендуємо хостинг TIMEWEB
Рекомендуємо хостинг TIMEWEB
Стабільний хостинг, на якому розміщується соціальна мережа EVILEG. Для проектів на Django радимо VDS хостинг.

Вам це подобається? Поділіться в соціальних мережах!

6
Evgenii Legotckoi
  • 12 січня 2017 р. 13:59

А вот тут Вы сударь пролетели неплохо.

keyPressEvent - это метод события. А Вы его как сигнал определяете в заголовочном файле mtableview.h . Да ещё и подключаете его опять же к методу keyPressEvent

В общем нельзя так, keyPressEvent - это не сигнал и не слот, к нему коннект никаким боком не прикрутишь. Нужно объявлять свои сигналы и слоты для передачи инфы между объектами. А в этом методе можно только ловить события, которые прилетают из приложения через event`ы

    Arrow
    • 12 січня 2017 р. 14:16

    Хорошо, только я не пойму как именно это реализовать. Основное это не могу понять как свой сигнал заставить срабатывать при нажатии клавиши.

      Evgenii Legotckoi
      • 12 січня 2017 р. 23:17
      • Відповідь була позначена як рішення.

      Из того, что я вижу в коде, можно сделать следующие выводы о том, как это дело можно реализовать.

      А именно, объявить сигнал, который будет испускаться при нажатий клавиш в таблице. И объявить слот в классе Wnd , который уже будет принимать этот сигнал.

      Файл mtableview.h:
      #ifndef MTABLEVIEW_H
      #define MTABLEVIEW_H
      
      #include <QObject>
      #include <QTableView>
      #include <QKeyEvent>
      
      class QTableViewPrivate;
      
      class MTableView : public QTableView
      {
      public:
          MTableView(QWidget *parent = 0);
          MTableView(QTableViewPrivate &d, QWidget *parent);
      signals:
          void keyReturnPressed();
      protected:
          virtual void keyPressEvent(QKeyEvent *event) override;
      };
      
      #endif // MTABLEVIEW_H
      
      Файл mtableview.cpp:
      #include "mtableview.h"
      
      MTableView::MTableView(QWidget *parent):
          QTableView(parent)
      { }
      
      MTableView::MTableView(QTableViewPrivate &d, QWidget *parent)
          : QTableView(d, parent)
      { }
      
      void MTableView::keyPressEvent(QKeyEvent *event)
      {
          if(event->key() == Qt::Key_Return)
          {
              emit keyReturnPressed();
          }
          QTableView::keyPressEvent(event);
      }
      

      В заголовочном файле Wnd необходимо объявить слот, который уже примет этот сигнал от таблицы.

      public slots:
          void slotKeyReturnPressed();
      

      В файле cpp написать реализацию этого слота.

      void Wnd::slotKeyReturnPressed()
      {
          // ToDo something
      }
      

      И подключить сигнал к слоту

      connect(ui->lView, &MTableView::keyReturnPressed, this, &Wnd::slotKeyReturnPressed);
      

      Ну и почитайте на досуге вот эту статью про сигналы и слоты в Qt5

        Arrow
        • 13 січня 2017 р. 15:13

        Спасибо. Статья хорошая, я ее как-то пропустил :) .

        Решение немного подкорректировал так:

        В классе наследнике:

        void MTableView::keyPressEvent(QKeyEvent *event)
        {
            if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Backspace || event->key() == Qt::Key_Tab)
            {
                emit keyPressed(event);
            }
            QTableView::keyPressEvent(event);
        }
        

        И далее:

        connect(ui->lTableView, &MTableView::keyPressed, this, &Wnd::keyPress);
        
        void Wnd::keyPress(QKeyEvent *event)
        {
            if(event->key() == Qt::Key_Return)
            {
                on_lTableView_doubleClicked(ui->lTableView->currentIndex());
            }
            else if(event->key() == Qt::Key_Backspace)
            {
                on_lPushButton_clicked();
            }
            else
            {
                ui->lBit->setFocus();
            }
        }
        

        Спасибо за помощь!

          Evgenii Legotckoi
          • 14 січня 2017 р. 01:24

          Не нравится мне ваш вариант кода ))) Давайте сразу приведём его в более грамотный вид:

          void MTableView::keyPressEvent(QKeyEvent *event)
          {
              switch (event->key()) 
              {
              case Qt::Key_Return:
              case Qt::Key_Backspace:
              case Qt::Key_Tab:
                  emit keyPressed(event);
                  break;
              default:
                  break;
              }
              QTableView::keyPressEvent(event);
          }
          

          И далее:

          connect(ui->lTableView, &MTableView::keyPressed, this, &Wnd::keyPress);
          
          void Wnd::keyPress(QKeyEvent *event)
          {
              switch (event->key()):
              {
              case Qt::Key_Return:
                  on_lTableView_doubleClicked(ui->lTableView->currentIndex());
                  break;
              case Qt::Key_Backspace:
                  on_lPushButton_clicked();
                  break;
              default:
                  ui->lBit->setFocus();
                  break;
              }
          }
          

          А теперь, чем мой вариант лучше:

          1. В данном случае метод key() вызывается всего один раз, в вашем коде он вызывается каждый раз при каждом условии.
          2. Конструкция switch case как правило разворачивается компилятором в более эффективный ассемблерный код. К сожалению я не могу привести статью в подтверждение своих слов, но на хабре такая статья есть, просто я её уже забыл. Где разбирается этот момент.
          3. В условии проверяются enum константы, которые традиционно проверяются через switch case
          4. Сама по себе конструкция switch case является более прозрачной для понимания, чем if else
            Arrow
            • 14 січня 2017 р. 05:46

            Спасибо большое!

            Статьи такой не встречал, попробую найти. /p>

            Согласен ваш вариант более читабельнее и понятнее, к тому же выглядит элегантнее.

              Коментарі

              Only authorized users can post comments.
              Please, Log in or Sign up
              sf

              C++ - Тест 004. Указатели, Массивы и Циклы

              • Результат:90бали,
              • Рейтинг балів8
              МВ

              Qt - Тест 001. Сигналы и слоты

              • Результат:68бали,
              • Рейтинг балів-1
              ЛС

              C++ - Тест 001. Первая программа и типы данных

              • Результат:53бали,
              • Рейтинг балів-4
              Останні коментарі
              A
              ALO1ZE19 жовтня 2024 р. 08:19
              Читалка файлів fb3 на Qt Creator Подскажите как это запустить? Я не шарю в программировании и кодинге. Скачал и установаил Qt, но куча ошибок выдается и не запустить. А очень надо fb3 переконвертировать в html
              ИМ
              Игорь Максимов05 жовтня 2024 р. 07:51
              Django - Урок 064. Як написати розширення для Python Markdown Приветствую Евгений! У меня вопрос. Можно ли вставлять свои классы в разметку редактора markdown? Допустим имея стандартную разметку: <ul> <li></li> <li></l…
              d
              dblas505 липня 2024 р. 11:02
              QML - Урок 016. База даних SQLite та робота з нею в QML Qt Здравствуйте, возникает такая проблема (я новичок): ApplicationWindow неизвестный элемент. (М300) для TextField и Button аналогично. Могу предположить, что из-за более новой верси…
              k
              kmssr08 лютого 2024 р. 18:43
              Qt Linux - Урок 001. Автозапуск програми Qt під Linux как сделать автозапуск для флэтпака, который не даёт создавать файлы в ~/.config - вот это вопрос ))
              АК
              Анатолий Кононенко05 лютого 2024 р. 01:50
              Qt WinAPI - Урок 007. Робота з ICMP Ping в Qt Без строки #include <QRegularExpressionValidator> в заголовочном файле не работает валидатор.
              Тепер обговоріть на форумі
              J
              JacobFib17 жовтня 2024 р. 03:27
              добавить qlineseries в функции Пользователь может получить любые разъяснения по интересующим вопросам, касающимся обработки его персональных данных, обратившись к Оператору с помощью электронной почты https://topdecorpro.ru…
              ИМ
              Игорь Максимов03 жовтня 2024 р. 04:05
              Реализация навигации по разделам Спасибо Евгений!
              JW
              Jhon Wick01 жовтня 2024 р. 15:52
              Indian Food Restaurant In Columbus OH| Layla’s Kitchen Indian Restaurant If you're looking for a truly authentic https://www.laylaskitchenrestaurantohio.com/ , Layla’s Kitchen Indian Restaurant is your go-to destination. Located at 6152 Cleveland Ave, Colu…
              КГ
              Кирилл Гусарев27 вересня 2024 р. 09:09
              Не запускается программа на Qt: точка входа в процедуру не найдена в библиотеке DLL Написал программу на C++ Qt в Qt Creator, сбилдил Release с помощью MinGW 64-bit, бинарнику напихал dll-ки с помощью windeployqt.exe. При попытке запуска моей сбилженной программы выдаёт три оши…
              F
              Fynjy22 липня 2024 р. 04:15
              при создании qml проекта Kits есть но недоступны для выбора Поставил Qt Creator 11.0.2. Qt 6.4.3 При создании проекта Qml не могу выбрать Kits, они все недоступны, хотя настроены и при создании обычного Qt Widget приложения их можно выбрать. В чем может …

              Слідкуйте за нами в соціальних мережах