【问题标题】:Implementing callback in Qt在 Qt 中实现回调
【发布时间】:2016-03-25 22:14:17
【问题描述】:

我想在 Qt 中实现某种回调。

我有一个名为 ApiHandler 的类来发出请求。我应该有办法将一个函数作为回调传递给 ma​​keRequest 并在 replyFinished 时执行它。 我知道一种使用 std::function/std::bind 的方法。但也许有办法使用 Qt 做到这一点?插槽?或者关于在这种情况下使用 std::function/std::bind 的更详细说明。

谢谢!

typedef void (*callback)();
void ApiHandler::makeRequest(QString method, QMap<QString, QString> parameters, callback)
{
    QUrl url = this->buildCall(method, parameters);

    connect(this->manager, SIGNAL(finished(QNetworkReply*)), this, SLOT(replyFinished(QNetworkReply*, callback)));

    QNetworkRequest request;
    request.setUrl(url);
    request.setRawHeader("User-Agent", "Test");

    QNetworkReply *reply = this->manager->get(request);
    connect(reply, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
    connect(reply, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(slotError(QNetworkReply::NetworkError)));
    connect(reply, SIGNAL(sslErrors(QList<QSslError>)), this, SLOT(slotSslErrors(QList<QSslError>)));
}
void ApiHandler::replyFinished(QNetworkReply* reply, callback)
{
    qDebug() << "replyFinished" << reply->url();
    QJsonDocument j = QJsonDocument::fromJson(reply->readAll());
    if (j.isEmpty()) {
        // throw error
    }

    // call the callback with "j" as parameter
    // callback(j)

    reply->deleteLater();
}

【问题讨论】:

  • 什么情况下使用?只有在编译时无法解析回调时,您才需要 std::function。如果你事先知道所有的回调,那么就让它们成为插槽。
  • 我可以拨打不同的电话,例如 QMap&lt;QString, QString&gt; m; m["user_id"] = this-&gt;settings.value(USER_ID).toString(); ApiHandler *a = new ApiHandler; a-&gt;makeRequest("users.isAppUser", m, testCallback); 我应该需要传递不同的回调。例如,如果我从应用程序开始调用它,我会传递回调以显示警告,如果我从关于窗口调用它,我会传递回调以显示任何用户正在使用应用程序。
  • 您要么使用不同的对象,用于不同的信号,要么使用disconnect and connect slots 上下文
  • 你基本上需要一个代理来将reply转换为j,那为什么不做一个这样的代理类呢?就像当你makeRequestnew和代理时,然后将代理的接收端连接到回复并将发送端连接到回调。

标签: c++ qt c++11


【解决方案1】:

由于您已经在使用信号和槽并且makeRequest 参数已经是基于 Qt 的类型,您可以只传入一个派生自 QObject 并具有信号的 Request 实例。

class Request : public QObject
{
public:
      QString method();
      QMap<QString, QString> parameters();

 signals:
     void received( QJsonDocument );
};

replyFinished 然后可以通过Request 而不是回调

void ApiHandler::replyFinished(QNetworkReply* reply, Request* request )

当一切准备就绪时,您只需发出信号。

request->received( j ); 

在传递Request 之前,您只需连接任何您想要的东西。

connect( request, &Request::received, [=]( QJSonDocument ) {
    // whatever ...
} );

【讨论】:

  • 我投了反对票,因为这个答案不清楚。特别是,答案没有显示如何使用回调函数。在短语“replyFinished 然后可以传递一个请求而不是回调”中,被动语态的使用有效地阻止了读者理解您在哪里创建请求对象以及您在哪里将此对象传递给replyFinished。 “然后当一切准备就绪”?比是什么意思? “你只是连接你想要的任何东西”?不是很有帮助。对不起。
  • 如果像我这样的人正在寻找一个简短的简单答案,我想我会把它放在这里。因此,如果我理解正确,向服务器发出请求的客户端正在创建一个 Request 对象,并实现了一个信号 received() (即使没有参数,如果他唯一需要的是完成某事的通知),并且服务器有一个插槽,它通过指针获取此请求对象,将其注册到自身并在完成时发出信号。接收信号的接收者不需要令牌。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-12-13
  • 2010-09-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多