3

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)));
Lander
  • 3,369
  • 2
  • 37
  • 53
  • I don't really understand, at first glance this seems like it should work. The thread emits `FileProgressChanged` from `drive`--is `OnFileProgressChanged` being called properly? Emitting a signal from one thread to another thread's slot should work properly (it gets queued). – Brendan Shanks Feb 20 '12 at 20:38
  • On the function that emits, the code is `emit FileProgressChanged(p)`. If I step into that, it brings me to [this](http://pastebin.com/hhSa8WjV), but my breakpoint at OnFileProgressChanged is never hit. – Lander Feb 20 '12 at 20:46

2 Answers2

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.

Brendan Shanks
  • 3,141
  • 14
  • 13
  • No dice. I did some more searching around and I *believe* the answer lies in [this question](http://stackoverflow.com/questions/7881052/qt-qthread-trouble-using-signal-slot-going-from-worker-to-gui). The signal/slot connection works fine without the parameters. – Lander Feb 21 '12 at 00:54
  • 1
    That's possible too. You'll need to have a `qRegisterMetaType("Progress");` line somewhere before the `connect()` call. Leaving that out should have thrown an error though (either at compile time or runtime). – Brendan Shanks Feb 21 '12 at 00:59
  • Tested and it was the issue! Quite a simple fix, thankfully. Thanks for the assistance. – Lander Feb 21 '12 at 01:01
  • Good to hear. I'm surprised it didn't throw errors at runtime though, were you watching the output (like the "Application Output" pane of Qt Creator)? Also, mind marking this as an accepted answer? :) – Brendan Shanks Feb 21 '12 at 04:53
  • I was going to say that I would mark this as the answer, so... yes. I don't feel like waiting 2 days. My application had spit out too much info to be able to notice anything in the output, so if it did then it went unnoticed. – Lander Feb 21 '12 at 05:13
0

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.

Community
  • 1
  • 1
Lander
  • 3,369
  • 2
  • 37
  • 53