Больше не могу получать события QGesture из QTreeWidget - PullRequest
0 голосов
/ 28 января 2019

Эта очень простая программа, которая отлично работала при использовании Qt 5.6 на Android, теперь не работает с Qt 5.12.В Windows он работает с обеими версиями.

Это очень просто, просто создать помощника для перехвата событий QGesture и уведомления указанного класса.

gest.h :

#ifndef RMCWRAPPER_H
#define RMCWRAPPER_H

#include <QObject>
#include <QPoint>

class QWidget;

class TapAndHoldWrapper : public QObject
{
    Q_OBJECT

public:
    TapAndHoldWrapper( QWidget* parent, QObject* receiver = NULL, const char* slot = NULL );
    ~TapAndHoldWrapper();

    bool eventFilter(QObject *obj, QEvent *event);

signals:
    void requested( QPoint globalPos );

private:
    QWidget* m_parent;
};

#endif

gest.cpp :

#include "gesture.h"

#include <QWidget>
#include <QEvent>
#include <QGestureEvent>

TapAndHoldWrapper::TapAndHoldWrapper( QWidget* parent, QObject* receiver, const char* slot ) : 
    QObject( parent ), m_parent( parent )
{
    m_parent->installEventFilter( this );
    m_parent->grabGesture( Qt::TapAndHoldGesture );

    if ( receiver && slot )
    {
        connect( this, SIGNAL(requested(QPoint)), receiver, slot );
    }
}

TapAndHoldWrapper::~TapAndHoldWrapper()
{

}

bool TapAndHoldWrapper::eventFilter(QObject *obj, QEvent *event)
{
    if ( event->type() == QEvent::Gesture && obj == m_parent )
    {
        QGestureEvent *gestevent = static_cast<QGestureEvent *>(event);
        if (QGesture *gest = gestevent->gesture(Qt::TapAndHoldGesture))
        {
            if ( gest && gest->state() == Qt::GestureFinished )
            {
                QPoint globalPos = gest->hotSpot().toPoint();
                emit requested( globalPos );
                return true;
            }
        }
    }
    // standard event processing
    return QObject::eventFilter(obj, event);
}

mainwidget.h :

#ifndef MAINWIDGET_H
#define MAINWIDGET_H

#include <QMainWindow>

class TapAndHoldWrapper;

class MainWidget : public QMainWindow
{
    Q_OBJECT

public:
    MainWidget(QWidget *parent = 0);

public slots:
    void showMenu( QPoint pt );

private:
    TapAndHoldWrapper* helper;
};

#endif

mainwidget.cpp :

#include "mainwidget.h"
#include "gesture.h"

#include <QScreen>
#include <QGuiApplication>
#include <QTreeWidget>
#include <QLabel>
#include <QMessageBox>

MainWidget::MainWidget(QWidget *parent)
    : QMainWindow(parent)
{
    QTreeWidget* widget = new QTreeWidget(this);
    setCentralWidget(widget);

    helper = new TapAndHoldWrapper( widget, this, SLOT(showMenu(QPoint)) );
}

void MainWidget::showMenu( QPoint pt )
{
    QMessageBox::information( this, "", "gesture detected" );
}

main.cpp :

#include "mainwidget.h"

#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    MainWidget w;
    w.show();
    return app.exec();
}

TapAndHoldWrapper, используемый для перехвата события и вызова MainWidget::showMenu.Это больше неОн отлично работает, когда центральным виджетом QMainWindow является QLabel, но не работает, когда он QTreeWidget.

. Журнал сообщает об этой ошибке (впервые в Qt 5.12):

    W/libqtbug_gesture.so(22735): QMetaObject::invokeMethod: No such method
    QTreeWidget::inputMethodQuery(Qt::InputMethodQuery,QVariant)

Есть ли что-то особенное, что нужно сделать для QTreeWidget, чтобы разумно работать с жестами на Android с Qt 5.12?Есть ли что-то особенное, что можно сделать с помощью методов ввода?Я пытался позвонить widget->setInputMethodHints( Qt::InputMethodHint::ImhNone );, но это не помогло ...

1 Ответ

0 голосов
/ 30 января 2019

Поскольку это, по-видимому, ошибка Qt, единственное решение - это обойти ее.Нажатие и удержание можно легко обнаружить, как показано ниже:

жест.ч :

#ifndef RMCWRAPPER_H
#define RMCWRAPPER_H

#include <QObject>
#include <QPoint>
#include <QTime>

class QWidget;

class TapAndHoldWrapper : public QObject
{
    Q_OBJECT

public:
    TapAndHoldWrapper( QWidget* parent, QObject* receiver = NULL, const char* slot = NULL );
    ~TapAndHoldWrapper();

    bool eventFilter(QObject *obj, QEvent *event);

signals:
    void requested( QPoint globalPos );

private:
    QWidget* m_parent;
    QTime m_pressedAt;
    QPoint m_pressedPos;
};

#endif

жест.cpp :

#include "gesture.h"

#include <QWidget>
#include <QEvent>
#include <QGestureEvent>
#include <QAbstractScrollArea>

#if QT_VERSION >= QT_VERSION_CHECK( 5, 12, 0 )
// handle this manually, see https://bugreports.qt.io/browse/QTBUG-73326
#define HANDLE_TAP_AND_HOLD_MANUALLY
#endif

TapAndHoldWrapper::TapAndHoldWrapper( QWidget* parent, QObject* receiver, const char* slot ) : 
    QObject( parent ), 
    m_parent( parent )
{
    // optional in Qt 5.6. Required in Qt 5.12
    QAbstractScrollArea* area = dynamic_cast< QAbstractScrollArea* >( m_parent );
    if ( area )
        m_parent = area->viewport();

    m_parent->installEventFilter( this );

#ifndef HANDLE_TAP_AND_HOLD_MANUALLY
    m_parent->grabGesture( Qt::TapAndHoldGesture );
#endif

    if ( receiver && slot )
    {
        connect( this, SIGNAL(requested(QPoint)), receiver, slot );
    }
}

TapAndHoldWrapper::~TapAndHoldWrapper()
{

}

bool TapAndHoldWrapper::eventFilter(QObject *obj, QEvent *event)
{
#ifdef HANDLE_TAP_AND_HOLD_MANUALLY
    if ( event->type() == QEvent::MouseButtonPress && obj == m_parent )
    {
        QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>( event );
        if ( mouseEvent->button() == Qt::LeftButton )
        {
            m_pressedAt = QTime::currentTime();
            m_pressedPos = mouseEvent->globalPos();
        }
    }
    else if ( event->type() == QEvent::MouseButtonRelease && obj == m_parent )
    {
        QMouseEvent* mouseEvent = dynamic_cast<QMouseEvent*>( event );
        if ( mouseEvent->button() == Qt::LeftButton )
        {
            int elapsed = m_pressedAt.msecsTo( QTime::currentTime() );
            if ( elapsed >= 500 )
            {
                if ( std::abs( m_pressedPos.x() - mouseEvent->globalPos().x() ) < 10 &&
                     std::abs( m_pressedPos.y() - mouseEvent->globalPos().y() ) < 10 )
                {
                    emit requested( mouseEvent->globalPos() );
                }
                // else, mouse moved too much, it's not a tap and 
            }
        }
    }
#else
    if ( event->type() == QEvent::Gesture && obj == m_parent )
    {
        QGestureEvent *gestevent = static_cast<QGestureEvent *>(event);
        if (QGesture *gest = gestevent->gesture(Qt::TapAndHoldGesture))
        {
            if ( gest && gest->state() == Qt::GestureFinished )
            {
                QPoint globalPos = gest->hotSpot().toPoint();
                emit requested( globalPos );
                return true;
            }
        }
    }
#endif

    // standard event processing
    return QObject::eventFilter(obj, event);
}

Обратите внимание, что фильтр событий должен быть установлен в окне просмотра, а не на самом виджете.

...