Connecting signals/slots on separate thread using

2019-04-02 10:37发布

问题:

In my application I have the following code in a dialog:

connect(drive, SIGNAL(FileProgressChanged(Progress)), SLOT(OnFileProgressChanged(Progress)));

QtConcurrent::run(this, &ProgressDialog::PerformOperation, Operation, *Path, OutPath, drive);

The PerformOperation function eventually calls to a function in drive which emits the signal FileProgressChanged, and my OnFileProgressChanged function is as follows:

void ProgressDialog::OnFileProgressChanged(Progress p)
{
    if (ui->progressCurrent->maximum() != p.Maximium)
        ui->progressCurrent->setMaximum(p.Maximium);

    ui->progressCurrent->setValue(p.Current);

    if (ui->groupBoxCurrent->title().toStdString() != p.FilePath)
        ui->groupBoxCurrent->setTitle(QString::fromStdString(p.FilePath));
}

I was doing some reading and saw that QFuture and QFutureWatcher support monitoring progress values (which would work great in this situation!), but those cannot be used in conjunction with QtConcurrent::run.

How would I go about connecting the signal that gets moved emitted on the separate thread to the slot on my main thread so I can monitor the progress of the function called on the emitter thread?

*Edit -- * I actually found an error with my code, but it doesn't seem to have an affect. I forgot to add this as an argument after the signal

connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)));

回答1:

Try using connect() with QueuedConnection, like:

connect(drive, SIGNAL(FileProgressChanged(Progress)), this, SLOT(OnFileProgressChanged(Progress)), Qt::QueuedConnection);

The connection should already be queued by default (since the emitter and receiver are in different threads), but this just makes it more explicit.

EDIT: The problem was that the Progress type wasn't registered with Qt's meta-object system. Adding qRegisterMetaType<Progress>("Progress"); fixed the problem.



回答2:

It appears as though the problem isn't with the cross-thread signal/slot, but instead with the parameter Progress. This question's answer goes into further detail, but the solution was found by doing the following in the header file in which Progress was declared:

struct Progress
{
    int Current;
    int Maximium;
    std::string FilePath;
    std::string FolderPath;
    int TotalMinimum;
    int TotalMaximum;
};

Q_DECLARE_METATYPE(Progress)

And in my form class:

qRegisterMetaType<Progress>();
    connect(Drive, SIGNAL(FileProgressChanged(const Progress&)), this, SLOT(OnFileProgressChanged(const Progress&)), Qt::QueuedConnection);

Changing Progress to const Progress& most likely isn't needed but I left it while testing.