【问题标题】:Question about app.exec() and looping in Qt关于 Qt 中 app.exec() 和循环的问题
【发布时间】:2022-01-01 19:28:54
【问题描述】:

app.exec() 不是返回main() 的无限循环吗?

我想循环下面的服务器客户端通信,但它只执行一个,然后主函数以app.exec()结束

我是 Qt 和 C++ 的新手,我该如何管理这个循环?

int main(int argc, char *argv[])
{
    cout << "Waiting for the next request " << endl;
    QApplication app(argc, argv);

    //  Prepare our context and socket
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:2424");
    zmq::message_t request;


    QQmlApplicationEngine engine;

    VideoStreamer videoStreamer;
    imageProvider *liveOriginalImageProvider(new imageProvider);
    imageProvider *liveMaskedImageProvider(new imageProvider);

    //********SERVER CLIENT COMMUNICATION BEGINS******//

    // Wait for next request from client
    cout << "Waiting for the next request ." << endl;
    socket.recv(&request);
    cout << "Waiting for the next request.. " << endl;
    string replyMessage = string(static_cast<char *>(request.data()), request.size());

    // Print out received message
    cout << "Received from client (Python): " + replyMessage << endl;

    //  See the gradual sending/replying from client
    sleep(1);

    //  Send reply back to client
    string msgToClient("W");
    zmq::message_t reply(msgToClient.size());
    memcpy((void *) reply.data(), (msgToClient.c_str()), msgToClient.size());
    socket.send(reply);

    //*********SERVER CLIENT COMMUNICATION ENDS**********//

    engine.rootContext()->setContextProperty("VideoStreamer",&videoStreamer);
    engine.rootContext()->setContextProperty("liveOriginalImageProvider",liveOriginalImageProvider);
    engine.rootContext()->setContextProperty("liveMaskedImageProvider",liveMaskedImageProvider);

    engine.addImageProvider("liveOriginal",liveOriginalImageProvider);
    engine.addImageProvider("liveMasked",liveMaskedImageProvider);


    const QUrl url(QStringLiteral("qrc:/main.qml"));
    engine.load(url);

    QObject::connect(&videoStreamer,&VideoStreamer::originalImage,liveOriginalImageProvider,&imageProvider::updateImage);
    QObject::connect(&videoStreamer,&VideoStreamer::maskedImage,liveMaskedImageProvider,&imageProvider::updateImage);

    return app.exec();
}

---------更新---------

我在 thread.h

中创建了这个线程
class MyThread : public QThread{
public slots:
    void run();
};

thread.cpp中我声明了方法:

void MyThread :: run() {
    //  Prepare our context and socket
    zmq::context_t context(1);
    zmq::socket_t socket(context, ZMQ_REP);
    socket.bind("tcp://*:2424");
    zmq::message_t request;

    //********SERVER CLIENT COMMUNICATION BEGINS******//

    // Wait for next request from client
    cout << "Waiting for the next request ." << endl;
    socket.recv(&request);
    cout << "Waiting for the next request.. " << endl;
    string replyMessage = string(static_cast<char *>(request.data()), request.size());

    // Print out received message
    cout << "Received from client (Python): " + replyMessage << endl;

    //  See the gradual sending/replying from client
    sleep(1);

    //  Send reply back to client
    string msgToClient("W");
    zmq::message_t reply(msgToClient.size());
    memcpy((void *) reply.data(), (msgToClient.c_str()), msgToClient.size());
    socket.send(reply);

    exec();
    //*********SERVER CLIENT COMMUNICATION ENDS**********//
}

ma​​in.cpp 我称之为:

QThread *thread = new QThread();

MyThread *myThread = new MyThread();
myThread->moveToThread(thread);
myThread->connect(thread, SIGNAL(started()), myThread, SLOT(run()));

thread->start();

我得到Error: Class declaration lacks Q_OBJECT macro. QThread 不继承 QObject 吗?如何正确调用循环?

【问题讨论】:

  • 您可以在单独的线程上运行 zeroMQ 的东西(在 QThread 上阅读),或者您可以尝试将 zeroMQ 套接字连接到事件循环。后者需要创建一个新的 QTcpSocket,采用带有setSocketDescriptor 的 zeroMQ 套接字,然后将侦听器添加到onReadyRead 以实际读取(并可能处理)zeroMQ 消息。快速谷歌发现 github.com/jonnydee/nzmqt ,这是“0MQ 和 Qt 之间的无缝接口”。我强烈建议您先尝试一下。
  • 不,这不是一个无限循环(如果是,它永远不会返回),它不会返回 main() - 调用 main 是未定义的。
  • app.exec() 不是一个“返回main() 的无限循环 - 它是在QApplication 内部启动Qt 事件循环的原因。您的ZMQ 对象需要存在于由管理的QObjects 中的某处应用程序并在事件循环中执行它们的 I/O。
  • 我不明白“将 zeroMQ 套接字连接到事件循环”是什么意思。这个事件循环在哪里,我将如何在其中编写我的 zmq 代码。.跨度>

标签: c++ qt


【解决方案1】:

我目前从事的主要项目之一使用 Qt 和 ZMQ - 您的 ZMQ 套接字需要位于在应用程序事件循环上运行的 QObject 内,而不是在应用程序的 main() 函数内

这是一个非常简略视图,说明我们的一个 ZMQ 套接字如何在 Qt 事件循环上进行通信 - 应用程序有一个 ZMQ_SUB 套接字连接到另一端的 ZMQ_PUB 套接字发布事件从硬件接口

int main(int argc, char* argv[])
{
   QApplication app(argc, argv);
   ...
   ConnectionManager connMgr; // Create connection class - is a QObject subclass
   connMgr.connect(target);

   MainWindow mainWin; // Create GUI classes

   return app.exec();
}
void ConnectionManager::connect(std::string target)
{
    context = zmq_ctx_new();

    zsocket = zmq_socket(context, ZMQ_SUB);
    zmq_connect(zsocket, (connection + ":" + REQUEST_PORT).c_str());
    ...

    QTimer pollTimer;
    pollTimer.callOnTimeout(this, &ConnectionManager::onPollTimer);
    pollTimer.start(100);
}

void ConnectionManager::onPollTimer()
{
    uint16_t length = 0;

    const size_t buffer_length = 1024;
    uint8_t* buffer = new uint8_t[buffer_length];

    do
    {
        int64_t more = 0;
        size_t more_size = sizeof more;
        auto len = zmq_recv(zsocket, buffer + length, buffer_length - length, ZMQ_NOBLOCK);
        if (len == -1)
        {
            return;
        }
        else if (len > 0)
        {
            length += len;
            auto rc = zmq_getsockopt(socket, ZMQ_RCVMORE, &more, &more_size);
        }
    } while (more);

    std::cout << "Received" << length << "bytes";
    HandleMessage(buffer, length); // Process the incoming message
}

本质上,app.exec() 确实创建了一个无限循环,但该循环存在于 QApplication 对象中,而不是重复运行调用它的 main() 函数并利用该循环的循环您的应用程序应创建QObject 子类的其他实例,并使用信号/插槽/QEvent/QTimer 机制来执行操作以响应用户操作/输入事件/时间间隔

【讨论】:

  • 谢谢你的解释,但这对我来说真的很难实现。使用我上面写的代码可以解决这种情况吗?
  • 在您的问题中,您说“我对 Qt 和 C++ 都很陌生”——您是一般编程新手还是您用其他语言编写过,而您现在正在尝试使用 C++/Qt首次?我问是因为您在这里尝试的不是我建议您作为初学者程序员尝试实现的东西,直到您对一般语言更加熟悉,然后熟悉 Qt 应用程序事件循环和信号/插槽机制有效,因为这些是编写 Qt 应用程序的基本机制
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-12-28
  • 2014-05-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多