Unsolved What's the easiest way to have an animation run a particular function undefinitely?
-
Let's assume I have a member function of a QObject, and I would like that function to be run constantly. Let's also assume it's the stupidest function ever, like the following:
void MyClass::myFunction(void) { std::cout << "foo!" << std::endl; }
Based on the QAbstractAnimation page, it looks like I should set the loopCount of such animation to
-1
, and set its duration to any random value, but I would like to know how exactly I'm supposed to link the animation to the above function. Do I need to make it a QPropertyAnimation, and then link the property to the function, or is there a smarter way around?Thanks in advance.
-
@Pippin
Hello,Let's assume I have a member function of a QObject, and I would like that function to be run constantly.
Fastest thing is to make that function a slot and attach it to a zero-timeout timer.
// These couple of lines should be adapted so the objects don't get out of scope MyClass myObject; QTimer timer; QObject::connect(&timer, SIGNAL(timeout()), &myObject, SLOT(myFunction())); timer.start(0);
Alternatively, the function can be made invokable (through putting Q_INVOKABLE in front of its declaration) and the loop can be run manually:
void MyClass::myFunction() { std::cout << "foo!" << std::endl; QMetaObject::invokeMethod(this, "myFunction", Qt::QueuedConnection); //< Will cause the function to be invoked again when control returns to the event loop }
Based on the QAbstractAnimation page, it looks like I should set the loopCount of such animation to -1, and set its duration to any random value, but I would like to know how exactly I'm supposed to link the animation to the above function.
That class is abstract so a number of methods must be implemented in a derived class. Then the derived class can emit signals when the current time property is changed, and those signals can be connected to
myFunction
(it should be a slot to do that).Is
MyClass
a subclass ofQAbstractAnimation
or are we talking about a completely unrelatedQObject
instance?Do I need to make it a QPropertyAnimation, and then link the property to the function, or is there a smarter way around?
The question is moot without knowing what you're trying to achieve.
Kind regards.
-
Thank you @kshegunov .
QTimers look awesome, but they would run the function in another thread, right? Isn't this a problem if the function, say, is changing the texts of QLineEdits? Isn't there an issue about QWidget member functions not being reentrant or something? :S
Edit: I guess it's my fault, I should have specified that the function is stupid, but also supposed to use QWidget member functions.
-
@Pippin
Hello,QTimers look awesome, but they would run the function in another thread, right?
No, timers run in the same thread they're created. But even if they didn't signals-slot calls are thread-safe (with the default connection type).
Isn't this a problem if the function, say, is changing the texts of QLineEdits? Isn't there an issue about QWidget member functions not being reentrant or something? :S
Yes, this is correct. Widgets are not reentrant nor thread-safe, but the question is moot because the slot is connected to a signal (see above comment).
I guess it's my fault, I should have specified that the function is stupid, but also supposed to use QWidget member functions.
Not a problem. I/We would've asked if there was something I/we didn't understand or if the explanation was unclear.
Kind regards.
-
Thanks @kshegunov!
I might as well ask another kind of question here rather than start a new topic.
I created a QThread pointer (parent set to
nullptr
) and connected it this way:QObject::connect(simulatingThread, SIGNAL(started()), this, SLOT(_runSimulation()));
Then I start the thread later:
simulatingThread->start();
but the Qt loop freezes until
simulatingThread
reaches the end of_runSimulation
, which makes me believe thatsimulatingThread
is actually part of the main thread. Is there something I'm missing, or this shouldn't happen at all?Edit: Furthermore,
simulatingThread->isRunning()
returnstrue
even after its task is complete, ie. even after_runSimulation
is over. -
_runSimulation()
Is executed in the main thread. Why should it be executed in the other thread?
What does _runSimulation() do?
"until simulatingThread reaches the end of _runSimulation" - simulatingThread does not execute _runSimulation(). -
@jsulm I must have misunderstood how QThreads are intended to work then. How exactly do I make
_runSimulation
run by another thread? -
@Pippin
Hi,Your
_runSimulation
slot is executed in the main thread.You need to have a worker object pushed into the thread to have the worker object's slots executed in that thread. There's a lot of info around the forum how to do such things, even just yesterday someone asked about threads. You can look up that post, it's a good way to useQThread
s, also as base you can read this. The Qt documentation provides insight into QObjects's relation with threads and threading in general.Kind regards.
Edit:
Ah, jsulm beat me to it. @Pippin, read the links. -
@kshegunov thanks for the links.
In my case, there is only one QObject (a QMainWindow subclass). The documentation seems to say that one QObject can't belong to two different threads, so I don't know what to do. Basically, I'd like the main thread to keep displaying the QMainWindow (along with the QTimer adjusting things whenever necessary), while the other thread is making calculations using some of that QMainWindow's attributes.
-
The documentation seems to say that one QObject can't belong to two different threads, so I don't know what to do.
The documentation is (understandably) correct. A
QObject
instance "belongs" to one thread and one thread alone (leaving aside things like manual synchronization, which is beyond the scope of this discussion). For your setup, you should have a dedicated worker object, which performs the calculation (in the worker thread) and communicates with the widgets (that all live in the main thread) through signal-slot connections. To do that you derive fromQObject
put whatever signals/slots you need and when starting the thread you create an instance of that class (in the heap). The worker object is then pushed into the worker thread (as in the forum post I sourced above, or as in the blog post) and its slots that are connected to signals will be executed in the worker thread. Don't call the slots directly though, because this is not thread-safe. And that's about it.Kind regards.