"Tcl_ServiceModeHook: Notifier not initialized" FLTK 和 c++11 线程错误

"Tcl_ServiceModeHook: Notifier not initialized" error with FLTK and c++11 thread

我正在尝试在我的 C++ 项目中获取 FLTK 运行ning。我正在创建一个 OMNeT++ 模拟,并希望像模拟主机一样使用 GUI,也就是说,我可以制作一个发送按钮,连接到 GUI 的主机将排队一条消息以在模拟中发送。

我遇到的问题是,当 FLTK window 运行s 时,它会等待导致整个模拟冻结的响应,直到我关闭 window .我的解决方案是 运行 GUI 在一个单独的线程中。但是,现在我收到此错误:

Tcl_ServiceModeHook: Notifier not initialized

下面是包含线程和 GUI 的 class 的代码。

#include <Enumerations.H>
#include <Fl.H>
#include <Fl_Box.H>
#include <Fl_Widget.H>
#include <Fl_Window.H>
#include <GUI.h>


void GUI::callThread() {
    t = std::thread(&GUI::openWindow, this);
}

int GUI::openWindow() {
    Fl_Window *window = new Fl_Window(300,180);
    Fl_Box *box = new Fl_Box(20,40,260,100,"Hello, World!");
    box->box(FL_UP_BOX);
    box->labelsize(36);
    box->labelfont(FL_BOLD+FL_ITALIC);
    box->labeltype(FL_SHADOW_LABEL);
    window->end();
    window->show();
    return Fl::run();
}

我所做的就是调用它:

GUI *g = new GUI();
g->callThread();

如果我直接调用 openWindow(),window 可以正常打开,但它会等待一个动作,因此模拟的其余部分无法继续。

我正在努力使这个跨平台(必须在 Mac 和 Windows 上工作)。我尝试了 Qt(设置太复杂)和 wxWidgets(在我的电脑上出错)所以 FLTK 似乎是下一个最佳选择之一。

如果有人知道如何修复此错误或对设置我的 GUI 的更好方法有任何意见,我会洗耳恭听。这似乎是我唯一能做的事情。

OMNeT++ 5.0 及更高版本具有 Qtenv,它是基于 QT 的运行时(Tkenv 现已弃用),因此整个 QT 设置、依赖项等都由 OMNeT++ 为您完成。 Qtenv 将成为 OMNeT++ 5.1 中的默认运行时

不太清楚您要实现的目标。如果你想在每次按下按钮时将事件插入事件队列,你肯定必须使用一个单独的线程,但你必须弄清楚模拟时间和挂钟时间是如何相互关联的。如果它们必须同步,您需要实施一个 real-time 调度程序,将模拟时间与挂钟时间同步。 OMNeT++ 中的套接字示例执行此操作并且行为与您描述的类似,除了插入事件队列的外部事件来自套接字(您可以在其中附加浏览器)而不是来自 GUI。

如果您不关心同步,即您想将其用于某种演示,那么您不必使用 real-time 调度程序,但您应该知道 OMNeT++ 本身就是单线程并且您的 GUI 在单独的线程中 运行,因此您也必须同步它们。即绝对禁止从 GUI 线程访问 OMNET 正在使用的任何东西(否则会发生坏事)。

穷人的解决方案:如果您只想触发一个事件(即您真的只需要一个按钮)。在主机中编写一个应用程序,定期轮询一个易变的 bool 参数。如果找到参数 "true",它会发送事件,然后将参数设置为 "false"。现在你如何触发一个事件?您可以在 属性 检查器(运行时的左下方面板)中浏览给定节点的参数,您可以手动将其值更改回 true,然后让模拟继续。在下一次轮询时,主持人的应用程序将再次检测到该参数为真并再次发送。显然它是有限的,但它在不编写太多代码的情况下提供了有限的交互(并且所有的多线程问题都由运行时本身处理)