I am looking for a way to insert a call to my function or a slot with every looping of the Qt's event loop. I know there exists a solution using QTimers which is prescribed by Qt but they also say it is possible by calling processEvents(). Does that mean that I don't call exec at all and do the following?
while(true)
{
// My processing code
// blah blah
qApp.processEvents();
}
I believe this is not what they meant. Does anyone have more idea on how to do this using the processEvents() approach?
This question is similar to
Executing slot on every application's event loop iteration
but I am looking for something completely without timers.
Any references or links are very much appreciated.
Best,
CV
Related
using QtCreator to make a loftier interface to a sofware.
There is basically a set of buttons to tune and inputs, a start and stop job
buttons, my problem comes from an infinite loop that freezes the display so I came up with using fork() so that the loop have to compete with the main program instead of eating up the whole resources (no multithreading), but the program crashes spiting:
[xcb] Unknown sequence number while processing queue
[xcb] Most likely this is a multi-threaded client and XInitThreads has not
been called
[xcb] Aborting, sorry about that.
a.out: ../../src/xcb_io.c:274: poll_for_event: Assertion
`!xcb_xlib_threads_sequence_lost' failed.
the fonction calling the loop is called 'ON', 'OFF' is supposed to exit the forked process.
//in button 'ON' func
ps = fork();
if(getpid() == ps)
{
while(1)
{
strcpy(word, charset(minlength, maxlength, N));
ui->pass->setText(word);//operation on the display
....SNIP
}
}
//In button 'OFF' func
if(getpid() == ps)
exit(0);
I'm really asking what is the correct way of starting a while(1) and be able to break, exit, or return from it while not freezing the window using QT, thanks.
You crash probably here:
ui->pass->setText(word);//operation on the display
as in Qt, you can not change UI from non UI threads directly. Only from signals and slots mechanism.
The proper way to not freeze UI is obviously to compute lengthy operations in another thread.
You can achieve this in several ways:
One is by sub-classing QObject class to create 'worker object' which would perform all heavy operations. You create new QThread object that should live as long as you need your object. And use QObject::moveToThread method to move created object to new thread. To control your worker object you should send signals from object and call it's slots also via signal-slot mechanism. If you call them directly - they will be executed in caller thread (so do not perform stuff like worker->startHeavyJob(); in UI thread). Instead emit signal in UI (emit sigStartHeavyStuff();) and connect it to slot of your worker object (slotDoHeavyStuff();)
if you do not want to bother with this (if operation is pretty small)
- you can use QApplication::processEvents() to process events in UI event loop while going in your infinite while loop.
Another way is to use QtConcurrentRun framework to run function in separate thread which manages itself. Threads are taken from thread pool and are managed by Qt. This approach looks like something you want to do. Though you still will be able to access UI objects only through signals and slots.
I see one big issue in the presented code that is causing your freeze: You never let Qt process anything while you are in the loop. You need to allow Qt to run it's event loop. The easiest way is to use QApplication::processEvents() inside the loop.
I'm also not a fan of a while(1) loop for a couple of reasons. The first of which is that it can eat machine cycles waiting for things to happen. I doubt you really need to run the code as fast as possible, you could probably get away with some sleeping in your loop.
The other issue is that it is hard to break out. A cleaner approach would be something like this
void MyClass::on_pushButton_ON_clicked()
{
MyClass::done = false; // this is a class attribute
while (!MyClass::done) {
QApplication::processEvents();
//...
}
}
void MyClass::on_pushButton_OFF_clicked()
{
MyClass::done = true;
}
As this thread, we can stop iteration loop by setting function (f:trainer -> bool) as Trainer's stop_triger.
But in this way, I think we can't use other extension such as LogReport which use stop_trigger=((args.epoch, '10')).
So, my question is how to implement early stopping as the Extension and how to send a signal to stop trainer's iteration from Extension.
thanks.
I implemented the example code on gist,
and updated the answer on the original thread.
I noticed that stop_trigger originally uses tuple notation like (args.epoch, '10'), instead we need to change to pass a callable object (EarlyStoppingTrigger in above example).
I have a class derived from QThread: class MyClass : public QThread. In the run method I have "my own" message loop:
run() {
// exec(); // while not reached
while (_runMessageLoop && ...) {
hr = CallDispatch(.....);
if (hr== 0) QThread::msleep(100);
// QCoreApplication::processEvents(); // Does not work
}
}
Since exec() is not executed, I have no Qt event loop. This obviously causes signal / slots not to work correctly. Is there any chance to combine the Qt and my own message loop? Or do I need a frequently firing timer in order to do what I have accomplished in my infinite loop?
The right way "Qt-wise" is to use a timer and let Qt manage the event loop.
If you need to depend on external things, you can use things like QAbstractSocket to send events when data comes in over an external socket, eg.
This is not really the answer for implementing the event loop correctly, I'm fairly sure there is a way, but more of a workaround:
Start the thread normally, exec() and all, and connect the start signal to a slot (make sure it gets called in the right thread), then put your loop there, and call Qt's processEvents() in that loop. That makes sure Qt event loop gets properly set up.
I have a couple of checkboxes on my form, and I don't want to write separate event handler for each, because they all will implement the same logic. Instead I want to write just one event handler that will know about what checkbox has been clicked.
E.g. in Delphi I can use it this way:
function click_handler(sender):
begin
checked_box := sender.tag;
end;
Here I remember current checked box number in some variable (tag property was manually set in Delphi IDE).
I searched and can't find how I can implement this using Qt, because event handlers don't have sender argument.
I implemented it like this, but it's not convenient:
# assign handlers (n assignments)
checkbox_1.clicked.connect(self.cb_1_click)
...
checkbox_<n>.clicked.connect(self.cb_<n>_click)
# separate handler for each check box (n functions, doing the same stupid work)
def cb_1_click:
self.cb_click(sender=1)
...
def cb_<n>_click:
self.cb_click(sender=n)
# main check box click logic (1 function)
def cb_click(sender):
# do something common for all checkboxes
Thank you.
You may use QObject::sender() in slots to find out who emitted the signal.
Also you might want to check out QSignalMapper which is intended exactly for solving these problems.
I have a problem.
I am coding using VS2008.
I am calling webservices from my JavaScript Page.
An example
Services.ChangeDropDownLists.GetNowPlayingMoviesByLocationSVC(
blah,
OnSuccessMoviesByRegion,
OnError,
OnTimeOut
);
after execution, it goes to the function OnSuccessMoviesByRegion.
But if I put the Services in a loop (a simple for loop)
Services.ChangeDropDownLists.GetNowPlayingMoviesByLocationSVC(
blah[i],
OnSuccessMoviesByRegion,
OnError,
OnTimeOut
);
OnSucessMoviesByRegion function won't execute (but the service call executes n times successfully
But I must have the function cos I am returning value through it.
What am I missing?
Is that the typical behaviour?
Any alternatives?
Naveen, I'm answering your follow-up question here. I can think of two options:
Try to make a single call packaging your data (sending the whole blah array and handle it on the server).
Use a counter variable which you decrement in the "OnSucces" client handler each time and stop if this counter variable reaches 0.
I guess there is some kind of concurrency problem. Probably you fire the next request before the last one finished.
I think you'll have to rewrite the loop. Try to move that code, calling only the first request and then using the "OnSuccess" function to call the next one each time.