【问题标题】:Wait for a SLOT to finish等待 SLOT 完成
【发布时间】:2010-12-23 12:17:00
【问题描述】:

我使用 QNetworkAccessManager 进行表单 POST。

我已将信号和插槽连接为:

connect(manager,SIGNAL(finished(QNetworkReply*)),this,SLOT(readCookies(QNetworkReply*)));

现在,我通过以下方式提出请求:

manager->post(request,postData);

现在 readCookies(QNetworkReply *) 将在 SIGNAL 发出后立即运行。现在,使用我在这个插槽中获得的 Cookie,我必须再进行一次 POST..

由于信号和槽是异步的,我想等到我从第一个 POST 中获取 cookie,然后我想再次使用我在第一个 POST 中获得的 cookie 来做另一个帖子,比如

//Setting new request, headers etc...
manager->post(request2,postData2);

我希望后者始终在第一个执行后执行(以便我获得正确的 cookie 值)。

要走的路是什么?我是所有这些信号和插槽的新手,所以请多多包涵。

【问题讨论】:

    标签: c++ qt qt4 signals-slots


    【解决方案1】:

    你可以在你的 readCookies() 槽中发帖:

    void readCookies( QNetworkReply* reply ) {
        if ( ...error? ) {
            report error...
            return;
        }
    
        ...
        manager->post(request2,postData2);
    }
    

    读取 cookie 后我会被叫到,然后您可以继续您的帖子。将其连接到第二个插槽,依此类推。 但是,如果您在单个对象中管理其中的许多,那么管理多个可能并行运行的异步操作可能会变得容易出错。我建议使用命令模式 - here I described 为什么我发现它在这种情况下非常有用。请求和异步操作的序列被封装在一个对象中(缩写,带有一些伪代码):

    class PostStuffOperation : public QObject {
        Q_OBJECT
    public:
        enum Error {
           NoError=0,
           Error=1,
           ...
        };
    
        Error error() const; //operation successful or not?
        QString errorString() const; //human-readable error description
    
        ... setters for all the information the operation needs
        ...
        void start() {
           ...start your first request and connect it to cookiesRead 
        }
    
    public Q_SLOTS:
        void cookiesRead( QNetworkReply * ) {
        if ( error ) {
           // set error and errorString...
           emit finished( this ); //couldn't read cookies, so the operation fails
           return;
        }
        ... do post
     }
    
     void postFinished( QNetworkReply* ) {
         if ( error ) {
             // set error and errorString...
         }
    
        emit finished( this ); //post finished - that means the whole operation finished
     }
    Q_SIGNALS:
        void finished( PostStuffOperation* );
    };
    

    要开始操作,请执行

    PostStuffOperation op* = new PostStuffOperation( this );
    ... pass data like server, port etc. to the operation
    connect( op, SIGNAL(finished()), this, SLOT(postOperationFinished()) );
    op->start();
    
    void postOperationFinished( PostStuffOperation* op ) {
        if ( op->error != PostStuffOperation::NoError ) {
            //handle error, e.g. show message box
        }
    }
    

    为此类操作拥有一个通用基类是有意义的,请参见例如KDE 的KJob

    【讨论】:

      【解决方案2】:

      您可以将此信号连接到管理器的插槽,并在读取 cookie 后发出信号。举例:

      connect(this, SIGNAL(cookiesRead()), manager, SLOT(PostAgain());
      

      所以你的 readCookies 函数将是:

      {
         // Read cookies
         emit cookiesRead();
      }
      

      当然你可以将你想要的所有数据从信号发送到槽。

      希望有帮助

      【讨论】:

      • 怎么想不到……我在想像 pthread_join 这样复杂的东西……谢谢……
      • 通常很难与自己的代码保持距离
      【解决方案3】:

      如果您已完成第一个 cookie 的评估,您可以发送连接到另一个插槽(重新发送插槽)的第二个信号。您可以直接在插槽中执行此操作。你也可以像普通的成员函数一样调用槽。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-10-04
        • 2020-07-04
        • 2011-12-28
        • 2011-09-08
        • 1970-01-01
        • 2011-10-14
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多