代码之家  ›  专栏  ›  技术社区  ›  jpo38

无法再从QTreeWidget获取qgest事件

  •  0
  • jpo38  · 技术社区  · 6 年前

    这非常简单,只需创建一个助手来捕获QGesture事件并通知指定的类。

    :

    #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
    

    手势.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);
    }
    

    主控件.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
    

    主控件.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" );
    }
    

    主.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控件 widget->setInputMethodHints( Qt::InputMethodHint::ImhNone ); 但这无助于。。。

    1 回复  |  直到 6 年前
        1
  •  0
  •   jpo38    6 年前

    由于这显然是一个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
    

    :

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

    请注意,事件过滤器必须安装在视口上,而不是小部件本身。