Solved proper design for first project
-
Yeah, I should have figured that out myself.
So, I'm trying to get this working, and I'm hitting two compile errors that I can't figure out. Here's my main()"
int main(int argc, char *argv[]) { QApplication a(argc, argv); QThread workerThread; SimulatorWidget *widget = new SimulatorWidget(); SimulatorWorker *worker = new SimulatorWorker(); //< No parent, otherwise you can't move it to the thread widget->show(); // Start the worker thread and move the worker object to the worker thread workerThread.start(); worker->moveToThread(&workerThread); // Connect the signals for cleanup QObject::connect(&a, &QApplication::aboutToQuit, &workerThread, &QThread::quit); // When the app is quitting - stop the thread QObject::connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater); // Free the worker object on thread exiting // Connect signals/slots from the worker object to your widget or window here ... QObject::connect(widget, &SimulatorWidget::buttonPressed, worker, &SimulatorWorker::startStopTimer); QObject::connect(worker, &SimulatorWorker::counterChanged(qint32), widget, &SimulatorWidget::doStuff);
On the last line, I'm getting this error:
/home/mzimmers/hatchco/simulator/main.cpp:26: error: expected primary-expression before ‘)’ token
QObject::connect(worker, &SimulatorWorker::counterChanged(qint32), widget, &SimulatorWidget::doStuff);
^I imagine it's some lame syntax error, but I can't see it.
More troubling is this error:
/opt/Qt/5.9/5.9/gcc_64/include/QtCore/qglobal.h:733: error: static assertion failed: No Q_OBJECT in the class with the signal
#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(bool(Condition), Message)
^
This is generated from the line:QObject::connect(widget, &SimulatorWidget::buttonPressed, worker, &SimulatorWorker::startStopTimer);
Does the problem stem from the fact that SimulatorWidget isn't derived from QObject?
Thanks.
-
Remove the
qint32
from the connect statement. Using that version you only pass the address of the function. -
@mzimmers said in proper design for first project:
Does the problem stem from the fact that SimulatorWidget isn't derived from QObject?
If it's a widget then it's a
QObject
, make sure you have theQ_OBJECT
macro at the top of your class. -
Thank you to SGaist and kshegunov. Both suggestions were exactly right. I did have to re-run qmake after adding the Q_OBJECT macro, though, to get rid of some undefined error references.
Now that it builds, I'll do some debugging and report back. Thanks again...
-
This connect statement isn't doing what I expect:
QObject::connect(widget, &SimulatorWidget::buttonPressed, worker, &SimulatorWorker::startStopTimer);
The signal is firing (as evinced by a breakpoint in the function) but the slot routine isn't being called. Here's the widget code:
SimulatorWidget::SimulatorWidget(QWidget *parent) : QWidget(parent) { setLayout(new QVBoxLayout()); lcd = new QLCDNumber(); layout()->addWidget(lcd); QPushButton* button = new QPushButton("Start/Stop"); layout()->addWidget(button); connect(button, &QPushButton::clicked, this, &SimulatorWidget::buttonPressed); } void SimulatorWidget::buttonPressed() { ; // do nothing }
Any ideas what I'm doing wrong? And I realize this example is somewhat odd, but I couldn't think of a more direct way (to send the button signal to the worker slot).
Thanks.
-
Aren't you connecting two slots there ?
buttonPressed should be a signal.
-
Here's what I was trying to do: get the button clicked signal to fire a slot function within the widget, and that slot would also be a signal to the worker.
From your question, I gather that this isn't right, so how do I connect the button press to the worker?
-
Ohhh...I think I just realized something: the signal isn't a routine defined by me. It just gets created for me (by the MOC?).
So, I made these changes:
void SimulatorWidget::buttonPressed() { emit notifyWorker(); }
and in main:
QObject::connect(widget, &SimulatorWidget::notifyWorker, worker, &SimulatorWorker::startStopTimer);
The worker slot now gets called when the button is pressed.
Now, though, my worker slot for the timer:
QObject::connect(&counterTimer, &QTimer::timeout, this, &SimulatorWorker::signalCounterChange);
isn't working. The slot signalCounterChange() is never called. Any ideas here?
Thanks.
-
I'd check that
counterTimer.start(1000)
is really called. -
Yeah, that was basically it. When I stitched together the examples from above, I neglected to notice that my worker object had two timers declared, and I wasn't consistent on which I used.
Works now. I've tested multiple starts and stops, and verified that the "finished" signal works, too. I do believe I have a functional example. I also modified the program so the worker passes the value to the widget for display.
So, to summarize what I've learned here:
- run at least two threads: one for the UI and one to do work. This prevents compute-intensive tasks from blocking the UI updates.
- create a class for the worker, and instantiate an object in main().
- use moveToThread to move the worker object to another thread.
- make your worker interrupt-driven (work depends mostly on signals from UI).
- use the arguments in the signal/slot routines to pass data.
I think I have a basis for reasonable design now. Thank you to everyone who participated in this.