如何在QML中模拟鼠标点击?

时间:2011-09-22 15:51:00

标签: qt events onclick mouse qml

我正在尝试向当前显示的QML对象发送QMouseEventQApplication::sendEvent()始终返回false,表示我的事件未得到处理;但我不明白为什么。
也许我将事件发送到错误的对象?我应该把它寄到哪里? 我也玩QGraphicsSceneMouseEvent而不是QMouseEvent,但也没有运气。

我尝试使用调试器逐步调试事件代码,但对我来说太复杂了,看不出它为什么不起作用。

背景

我正在开发一款可以通过简单的触摸屏控制的软件。我通过以太网获得触摸事件,我想从它们合成鼠标点击事件。 这样,软件将以与开发者PC上相同的方式在目标设备上进行控制。

更新

  1. 如fejd所述,点击代码在QApplication::Exec()之前执行,因此我将其移至计时器处理程序中,该处理程序将在exec()运行时触发。
  2. 添加了按预期工作的特定于Windows的代码。
  3. 在Qt中添加了一些尝试,无论sendEvent()是否返回truefalse,都无效。
  4. 到目前为止,我有这个:

    的main.cpp

    #include <QtGui/QApplication>
    #include "qmlapplicationviewer.h"
    
    #include "clicksimulator.h"
    
    #include <QTimer>
    
    int main(int argc, char *argv[])
    {
        QApplication app(argc, argv);
    
        QmlApplicationViewer viewer;
        viewer.setOrientation(QmlApplicationViewer::ScreenOrientationAuto);
        viewer.setMainQmlFile(QLatin1String("qml/qmlClickSimulator/main.qml"));
        viewer.showMaximized();
    
        ClickSimulator sim(&viewer);
        QTimer timer;
        sim.connect(&timer, SIGNAL(timeout()), SLOT(click()));
        timer.start(100);
    
        return app.exec();
    }
    

    clicksimulator.h

    #ifndef CLICKSIMULATOR_H
    #define CLICKSIMULATOR_H
    
    #include <QObject>
    
    class QmlApplicationViewer;
    
    class ClickSimulator : public QObject
    {
        Q_OBJECT
        QmlApplicationViewer* m_viewer;
    public:
        explicit ClickSimulator(QmlApplicationViewer* viewer, QObject *parent = 0);
    
    public slots:
        void click();    
    };
    
    #endif // CLICKSIMULATOR_H
    

    clicksimulator.cpp

    #include "clicksimulator.h"
    #include "qmlapplicationviewer.h"
    
    #include <QMouseEvent>
    #include <QDebug>
    #include <QGraphicsSceneMouseEvent>
    #include <QApplication>
    #include <QGraphicsScene>
    #include <QTest>
    
    #define _WIN32_WINNT 0x0501
    #define WINVER 0x0501
    #include "Windows.h"
    
    
    ClickSimulator::ClickSimulator(QmlApplicationViewer* viewer, QObject *parent) :
    QObject(parent)
    , m_viewer(viewer)
    {
    }
    
    void ClickSimulator::click()
    {
        if (NULL != m_viewer)
        {
            const int x = qrand() % 500 + 100, y = qrand() % 500 + 100;
    
            {
               QMouseEvent pressEvent(QEvent::MouseButtonPress, QPoint(x, y), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
    //            QMouseEvent pressEvent(
    //                QEvent::MouseButtonPress, 
    //                QPoint(x, y),
    //                Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
               const bool isSent = QApplication::sendEvent(m_viewer->scene(), &pressEvent);
               qDebug() << "'Press' at (" << x << "," << y << ") successful? " << isSent;
            }
    
            {
                QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
                pressEvent.setScenePos(QPointF(x, y));
                pressEvent.setButton(Qt::LeftButton);
                pressEvent.setButtons(Qt::LeftButton);
    
                QGraphicsItem* item = m_viewer->itemAt(x, y);
                const bool isSent = m_viewer->scene()->sendEvent(item, &pressEvent);
                //const bool isSent = QApplication::sendEvent(m_viewer->scene(), &pressEvent);
                qDebug() << "'Press' at (" << x << "," << y << ") successful? " << isSent;
            }
    
            // This platform specific code works...
            {
                const double fScreenWidth = ::GetSystemMetrics( SM_CXSCREEN )-1; 
                const double fScreenHeight = ::GetSystemMetrics( SM_CYSCREEN )-1; 
                const double fx = x*(65535.0f/fScreenWidth);
                const double fy = y*(65535.0f/fScreenHeight);
    
                INPUT inp[3];
                inp[0].type = INPUT_MOUSE;
    
                MOUSEINPUT & mi = inp[0].mi;
                mi.dx = fx;
                mi.dy = fy;
                mi.mouseData = 0;
                mi.dwFlags = MOUSEEVENTF_MOVE | MOUSEEVENTF_ABSOLUTE;
                mi.time = 0;
                mi.dwExtraInfo = 0;
    
                inp[1] = inp[0];
                inp[1].mi.dwFlags = MOUSEEVENTF_LEFTDOWN;
    
                inp[2] = inp[0];
                inp[2].mi.dwFlags = MOUSEEVENTF_LEFTUP;
    
                SendInput(3, inp, sizeof(INPUT));
            }
        }
    }
    

    main.qml

    import QtQuick 1.0
    
    Rectangle {
        width: 360
        height: 360
        Text {
            id: text1
            text: qsTr("This text is placed at the click coordinates")
        }
    
        MouseArea {
            id: mousearea1
            anchors.fill: parent
            onClicked: {
            console.log("click at " + mouse.x + ", " + mouse.y);
                text1.pos.x = mouse.x;
                text1.pos.y = mouse.y;
            }
        }
    }
    

    输出

    'Press' at ( 147 , 244 ) successful?  false 
    'Press' at ( 147 , 244 ) successful?  true 
    

2 个答案:

答案 0 :(得分:10)

由于您在app.exec()之前发送事件,我认为主事件循环尚未启动。您可以尝试使用postEvent,但如果exec()在启动之前清除事件队列,则可能会失败。在这种情况下,也许你可以在exec()之后的某个地方发布它?

更新:通过查看QDeclarativeMouseArea autotests,立即开始工作。缺少的是发布活动。这对我有用:

QGraphicsSceneMouseEvent pressEvent(QEvent::GraphicsSceneMousePress);
pressEvent.setScenePos(QPointF(x, y));
pressEvent.setButton(Qt::LeftButton);
pressEvent.setButtons(Qt::LeftButton);
QApplication::sendEvent(m_viewer->scene(), &pressEvent);

QGraphicsSceneMouseEvent releaseEvent(QEvent::GraphicsSceneMouseRelease);
releaseEvent.setScenePos(QPointF(x, y));
releaseEvent.setButton(Qt::LeftButton);
releaseEvent.setButtons(Qt::LeftButton);
QApplication::sendEvent(m_viewer->scene(), &releaseEvent);

有点奇怪的是,在发布事件后,QML文件中的onPressed没有被调用 - 只有在发布了发布事件之后。

答案 1 :(得分:0)

接受的答案有效,但有更好的方法。只需使用QGraphicScene

即可
bool sendEvent(QGraphicsItem* item, QEvent* event)

功能。如果您知道将事件发送到哪个项目。