Start and stop a QThread with a loop - qt

In a QT app, I want to start a loop inside a qthread that reads 2 different sounds (it's a metronome).
I have a function with my process. I want to start it when I click on a button and stop it with another one.
The problem is, when I start it, my app doesn't respond, I can't click on the stop button. I have to stop the app.
#include <QSound>
#include <QEventLoop>
ClickThread::ClickThread(): highClickFile("://high_click.wav"), lowClickFile("://low_click.wav"), isRunning(false)
{
this->highClick = new QSound(highClickFile);
this->lowClick = new QSound(lowClickFile);
this->setPeriod(120);
}
void ClickThread::run()
{ QTimer *timer = new QTimer();
timer ->moveToThread(this);
timer->connect(timer, SIGNAL(timeout()),this, SLOT(process()));
timer ->start();
exec();
}
void ClickThread::process(){
highClick->play();
QThread::msleep(period);
highClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
lowClick->play();
QThread::msleep(period);
lowClick->stop();
}
void ClickThread::setIsRunning(bool set)
{
this->isRunning=set;
}
void ClickThread::setPeriod(unsigned long bpm)
{
this->period = 60000/bpm;
}
Thx for your answers

Stop using QTimer.
The QTimer you have currently is default to a timeout interval of 0. That is going to stuff up the event queue with infinite calls to process(), which will cause serious problems.
You should use this while loop instead:
stopPlaying = false;
while(stopPlaying == false)
{
process();
}
The boolean stopPlaying variable should be declared in your "ClickThread" class definition and used by your stop button to cause the thread to drop out of the loop, terminating the thread.

Related

Android: ASyncTask's behavior contrary to documentation

First time writing an AsyncTask and I seem to have a subtle design flaw that prevents both ProgressDialog, ProgressBar, and even Log.d() from working properly. I suspect that somehow I am not actually creating a new thread/task.
Short: the symptoms
A ProgressDialog is created in the constructor, and the code orders Android to show it in onPreExecute(), but the dialog never shows.
onProgressUpdate() is supposed to execute whenever I call publishProgress() from within doInBackground(), correct? Well, it doesn't. Instead, it executes when doInBackground() completes.
Long: investigations
Things I have verified through the emulator and, when possible, on a phone:
onPreExecute() is definitely called
the progress bar is not reset until after doInBackground() completes
update_dialog.show() is definitely executed, but the dialog does not appear unless I remove the .dismiss() in onPostExecute(); I imagine dialog is, like the progress bar, not shown until after doInBackground() completes, but is naturally immediately dismissed
the code will happily show dialogs when no computation is involved
doInBackground() definitely invokes publishProgress()
when it does, onProgressUpdate() does not execute immediately! that is, I have a breakpoint in the function, and the debugger does not stop there until after doInBackground() completes! (perhaps this is a phenomenon of the debugger, rather than doInBackground(), but I observe the same symptoms on a mobile device)
the progress bar gets updated... only after doInBackground() completes everything
similarly, the Log.d() data shows up in Android Monitor only after doInBackground() completes everything
and of course the dialog does not show up either in the emulator or on a device (unless I remove .dismiss() from onPostExecute())
Can anyone help find the problem? Ideally I'd like a working dialog, but as Android has deprecated that anyway I'd be fine with a working progress bar.
Code
Here are the essentials, less the details of computation &c.:
Where I call the AsyncTask from the main thread:
if (searching) { // this block does get executed!
Compute_Task my_task = new Compute_Task(overall_context, count);
my_task.execute(field, count, max_x, max_y);
try { result = my_task.get(); } catch (Exception e) { }
}
The AsyncTask itself:
private class Compute_Task extends AsyncTask<Object, Integer, Integer> {
public Compute_Task(Context context, int count) {
super();
current_positions = 0;
update_dialog = new ProgressDialog(context);
update_dialog.setIndeterminate(true);
update_dialog.setCancelable(false);
update_dialog.setTitle("Thinking");
update_dialog.setMessage("Please wait");
}
protected void onPreExecute() {
super.onPreExecute();
update_dialog.show();
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.setProgress(0);
}
protected void onPostExecute() {
super.onPostExecute();
update_dialog.dismiss();
}
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
ProgressBar pb = ((ProgressBar) ((Activity) overall_context).findViewById(R.id.progress_bar));
pb.setMax(base_count);
pb.incrementProgressBy(1);
Log.d(tag, values[0].toString());
}
protected Integer doInBackground(Object... params) {
Integer result = compute_scores(
(boolean[][]) params[0], (Integer) params[1], (Integer) params[2], (Integer) params[3], 0)
);
return result;
}
public int compute_scores(boolean[][] field, int count, int max_x, int max_y, int level) {
int result, completed = 0;
switch(count) {
// LOTS of computation goes on here,
// including a recursive call where all params are modified
if (level == 0)
publishProgress(++completed);
}
}
ProgressDialog update_dialog;
}
Turns out this is basically the same issue as the one given here. The "fatal" line is this one:
try { result = my_task.get(); } catch (Exception e) { }
Apparently this puts the UI thread into deep sleep. One should not use get() with an AsyncTask unless one is willing to suspend the UI thread. We have to perform a little magic in onPostExecute() instead.
Although it turns out that this was a duplicate, I didn't find it until after I wrote it, because I didn't realize the thread was blocking.

Qt5 | Function w/ Slot Not Working

I've made an app with two forms.
When I press the save button in the second form, it updates the DB Record, and returns back to the first form. I've connected the two forms via Signal-Slot with this code:
DruckerData.h
signals:
void btnSavePressed(QString printerName);
DruckerData.cpp
UiMainWindow frmMain;
connect(this,SIGNAL(btnSavePressed(QString)),&frmMain,SLOT(refreshSaved( QString )));
emit btnSavePressed(ui->ledit_druckerName->text());
this->hide();
UiMainWindow.h
public slots:
void refreshSaved(QString printerName);
UiMainWindow.cpp
void UiMainWindow::refreshSaved(QString printerName){
qDebug()<<"Updated: "<<printerName;
show_list(); //<<<<<<<<<<<<<<<<<<<<<< this function
}
show_list
void UiMainWindow::show_list (){
QList<DB_Printers_lvs> list;
DB_Printers_lvsTransporter t("LVS");
QString wc;
this->setCursor(Qt::WaitCursor);
wc = QString("where 1=1 order by nam_printer");
if (!t.load_dbPrinters_lvs_wc(&list,wc))
{
log()<< "get printers failed"<< wc << t.getLastError();
this->setCursor(Qt::ArrowCursor);
return;
}
ui.treeWidget->clear();
foreach (DB_Printers_lvs db, list)
{
QTreeWidgetItem *item = new QTreeWidgetItem(0);
printer_to_qtreewidgetitem(item, db);
ui.treeWidget->insertTopLevelItem(ui.treeWidget->topLevelItemCount(), item);
}
ui.treeWidget->header()->resizeSections(QHeaderView::ResizeToContents);
ui.bow_search->apply();
this->setCursor(Qt::ArrowCursor);
}
When I press the button on the second form and the first form shows I see debug writing Updated with printer name but the problem is how can I call or start this funktion show_list()?
Thanks for help.
The problem that you create second instance of UiMainWindow here:
UiMainWindow frmMain;
Then you connect signal with this second instance, call it's slots, but you don't even show this second instance of MainForm. Instead of this, you should connect signal and slot inside the UiMainWindow just after you create DruckerData form. Unfortunatly there is no this code at your question so i can't show exactly place. This should be something like this:
//Inside UiMainWindow
DruckerData *data = new DruckerData(this);
connect(data, SIGNAL(btnSavePressed(QString)),this,SLOT(refreshSaved( QString )));
data->show();

Create a folder in runtime when date changes [duplicate]

I need to notify some objects to clear their cache at new day begins. So, I could create QTimer or something similar and check every ms that now midnight +-5ms or not, but it's not a good idea for me.
Is there(in QT) any standard mechanisms to get notified about this event without allocating any new object? Something static or living since application's initialization like qApp?
What would you do in situation like this where you need to do something at 00:00?
UPD:
I'm looking for fast enough solution. Fast means that I need to clear container in slot as quick as it possible, 'cause since midnight data in the container become invalid. So, there is some other timer which shots every 100ms for instance and it trying to get data from container. I need to clear container with invalid data right before any possible try of getting access.
The simplest solution does indeed utilize a timer. Polling for the passage of time in not only unnecessary, but would be horrible performance-wise. Simply start the actions when the midnight strikes:
static int msecsTo(const QTime & at) {
const int msecsPerDay = 24 * 60 * 60 * 1000;
int msecs = QTime::currentTime().msecsTo(at);
if (msecs < 0) msecs += msecsPerDay;
return msecs;
}
// C++11
void runAt(const std::function<void> & job, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
// Timer ownership prevents timer leak when the thread terminates.
auto timer = new QTimer(QAbstractEventDispatcher::instance());
timer->start(msecsTo(at), type);
QObject::connect(timer, &QTimer::timeout, [=job, &timer]{
job();
timer->deleteLater();
});
}
runAt([&]{ object->member(); }, QTime(...));
// C++98
void scheduleSlotAt(QObject * obj, const char * member, const QTime & at, Qt::TimerType type = Qt::VeryCoarseTimer) {
QTimer::singleShot(msecsTo(at), type, obj, member);
}
class MyObject : public QObject {
Q_OBJECT
void scheduleCleanup() {
scheduleSlotAt(this, SLOT(atMidnight()), QTime(0, 0));
}
Q_SLOT void atMidnight() {
// do some work here
...
scheduleCleanup();
}
public:
MyObject(QObject * parent = 0) : QObject(parent) {
...
scheduleCleanup();
}
};
there is some other timer which shots every 100ms for instance and it trying to get data from container.
Since both of these timers presumably run in the same thread, they execute serially and it doesn't matter how much "later" either one is. They won't both run at the same time.

How to Break an Infinite Loop using QPushButton?

I have an infinite loop, inside the loop I want to insert a state whenever I click a button, it will break the current loop.
I've tried several ways like:
if(ui->btnStop->isDown())
{
break;
}
if(ui->btnStop->isChecked())
{
break;
}
and
if(cv::waitKey(10)>=0)
{
break;
}
But, it doesn't work.
I wonder why cv::waitKey doesn't work in Qt, but in a non-Qt project it will work flawlessly.
Are there any other way to break an infinite loop with a QPushButton?
Any help would be appreciated.
It doesn't work because the event processor cannot run whilst execution is locked in your loop. The easiest solution is to simply call QApplication::processEvents() in each loop, this will force the event processor to run.
// Add a boolean to your class, and a slot to set it.
MyClass
{
...
private slots:
void killLoop() { killLoopFlag_ = true; }
private:
bool killLoopFlag_;
}
// In the constructor, connect the button to the slot.
connect( ui->btnStop, SIGNAL( clicked() ),
this, SLOT( killLoop ) );
// Then when performing the loop, force events to be processed and then
// check the flag state.
killLoopFlag_ = false;
while ( true ) {
// ...Do some stuff.
QApplication::processEvents();
if ( killLoopFlag_ ) {
break;
}
}
However you need to ask yourself: Should I be doing long running calculations inside the GUI thread? The answer is usually no.

Enable no timeout for one specific page

I have a page that doing something, it can take 1,2 hours or even more...
After a while I get request timed out, I want that this specific page will NOT get request timed out - ever(or at least 24 hours).
How do I do it?
Thanks.
You can make a thread with a signal in it to know it its still running or not.
I suggest to use a mutex signal because is the only one that can be the same across many pools and threads.
The thread code can be:
public class RunThreadProcess
{
// Some parametres
public int cProductID;
// my thread
private Thread t = null;
// start it
public Thread Start()
{
t = new Thread(new ThreadStart(this.work));
t.IsBackground = true;
t.SetApartmentState(ApartmentState.MTA);
t.Start();
return t;
}
// actually work
private void work()
{
// while the mutex is locked, the thread is still working
Mutex mut = new Mutex("WorkA");
try
{
mut.WaitOne();
// do thread work
all parametres are available here
}
finally
{
mut.ReleaseMutex();
}
}
}
And you call it as
Mutex mut = new Mutex("WorkA");
try
{
if(mut.WaitOne(1000))
{
// release it here to start it from the thread as signal
mut.ReleaseMutex();
// you start the thread
var OneAction = new RunThreadProcess();
OneAction.cProductID = 100;
OneAction.Start();
}
else
{
// still running
}
}
finally
{
mut.ReleaseMutex();
}

Resources