【问题标题】:How to synthesize key press events?如何合成按键事件?
【发布时间】:2015-08-25 05:31:05
【问题描述】:

我可以通过 Qt 中的回调函数从 HAL 获取键值。由

为该键创建事件
QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, 
                                  inputKey.keyValue, 
                                  Qt::NoModifier);

注意:inputKey.keyValue 从 HAL 层接收的键值。

现在我需要在 Qt 中注册此键事件,以便如果在 IR Remote 中发生任何按键事件,则以各自的形式,keyPressEvent(e)event(e) 将被调用。并根据按键,执行特定的动作。

注意:不止一种形式,其中按键事件将触发并且不止一个键有“Page_Up,Page_Down,Ok Key等......”

试图调用 Postevent() 和 connect(.......) 但没有任何帮助。 KeyPressEvent() 没有被执行。

【问题讨论】:

  • 您可以阅读this chapter 的相关文档。
  • 欢迎来到 Stackoverflow。在提问之前,您是否阅读过 QCoreApplication::sendEvent()QCoreApplication::postEvent() 的相关信息?你遇到过什么问题吗?尝试添加有关它的更多详细信息。

标签: c++ qt qevent qkeyevent


【解决方案1】:

例如像这样:

// receiver is a pointer to QObject
QCoreApplication::postEvent (receiver, event);

您可以找到更多信息here

您可以在小部件中重新实现QObject::event()QWidget::keyPressEvent 以接收关键事件。 访问此linklink 了解更多信息。请参阅下面的示例代码,其中包含两个按钮和一个标签。单击pushButton 发送“按下输入”,pushButton_2 发送“按下字母A”。在event() 函数中接收到关键事件并相应地更新标签。

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    connect(ui->pushButton, SIGNAL(clicked()), this, SLOT(sendKeyEvent()));
    connect(ui->pushButton_2, SIGNAL(clicked()), this, SLOT(sendKeyEvent()));
}

void MainWindow::sendKeyEvent()
{
    QObject* button = QObject::sender();
    if (button == ui->pushButton)
    {
        QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
        QCoreApplication::postEvent (this, event);
    }
    else if (button == ui->pushButton_2)
    {
        QKeyEvent *event = new QKeyEvent (QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
        QCoreApplication::postEvent (this, event);
    }
}

bool MainWindow::event(QEvent *event)
{
    if (event->type() == QEvent::KeyPress)
    {
        QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
        if (keyEvent->key() == Qt::Key_Enter) {
            ui->label->setText("Enter received");
            return true;
        }
        else if (keyEvent->key() == Qt::Key_A)
        {
            ui->label->setText("A received");
            return true;
        }
    }

    return QWidget::event(event);
}

【讨论】:

  • 更新了答案以包含接收关键事件的示例。
  • 如何向多个接收者发送事件?
  • 您可能必须使用eventFilter。如果需要,请打开一个新问题。
【解决方案2】:

您可以在堆栈上创建事件。然后使用QCoreApplication::sendEvent 立即传递事件:

QWidget w1, w2;
QKeyEvent event(QEvent::KeyPress, inputKey.keyValue, Qt::NoModifier);
QApplication::sendEvent(&w1, &ev);
QApplication::sendEvent(&w2, &ev);

每个sendEvent 将调用小部件的event 方法,然后将调用xxxxEvent 受保护的方法(如果适用)。但是不要自己做,因为你会绕过应用程序全局事件过滤器并依赖于实现细节。

// WRONG!
w1.event(&ev);
// WRONG and won't compile since keyPressEvent is protected
w2.keyPressEvent(&ev);

或者,您可以在堆上创建它。 Qt 会在您发布事件后立即管理它的生命周期。发布后,该活动不再属于您,您无法重复使用它。您必须为每个帖子创建多个事件。避免重复的最简单方法是创建一个按需生成事件的本地函数。

QWidget w1, w2;
auto ev = [=]{ return new QKeyEvent(QEvent::KeyPress, inputKey.keyValue, Qt::NoModifier); };
QApplication::postEvent(&w1, ev());
QApplication::postEvent(&w2, ev());

事件将被添加到主线程的事件队列中。一旦控件返回QApplication::exec,它们将被一一传递给小部件。小部件的event 方法将从QApplication::exec 调用,postEvent 调用。

QWidget::event 实现解码事件类型并调用受保护的便利处理程序,例如keyPressEvententerEvent 等。它的实现遵循以下模式:

bool QWidget::event(QEvent * ev) {
  switch (ev->type()) {
  case QEvent::KeyPress:
    keyPressEvent(static_cast<QKeyEvent*>(ev));
    return true;
  case QEvent::Enter:
    enterEvent(static_cast<QEnterEvent*>(ev));
    return true;
  ...
  }
  return QObject::event(ev);
}

在为具有此类xxxxEvent 便利虚拟方法的事件类型实现处理程序时,您应该重新实现虚拟方法,而不是event() 本身。因此你的MainWindow 应该重新实现keyPressEvent

void MainWindow::keyPressEvent(QKeyEvent * event) {
  if (event->key() == Qt::Key_Enter)
    ui->label->setText("Enter received");
  else if (event->key() == Qt::Key_A)
    ui->label->setText("A received");
  QMainWindow::keyPressEvent(event);
}

如果您希望您的关键事件立即传递到您的窗口,并且这似乎是一种合理的方法,那么您的 sendKeyEvent 方法会变得更加简单:

void MainWindow::sendKeyEvent()
{
  if (sender() == ui->pushButton) {
    QKeyEvent event(QEvent::KeyPress, Qt::Key_Enter, Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
  else if (sender() == ui->pushButton_2) {
    QKeyEvent event(QEvent::KeyPress, Qt::Key_A, Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
}

不过,有一种方法可以进一步简化事情。回想一下QObject 支持动态属性。因此,您可以轻松地将键分配为按钮的属性,并在按下具有键属性的按钮时自动发送事件:

static const char keyPropKey[] = "key";

MainWindow::MainWindow(QWidget *parent) :
  QMainWindow(parent),
  ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  connect(ui->pushButton, &QPushButton::clicked, this, &MainWindow::sendKeyEvent);
  connect(ui->pushButton_2, &QPushButton::clicked, this, &MainWindow::sendKeyEvent);
  ui->pushButton.setProperty(keyPropKey, (int)Qt::Key_Enter);
  ui->pushButton.setProperty(keyPropKey, (int)Qt::Key_A);
}

void MainWindow::sendKeyEvent()
{
  auto key = sender().property(KeyPropKey);
  if (key.isValid()) {
    QKeyEvent event(QEvent::KeyPress, key.toInt(), Qt::NoModifier);
    QApplication::sendEvent(this, &event);
  }
}

最后,作为风格上的挑剔:没有理由让ui 成员成为指针。通过将其用作直接成员,您将避免一次堆分配和大量间接操作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-24
    • 2023-04-02
    • 2013-01-29
    • 1970-01-01
    • 2012-11-13
    相关资源
    最近更新 更多