【问题标题】:Connecting Leap And QT Togther将 Leap 和 QT 连接在一起
【发布时间】:2014-05-02 11:58:05
【问题描述】:

在互联网上进行了长时间的搜索后,我没有找到任何合理的解决方案来解决我的问题,那就是:

我有一个按需记录用户手指移动的应用程序,(当用户按下 r 时开始记录,当用户按下 s 时停止记录,

到目前为止,我的应用程序都在控制台上,因此它与跳跃动作完美配合, 现在我们决定将应用程序迁移到基于 GUI 的应用程序,并且我们选择了 QT 平台,我们将 GUI 与我们的解决方案集成在一起,我们放置了两个按钮来代替按键,并连接事件。 真正的问题开始于我们想要查看跳跃侦听器的 onFrame 回调捕获的内容,并且自从执行 QT 的主 GUI 以来,我们已经注意到跳跃的回调有些阻塞或只是没有获得 cpu 时间(我不知道真正的问题),我们尝试了几种解决方案,例如使用从 QObject 继承的包装类和 从那里开始一个线程,但它似乎没有任何影响。

这里是main.cpp

  int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    LeapClass::QLeapLis * smp = LeapClass::QLeapLis::get_instance();

    QThread * th =  smp->thread();
    //smp->moveToThread(th);
    th->start(QThread::HighPriority);


    w.show();

    return a.exec();
}

这里的 QLeapLis 是 Wrapper 类,它有一个启动设备的 run 方法, 但仍然注意到发生,我非常接近放弃 QT。

如果有人知道如何将这两者联系起来,我们将不胜感激

非常感谢。

【问题讨论】:

  • 一如既往:显示QLeapLis的完整代码。
  • 您拥有的整个线程毫无意义:smp 对象已经在其线程中(GUI 线程),并且该线程已经启动(main 在其中运行!)。所以尝试启动一个已经在运行的线程,或者将一个对象移动到它已经在其中的线程 - 有什么意义?
  • Leap 的 Controller 对象已经是多线程的,所以你不需要做任何特别的事情,真的,除了意识到你可能拥有的 Listener 类在另一个线程中调用并且只能使用线程安全的 Qt API。它应该只是发布事件和/或发送信号,因为它们都是线程安全的。

标签: c++ multithreading qt leap-motion


【解决方案1】:

下面的代码演示了如何在 Qt 中正确使用 Listener API。

此代码需要通过moc 运行。我还检查了它是否可以使用 Leap SDK 构建和运行。

#include <QApplication>
#include <QLabel>
#include "leap.h"

class MyListener : public QObject, public Leap::Listener {
public:
   virtual void onFrame(const Leap::Controller & ctl) {
      Leap::Frame f = ctl.frame();
      // This is a hack so that we avoid having to declare a signal and
      // use moc generated code.
      setObjectName(QString::number(f.id()));
      // emits objectNameChanged(QString)
   }
};

int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   MyListener listener;
   Leap::Controller controller;
   controller.addListener(listener);

   QLabel frameLabel;
   frameLabel.setMinimumSize(200, 50);
   frameLabel.show();
   frameLabel.connect(&listener, SIGNAL(objectNameChanged(QString)),
                      SLOT(setText(QString)));

   int rc = a.exec();
   controller.removeListener(listener);
   return rc;
}

【讨论】:

  • 正如您在上面的 cmets 中提到的,leap 创建了它自己的线程并通过尝试用 QThread 包装它来杀死它,我现在找到了一个合适的解决方案,我正在调用 LeapClass:: SimpleListener * 监听器;从 main.cpp 所以它现在工作。该信号我将使用 QTcp 套接字或 Leap::Controller 控制器传递网络; controller.addListener(*listener->get_instance());
  • @whIsrael 我正在向您展示究竟该做什么,只需放下我的虚拟 Leap 实现即可。它应该可以工作并且是即插即用的。为什么要“包装” Leap::Controller 自己的线程?这是不必要的。
  • 我也从你的主..关于监听器.. :(
  • “我也从你的主要内容中得到错误......关于听众”我无法读懂你的想法。什么错误,请告诉我?
  • 我很惊讶它确实工作得很好!! ,不,我可以发出信号抛出 onFrame 回调吗?
【解决方案2】:

你可以通过不使用 Leap 回调来避免这个问题。您可以使用动画循环或其他方便的循环机制调用 Controller::frame() 来获取最新的数据帧。 (每个 Frame 对象都有一个 ID,因此您可以判断您是否已经处理过一帧)。

例如,在某些环境(处理、浏览器动画循环、Unity、Cinder 等)中,已经有一个以应用程序的绘图帧速率调用的更新循环。比这更频繁地处理帧数据也可能是浪费时间。即使您的应用程序还不是多线程的,当您使用 LM 回调实现时,您也必须开始处理多线程可能带来的一些复杂问题。

根据 Kuba Ober 的说法,QT 小部件没有动画或绘制循环,因此他的回答显示了使用 Listener 回调的正确方法是正确的方法。

【讨论】:

  • 这是货物狂热编程的一种答案。尽管看起来连贯,但几乎每个句子都是错误的。回调是有原因的,你应该使用它们。不,在计时器上调用frame() 不是正确的方法,而且是不必要的复杂化。不,您不必在一个线程中休眠来给另一个线程“时间”来执行(如果是这样,线程将毫无意义)。
  • 嗯?如果您的应用程序已经有循环机制,那么通过回调添加多线程通常是不必要的复杂化。
  • 多线程不是“通过”回调完成的。回调只是 Leap 内部线程与您的代码进行通信的一种方式。它相当于发送信号,虽然有点笨拙。主要好处是您会立即收到通知,并且延迟尽可能小。 “循环机制”在理想情况下意味着主要是阻塞的,等待内核事件。您投票的次数越多,您浪费的能量就越多,用户对您的应用程序的感觉就越差。
  • 视情况而定。在某些环境(处理、浏览器动画循环、Unity、Cinder 等)中,已经有一个以应用程序的绘图帧速率调用的更新循环。比这更频繁地处理帧数据也可能是浪费时间。如果您的应用程序还不是多线程的,那么当您使用 LM 回调实现时,您正在添加多线程。
  • 根据 Kuba Ober 的反馈编辑答案
猜你喜欢
  • 1970-01-01
  • 2014-08-16
  • 2014-02-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-12-06
  • 1970-01-01
  • 2013-08-01
相关资源
最近更新 更多