将键盘事件发送到QML应用程序

时间:2018-01-26 10:24:11

标签: c++ multithreading qt qml qt-signals


我想从一个线程向我的应用程序发送一个Qt :: Key_Left信号。
我尝试使用以下代码发送我的事件,但没有任何反应:
QKeyEvent *event = new QKeyEvent ( QEvent::KeyPress, Qt::Key_Left, Qt::NoModifier); QCoreApplication::sendEvent (app, pressEvent);

实际上,这些函数是从正在侦听端口的线程调用的。这可能是问题是由于主线程没有调用这些函数引起的吗?

我只是让你知道我的应用是QML(不知道它是否有所改变)。我也试过静态函数QCoreApplication::postEvent

提前谢谢你。 对不起我的英语水平。

2 个答案:

答案 0 :(得分:1)

  

不,我没有,我也不知道该怎么做。主线程很忙   使用QGuiApplication :: exec

主线程并未真正锁定,每个事件循环周期之间都有一段时间,它会侦听来自其他线程的事件。

您可以使用QMetaObject::invokeMethod()或通过信号触发插槽,在两种情况下都使用Qt::QueuedConnection,这将使用该监听窗口来安排在下一个事件循环周期中执行的调用。相关的线程。

QCoreApplication::postEvent()应该可以工作,我使用它来发送来自用QML实现的自定义屏幕控制器的事件并且它工作正常,但是QML确实存在于主线程中,所以可能你的问题是你是从另一个线程发送。所以我假设如果您安排通过主线程发送的事件,它将按预期工作。

编辑:

好的,我弄清楚了什么是错的,出于某种原因,将事件发布到核心应用程序实例并不会将其转发到qml引擎和后续的qml对象。但是如果接收器被设置为根qml对象engine->rootObjects().at(0),它可以......有点......

通过Keys.onPressed和类似的方式收到焦点项目的事件,因此如果您需要的话,那么您就已经完成了设置。奇怪的是,如果我使用像TextEdit这样的方法,这种方法并不能将文本写入字段,尽管模拟诸如使用箭头键移动光标之类的东西确实有效。我甚至可以按移位修改器并选择文字。但不写文字......

所以也许它不像预期的那么简单。希望有人能够阐明这个问题。对我来说,这对于Qt来说太常见了,通常非常简单,显然逻辑上的东西最终没有按预期工作或者根本没有工作,因为有一些奇怪的实现细节。

以下是我使用的代码:

class Worker : public QObject {
    Q_OBJECT
  public slots:
    void forwardKeyEvent(int k) {
      sendKeyEvent(k);
    }
  signals:
    void sendKeyEvent(int k);
};

class Controller : public QObject {
    Q_OBJECT
  public:
    Controller(QQmlApplicationEngine * e) : engine(e) {
      w = new Worker;
      t = new QThread;
      w->moveToThread(t);
      connect(this, SIGNAL(sendKeyEvent(int)), w, SLOT(forwardKeyEvent(int)));
      connect(w, SIGNAL(sendKeyEvent(int)), this, SLOT(receiveEvent(int)));
      t->start();
    }
  public slots:
    void receiveEvent(int k) {
      QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyPress, (Qt::Key)k, Qt::NoModifier));
      QCoreApplication::postEvent(engine->rootObjects().at(0), new QKeyEvent(QEvent::KeyRelease, (Qt::Key)k, Qt::NoModifier));
    }

  private:
    Worker * w;
    QThread * t;
    QQmlApplicationEngine * engine;
  signals:
    void sendKeyEvent(int k);
};

// QML side
  Column {
    TextEdit {
      width: 400
      height: 200
      Keys.onPressed: console.log("pressed ", event.key)
      Keys.onReleased: console.log("released ", event.key)
    }
    Row {
      Repeater {
        model: [Qt.Key_Left, Qt.Key_S, Qt.Key_Right]
        delegate: Rectangle {
          width: 50
          height: 50
          color: "red"
          Text {
            anchors.centerIn: parent
            text: modelData
          }
          MouseArea {
            anchors.fill: parent
            onClicked: Work.sendKeyEvent(modelData) // this is actually the worker controller
          }
        }
      }
    }
  }

为了测试线程间事件发布,从QML到C ++控制器再到另一个线程中的对象,然后回到控制器然后发布事件,它来回做了一些疯狂的事情。它确实按预期工作 - 来自辅助线程的数据被正确地发布到事件循环中,但发布的事件无法按预期工作。

答案 1 :(得分:0)

实际上问题来自系统和用户,有必要将窗口集中在系统上以使其工作。