Qt4 在没有连接的情况下调用slot方法?

Qt4 在没有连接的情况下调用slot方法?,qt4,Qt4,我用以下方式实现了一个活动对象。它用于在后台执行长任务。主线程通过向公共插槽(即doTask)发送信号来调用任务。下面是一个简化的示例(未测试) 只要一个信号调用doTask(),这个(应该)就可以正常工作。但是如果主线程直接调用doTask(),那么它将由主线程执行。对于某些任务,我希望通过活动对象的线程强制执行,即使直接调用slot方法也是如此 我可以在doTask()前面添加代码,以检查当前线程是否为m_线程,在这种情况下,它将执行该方法。如果不是,我希望doTask()向“this”发出

我用以下方式实现了一个活动对象。它用于在后台执行长任务。主线程通过向公共插槽(即doTask)发送信号来调用任务。下面是一个简化的示例(未测试)

只要一个信号调用doTask(),这个(应该)就可以正常工作。但是如果主线程直接调用doTask(),那么它将由主线程执行。对于某些任务,我希望通过活动对象的线程强制执行,即使直接调用slot方法也是如此

我可以在doTask()前面添加代码,以检查当前线程是否为m_线程,在这种情况下,它将执行该方法。如果不是,我希望doTask()向“this”发出一个信号,以便doTask()的调用在m_thread exec循环中排队,并由它尽快执行

我怎么能这么做

编辑:根据建议的答案,这里是新代码。doTask方法现在由live objet的线程委派执行,即使主线程直接调用它也是如此。所调用的信号仍按预期工作

class MyTask : public QObject
{
    Q_OBJECT

public:
    explicit MyTask( QObject *parent = 0 );
    ~MyTask();

public slots:
    void doTask( int param );

private slots:
    void doTaskImpl( int param );

signals:
    void taskCompleted( int result );

private:
    QThread m_thread;
};

MyTask::MyTask( QObject *parent) : QObject(parent)
{
   moveToThread(&m_thread);
   m_thread.start();
}

MyTask::~MyTask()
{
    // Gracefull thread termination (queued in exec loop)
    if( m_thread.isRunning() )
    {
        m_thread.quit();
        m_thread.wait();
    }
}

void MyTask::doTask( int param )
{
    QMetaObject::invokeMethod( this, "doTaskImpl", Q_ARG( int, param ) );
}

void MyTask::doTaskImpl( int param )
{
    // Do the live oject's asynchronous task
    sleep( 10 );
    emit taskCompleted( param*2 );
}
这是我所能找到的支持在单独线程中执行异步方法的最简单的实现。一旦线程启动,doTask()方法的调用将被排队并处理。从对象线程调用时,它将立即执行(不排队)

请注意,started()信号仅在线程启动时发出。这意味着在线程启动之前排队的doTask()方法调用将在调用started()方法槽之前执行。这就是我将其从初始实现中删除的原因。因此,对象初始化最好在构造函数中执行。

您希望调用来执行此操作。在你的情况下,它看起来像

MyTask *task;
int param;
// ...
// Will automatically change threads, if needed, to execute 
// the equivalent of:
// (void)task->doTask( param );
QMetaObject::invokeMethod( task, "doTask", Q_ARG( int, param ) );

关于我要添加的唯一改进是节省一些查找方法的时间:

classmytask{
// ...
私人:
int m_doTaskImplIndex;
};
MyTask::MyTask():
//...
m_doTaskImplIndex(metaObject()->indexOfMethod(“doTaskImpl”))
//...
{}
void MyTask::doTask(int参数)
{
metaObject()->method(m_doTaskImplIndex).invoke(this,Q_ARG(int,param));
}

那么,把它全部打包成一个漂亮的类怎么样?
我还添加了一个slot
finishPlease
,该slot将作为消息待办事项列表中的最后一个元素添加,并在主程序实际处理完所有挂起的消息后,向主程序提供反馈,然后才能终止它

class Threaded : public QObject
{
    Q_OBJECT
public:
    Threaded() {
        thread = new QThread(this);
        this->moveToThread(thread);
        connect(thread, SIGNAL(started()), this, SLOT(init()), \
                                                  Qt::QueuedConnection);
        thread->start();
    }

    virtual ~Threaded() {
        thread->exit();
        thread->wait();
        delete thread;
    }

signals:
    void okayKillMe();

public slots:
    virtual void init() = 0;
    void finishPlease() {emit okayKillMe();}

protected:
    QThread* thread;
};

class MyClass : public Threaded
{
  Q_OBJECT
public:
    MyClass() { }
    virtual ~MyClass() { }

public slots:
    void init() { }
    void doStuff() { }
    void doOtherStuff(int* data) { }

};

我怀疑我的任务中有一个bug。如果我理解正确的话


移动到线程(&m_线程);


如果父级
不是0,则将失败。

这太棒了。它就像一个符咒。查看我的编辑以了解使用过的代码。是否可以在不使用方法的字符串名称的情况下执行此操作?我在这里看到一个问题:文档说,如果对象具有父线程,则无法将其移动到另一个线程。如果MyTask是由父对象创建的,那么您的代码是否有效?中也回答了一个类似的问题。您通过这一额外的努力获得了多少好处?传递给
indexOfMethod
的方法的签名应该包含参数并采用规范化形式(),因此正确的代码应该是
m_doTaskImplIndex(metaObject()->indexOfMethod)(metaObject()->normalizedSignature(“doTaskImpl(int)”)
class Threaded : public QObject
{
    Q_OBJECT
public:
    Threaded() {
        thread = new QThread(this);
        this->moveToThread(thread);
        connect(thread, SIGNAL(started()), this, SLOT(init()), \
                                                  Qt::QueuedConnection);
        thread->start();
    }

    virtual ~Threaded() {
        thread->exit();
        thread->wait();
        delete thread;
    }

signals:
    void okayKillMe();

public slots:
    virtual void init() = 0;
    void finishPlease() {emit okayKillMe();}

protected:
    QThread* thread;
};

class MyClass : public Threaded
{
  Q_OBJECT
public:
    MyClass() { }
    virtual ~MyClass() { }

public slots:
    void init() { }
    void doStuff() { }
    void doOtherStuff(int* data) { }

};