How to pause and resume a Qtimer (Qt 5) - qt

I need some help on the usage of Qtimer.
I work with Qt 5.0.2 and here my problem :
I am trying to develop a Timer, and the interface is simple :
There is just 2 button : the button "Start", to launch the timer, and the "Pause" Button, and a QtimeEdit to display the time.
This screenshot shows how it looks like : http://img834.imageshack.us/img834/1046/5ks6.png
The problem is that the pause function doesn't work. I have read all the documentation about Qtimer here : http://harmattan-dev.nokia.com/docs/library/html/qt4/qtimer.html and here : qt.developpez.com/doc/5.0-snapshot/qtimer/ , but no result.
This is the source code I have : (I put only what is needed)
// Creation of the Buttons and the time area
void MainWindow::createBottom()
{
bottom = new QWidget();
play = new QPushButton("Launch",this);
pause = new QPushButton("Pause",this);
play->setDisabled(false);
pause->setDisabled(true);
timeEdit = new QTimeEdit(this);
timeEdit->setDisplayFormat("mm:ss");
layout->addWidget(play);
layout->addWidget(pause);
layout->addWidget(timeEdit );
bottom->setLayout(layout);
connect(play, SIGNAL(clicked()), this, SLOT(startSimulation()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
}
// to resume the timer where is was stopped
void MainWindow::resumeSimulation()
{
timer->blockSignals( false );
pause->setText("Pause");
pause->disconnect(SIGNAL(clicked()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
paused = false;
timer->start();
int timeOfPause = time->restart();
int timeTotal = timeOfPause + timeElapsed;
time->addMSecs(-timeTotal);
}
// to Start the timer
void MainWindow::pauseSimulation()
{
timer->blockSignals(true);
pause->setText("Resume");
timer->stop();
play->setDisabled(false);
//pause->setDisabled(true);
pause->disconnect(SIGNAL(clicked()));
connect(pause, SIGNAL(clicked()), this, SLOT(resumeSimulation()));
paused = true;
}
// to Start the timer from zero.
void MainWindow::startSimulation()
{
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this , SLOT(updateTime()));
timer->start(500);
play->setDisabled(true);
pause->setDisabled(false);
}
void MainWindow::updateTime()
{
if(time == NULL)
{
time = new QTime(0,0,0,0);
time->start();
}
//timeEdit->setTime(QTime::fromS(time->elapsed()));
//time = &(time->addMSecs(1000));
if(hasRestart)
{
time->restart();
time->addMSecs(-timeElapsed);
hasRestart = false;
}
else
{
timeElapsed =+ time->elapsed();
}
int seconds = 0;
int minutes = 0;
int hours = 0;
if(!paused)
{
seconds = (timeElapsed/1000)%60;
minutes = (timeElapsed/60000)%60;
hours = (timeElapsed/3600000)%24;
std::cout << "Test : " << hours << ":" << minutes << ":" << seconds << std::endl;
timeEdit->setTime(QTime(0,minutes,seconds,0));
timeEdit->update();
}
}
When I push the Start button, the timer starts well, but when I push "Pause" it only pause it on the graphic interface, but when I resume, it shows the present time as if it hadn't paused.
For instance :
I start.
I pause at 00:05. It blocks apparently the timer.
I wait for 10 seconds. I resume the timer, it shows 00:15 instead of 00:06
How could I fix that ?
Thank you !
EDIT : Thanks Kuba Ober, but could you explain me the code you posted please ?
How does the pause work ?

Below is a SSCCE, tested under both Qt 4.8 and 5.1.
//main.cpp
#include <QApplication>
#include <QPushButton>
#include <QVBoxLayout>
#include <QLabel>
#include <QElapsedTimer>
#include <QTime>
class Window : public QWidget {
Q_OBJECT
int m_timerId;
qint64 m_accumulator;
QLabel *m_label;
QElapsedTimer m_timer;
Q_SLOT void on_restart_clicked() {
m_accumulator = 0;
m_timer.restart();
if (m_timerId == -1) m_timerId = startTimer(50);
}
Q_SLOT void on_pause_clicked() {
if (m_timer.isValid()) {
m_accumulator += m_timer.elapsed();
m_timer.invalidate();
} else {
m_timer.restart();
m_timerId = startTimer(50);
}
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timerId) {
QWidget::timerEvent(ev);
return;
}
QTime t(0,0);
t = t.addMSecs(m_accumulator);
if (m_timer.isValid()) {
t = t.addMSecs(m_timer.elapsed());
} else {
killTimer(m_timerId);
m_timerId = -1;
}
m_label->setText(t.toString("h:m:ss.zzz"));
}
public:
explicit Window(QWidget *parent = 0, Qt::WindowFlags f = 0) : QWidget(parent, f), m_timerId(-1) {
QVBoxLayout * l = new QVBoxLayout(this);
QPushButton * restart = new QPushButton("Start");
QPushButton * pause = new QPushButton("Pause/Resume");
restart->setObjectName("restart");
pause->setObjectName("pause");
m_label = new QLabel("--");
l->addWidget(restart);
l->addWidget(pause);
l->addWidget(m_label);
QMetaObject::connectSlotsByName(this);
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Window w;
w.show();
return a.exec();
}
#include "main.moc"

QTime totalTime, sinceStart;
void MainWindow::createBottom()
{
bottom = new QWidget();
play = new QPushButton("Launch",this);
pause = new QPushButton("Pause",this);
play->setDisabled(false);
pause->setDisabled(true);
timeEdit = new QTimeEdit(this);
timeEdit->setDisplayFormat("mm:ss");
layout->addWidget(play);
layout->addWidget(pause);
layout->addWidget(timeEdit);
bottom->setLayout(layout);
connect(play, SIGNAL(clicked()), this, SLOT(startSimulation()));
connect(pause, SIGNAL(clicked()), this, SLOT(pauseSimulation()));
connect(this, SIGNAL(timeChanged(QTime)), timeEdit, SLOT(setTime(QTime)));
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this , SLOT(updateTime()));
}
void MainWindow::updateTime() {
emit timeChanged(totalTime.addMSecs(sinceStart.elpased()));
}
void MainWindow::resumeSimulation() {
sinceStart.restart();
timer->start();
}
void MainWindow::pauseSimulation() {
timer->stop();
totalTime = totalTime.addMSecs(sinceStart.restart());
emit timeChanged(totalTime);
}

I made a Timer class for the start, stop, pause and resume
class MyTimer
{
public:
MyTimer();
QTime m_qtime;
int m_accumulator;
void start();
int stop();
void pause();
void resume();
};
MyTimer::MyTimer()
:m_accumulator(0), m_qtime(QTime())
{
}
void MyTimer::start()
{
m_qtime.start();
m_accumulator = 0;
}
int MyTimer::stop()
{
if(!m_qtime.isNull())
{
int l_elapsedTime = m_qtime.elapsed();
m_accumulator += l_elapsedTime;
}
m_qtime = QTime();
return m_accumulator;
}
void MyTimer::pause()
{
if(!m_qtime.isNull())
{
int l_elapsedTime = m_qtime.elapsed();
m_accumulator += l_elapsedTime;
}
}
void MyTimer::resume()
{
if(!m_qtime.isNull())
{
m_qtime.restart();
}
}

Related

How to stop a loop in a QPushButton pressed?

I have a connection with Arduino. I need to send continuously a character to serial port to handle a motor series when I press a button. So I created a QPushButton and I want when it is pressed it send this character.
But when I need to create a loop I don't know how to break it. I tried this solution
...
Class .... {
private:
bool buttonPressed = false;
}
void MainWindow::on_pulsante1_pressed()
{
buttonPressed = true;
while (buttonPressed == true)
{
connect(ui->pulsante1,SIGNAL(released()),this,SLOT(on_pulsante1_released()));
qDebug() << "pressed";
}
}
void MainWindow::on_pulsante1_released()
{
buttonPressed = false;
qDebug() << "released";
}
Where did I do wrong?
You probably want to use a QTimer for that. Also you can define the frequency that the timer fires. For example:
#include <QTimer>
..
Class .... {
private:
QTimer timer;
}
void MainWindow::MainWindow(){
// in your constructor
connect(&timer, [this]{
//
// write to serial here
//
});
}
void MainWindow::on_pulsante1_pressed()
{
qDebug() << "pressed";
timer.start(1); // run this every 1 milisecond
}
void MainWindow::on_pulsante1_released()
{
timer.stop();
qDebug() << "released";
}
}
Take a look to QTimer documentation

QAudioOutput buffer underflow

Getting a message "Got a buffer underflow!" after each write in this simple program.
Beep.hpp:
#pragma once
#include <QTimer>
#include <QAudioOutput>
class Beep: public QObject
{
Q_OBJECT
public:
explicit Beep();
virtual ~Beep();
void onTimer();
private:
QAudioOutput m_out;
QIODevice *m_outDev;
QTimer m_timer;
};
Beep.cpp:
#include "Beep.hpp"
int ms = 100;
const QAudioFormat defaultAudioFormat = []()
{
QAudioFormat format;
format.setSampleRate(8000);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
return format;
}();
Beep::Beep() :
m_out(defaultAudioFormat),
m_outDev()
{
m_out.setBufferSize(16 * ms);
m_outDev = m_out.start();
QObject::connect(&m_timer, &QTimer::timeout, this, &Beep::onTimer);
m_timer.setSingleShot(false);
m_timer.start(ms);
}
Beep::~Beep()
{
}
void Beep::onTimer()
{
std::vector<uint8_t> samples(16 * ms);
m_outDev->write((char*) &samples.front(), samples.size());
}
main.cpp:
#include <QCoreApplication>
#include "Beep.hpp"
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Beep beep;
return app.exec();
}
This test program is just writing buffers with zeros. With real data there are cracking sounds.
Writing more data or changing timings makes it worse. What's wrong with this code?
Using a Timer is the wrong way to do it.
Use the notify() signal
void AudioManager::init_audio(AudioManager *mgr) {
if (mgr->stream_id == -1) return;
mgr->audio_format.setSampleRate(mgr->context->time_base.den);
mgr->audio_format.setSampleSize(16);
mgr->audio_format.setChannelCount(2);
mgr->audio_format.setCodec("audio/pcm");
mgr->audio_format.setSampleType(QAudioFormat::SignedInt);
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (!info.isFormatSupported(mgr->audio_format)) {
mgr->audio_format = info.nearestFormat(mgr->audio_format);
}
mgr->audio_out = new QAudioOutput(mgr->audio_format, nullptr);
mgr->audio_out->setNotifyInterval(15);
mgr->audio_out->setBufferSize(mgr->context->time_base.den * 4); // 1 second worth of stereo data
connect(mgr->audio_out, SIGNAL(notify()), mgr, SLOT(audio_out_notify()));
connect(mgr->audio_out, SIGNAL(stateChanged(QAudio::State)), mgr, SLOT(audio_out_state_changed(QAudio::State)));
qreal volume_out = (qreal)parent->volume / 100.0f;
mgr->audio_out->setVolume(volume_out);
mgr->audio_out_device = mgr->audio_out->start();
}
This will be called when the audio playback requires more data
void AudioManager::audio_out_notify() {
qDebug() << "Audio notify";
check_audio_playback();
}
Most of the below code will be irrelevant but it is also called is audio has stopped playing.
void AudioManager::check_audio_playback() {
if (stream_id == -1) return;
pthread_mutex_lock(&audio_mutex);
if (!audio_out->state() == QAudio::State::IdleState) {
pthread_mutex_unlock(&audio_mutex);
return;
}
if (parent->pts_start_time < 0.0) {
if (parent->Video.stream_id == -1 && decode_pos > 65) { // start playback
parent->pts_start_time = buffers[0].frame_time;
parent->sys_start_time = (double)parent->timer.elapsed() / 1000.0;
qDebug() << "Audio playback started";
} else {
pthread_mutex_unlock(&audio_mutex);
return;
}
}
if (playback_pos == decode_pos) {
pthread_mutex_unlock(&audio_mutex);
return;
}
AudioBuffer *buffer = nullptr;
double current_sys_time = ((double)parent->timer.elapsed() / 1000.0) - parent->sys_start_time;
bool bounds = false;
int skipped = 0;
while (!bounds) {
if (playback_pos == decode_pos) bounds = true;
else {
AudioBuffer *temp_buffer = &buffers[playback_pos];
double temp_time = temp_buffer->frame_time - parent->pts_start_time;
if (temp_time < current_sys_time ) {
if (buffer) {
buffer->used = false;
skipped++;
}
buffer = temp_buffer;
playback_pos++; playback_pos %= MAX_AUD_BUFFERS;
} else {
bounds = true;
}
}
}
if (skipped > 0) qDebug("Skipped %d audio buffers on playback", skipped);
if (buffer) {
audio_out_device->write((const char *)buffer->data, buffer->buffer_size);
buffer->used = false;
}
pthread_mutex_unlock(&audio_mutex);
}
The example on the Qt website wasn't that obvious http://qt.apidoc.info/5.1.1/qtmultimedia/audiooutput.html at first but when I put it in to test it wasn't too bad.
The reason was that the source of audio data wasn't a "production-quality module" (it's a dummy testing class): the timer was drifting because its real interval was 10ms plus the processing time.
Other observations:
make QAudioOutput::setBufferSize() bigger
do QAudioInput::read() and QAudioOutput::write() in chunks with size that matches QAudioInput::periodSize() and QAudioOutput::periodSize()

QMessagebox not show text when call show()

my problem is I need to show a message ask users wait when I check network availability of other clients.My way is I have a class workerThread to do the business, before start it I create a qMessageBox. But the message only shows the title, not the content. I have no idea why, pls help :(
Here's the worker thread:
#include <QObject>
#include <QString>
#include "clientdataobj.h"
class WorkerThread : public QObject
{
Q_OBJECT
public:
explicit WorkerThread(QObject *parent = 0);
QList<ClientDataObj> listClient() const;
void setListClient(const QList<ClientDataObj> &listClient);
signals:
void finished();
void error(QString err);
void listClientPingChecked( QList <ClientDataObj> list);
public slots:
void testPing();
private:
QList <ClientDataObj> mListClient;
bool pingEachClient(QString ip);
};
implement:
#include "workerthread.h"
#include <QFile>
#include <QMessageBox>
#include <QTextStream>
WorkerThread::WorkerThread(QObject *parent) :
QObject(parent)
{
}
void WorkerThread::testPing()
{
if (mListClient.size()==0) {
emit finished();
return;
}
else{
for(unsigned i=0;i<mListClient.size();i++){
bool result = pingEachClient(mListClient[i].ip());
if(result)
mListClient[i].setStatus(true);
else
mListClient[i].setStatus(false);
}
emit listClientPingChecked(mListClient);
}
emit finished();
}
bool WorkerThread::pingEachClient(QString ip)
{
QString pingCommand = "ping " +ip + " -c 3 | grep loss | awk ' {print $7}' > pingResult.txt";
system(qPrintable(pingCommand));
QString lossPercentTxt = readFileText("pingResult.txt") ;
lossPercentTxt.chop(1);
int lossPercent = lossPercentTxt.toInt();
if(lossPercent<10){
return true;
}
else return false;
}
QList<ClientDataObj> WorkerThread::listClient() const
{
return mListClient;
}
void WorkerThread::setListClient(const QList<ClientDataObj> &listClient)
{
mListClient = listClient;
}
How I call it in MainWindow:
on_pbSendUpdate_clicked()
{
changeModeWaitPing();
getClientOnlineList();
}
getClientOnlineList()
{
if(mListClient.size()==0){
return;
}
mpThreadPing = new QThread;
mpWorkerThread = new WorkerThread;
mpWorkerThread->setListClient(mListClient);
connectThreadPingToGui();
mpThreadPing->start();
}
changeModeWaitPing()
{
ui->pbSendUpdate->setEnabled(false);
callMsgBox("Pinging client... Pls wait!");
// callWaitDialog();
}
callMsgBox( QString text)
{
if (NULL==mMsg) {
return;
}
mMsg->setWindowTitle("INFO");
// mMsg->setAttribute(Qt::WA_DeleteOnClose);
mMsg->setWindowModality(Qt::NonModal);
mMsg->setModal(false);
QString info ="Pinging client... Pls wait!";
mMsg->setText(info);
mMsg->show();
}
connectThreadPingToGui()
{
connect(mpWorkerThread, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(mpThreadPing, SIGNAL(started()), mpWorkerThread, SLOT(testPing()));
connect(mpWorkerThread, SIGNAL(finished()), mpThreadPing, SLOT(quit()));
connect(mpWorkerThread, SIGNAL(finished()), mpWorkerThread, SLOT(deleteLater()));
connect(mpThreadPing, SIGNAL(finished()), mpThreadPing, SLOT(deleteLater()));
connect(mpWorkerThread,SIGNAL(listClientPingChecked(QList<ClientDataObj>)),this,SLOT(updateListClientOnline(QList<ClientDataObj>)));
}
updateListClientOnline(QList<ClientDataObj> list)
{
mListClientOnline = list;
mPingDone = true;
if (NULL==mMsg) {
return;
}
else{
mMsg->hide();
}
if(mpDialogWaitPing==NULL){
return;
}
else{
mpDialogWaitPing->hide();
}
launchClientListTable();
}
You create a new thread, but you don't move any objects to that thread. So your new thread does nothing. I assume you wan't mpWorkerThread to be moved to the new thread. In that case you're missing mpWorkerThread->moveToThread(mpThreadPing);

qt private member function calling another member function crashes program

I have a class with a lot of member functions. Here are the ones giving me trouble (Segmentation Fault):
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"
MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
blah
}
MainWindow::~MainWindow(){delete ui;}
void MainWindow::resetHandle() {
//Open the first found LabJack U3.
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = GoOne(*lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
}
void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
char err[255];
if((lngErrorcode == 1015) && (!isOpen))
{
isOpen = true;
//STOP EVERYTHING
MainWindow::on_pushButton_clicked(false);
//Create an error message dialog only to prompt to connect labjack.
QMessageBox *msg = new QMessageBox();
msg->show();
msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");
}
if(lngErrorcode == 1003)
{
//attempt to solve handle problem by resetting handle
OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
GoOne(*lngHandle);
}
if(lngErrorcode != LJE_NOERROR)
{
ui->textBrowser->show();
ui->exitTextBrowser->show();
ErrorToString(lngErrorcode,err);
ui->textBrowser->setText(err);
}
}
void MainWindow::update_timer_complete()
{
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
//I really wanted to check if stuff is working during each update.
resetHandle(); //Will call runningError() handler if problem
}
I can call my error handling function runningError() from any member function except void update_timer_complete(). When I do, I get a .exe crash.
There were a lot more member functions omitted.
If this helps, here is the class definition header file:
#include <QMainWindow>
#include "LabJackUD.h"
#include <QTimer>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0, LJ_HANDLE* lngHandle = 0);
~MainWindow();
private slots:
void cycle_timer_complete();
void next_timer_complete(bool update = false);
void update_timer_complete();
void on_radioButton_pressed();
void on_radioButton_2_pressed();
void on_radioButton_released();
void on_radioButton_3_pressed();
void on_radioButton_4_pressed();
void on_pushButton_toggled(bool checked);
void on_pushButton_clicked();
void on_pushButton_4_clicked();
void on_pushButton_clicked(bool checked);
void on_exitTextBrowser_clicked();
private:
Ui::MainWindow *ui;
LJ_HANDLE *lngHandle;
LJ_ERROR lngErrorcode;
void clearAll();
void runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration);
QTimer *cycleComplete;
QTimer *nextExperiment;
QTimer *updateLCDs;
int selectedPin;
int timer1;
int timer2;
int timer3;
int prevTime, prevSpin1, prevSpin2, prevSpin3, prevSpin4;
void resetHandle();
void updatePins();
};
What could allow two equivalent member functions of the form private void doStuff() to have unequal access to the same member function? One calls it fine, the other calls it and produces a segmentation fault!
If really required, here is the full code:
#include "mainwindow.h"
#include <QTimer>
#include <QDebug>
#include <QMessageBox>
#include "ui_mainwindow.h"
#include "LabJackUD.h"
bool isOpen = false;
MainWindow::MainWindow(QWidget *parent, LJ_HANDLE *lngHandle2) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
lngHandle = lngHandle2;
cycleComplete = new QTimer(this);
nextExperiment = new QTimer(this);
updateLCDs = new QTimer(this);
selectedPin = 0;
timer1 = 0;
timer2 = 0;
timer3 = 0;
lngErrorcode = 0;
connect(cycleComplete,SIGNAL(timeout()),this,SLOT(cycle_timer_complete()));
connect(nextExperiment,SIGNAL(timeout()),this,SLOT(next_timer_complete()));
connect(updateLCDs,SIGNAL(timeout()),this,SLOT(update_timer_complete()));
ui->textBrowser->hide();
ui->textBrowser->raise();
ui->exitTextBrowser->hide();
ui->exitTextBrowser->raise();
clearAll();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::resetHandle() {
//Open the first found LabJack U3.
lngErrorcode = OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = GoOne(*lngHandle);
runningErrors(lngErrorcode, __LINE__, 0);
}
void MainWindow::runningErrors(LJ_ERROR lngErrorcode, long lngLineNumber, long lngIteration) {
char err[255];
if((lngErrorcode == 1015) && (!isOpen))
{
isOpen = true;
//STOP EVERYTHING
MainWindow::on_pushButton_clicked(false);
//Create an error message dialog only to prompt to connect labjack.
QMessageBox *msg = new QMessageBox();
msg->show();
msg->setText("WARNING:\n\nLabjack is not connected. Please\nconnect Labjack.");
}
if(lngErrorcode == 1003)
{
//attempt to solve handle problem by resetting handle
OpenLabJack(LJ_dtU3, LJ_ctUSB, "1", 1, lngHandle);
GoOne(*lngHandle);
}
if(lngErrorcode != LJE_NOERROR)
{
ui->textBrowser->show();
ui->exitTextBrowser->show();
ErrorToString(lngErrorcode,err);
ui->textBrowser->setText(err);
//Qdebugging purposes
qDebug() << ("Error number = ") << lngErrorcode;
qDebug() << ("Error string = ") << err;
qDebug() << ("Source line number = ") << lngLineNumber;
qDebug() << ("Iteration = ") << lngIteration;
}
}
void MainWindow::clearAll() {
lngErrorcode = eDO(*lngHandle, 4, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 5, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 6, 0);
runningErrors(lngErrorcode, __LINE__, 0);
lngErrorcode = eDO(*lngHandle, 7, 0);
runningErrors(lngErrorcode, __LINE__, 0);
ui->radioButton->setChecked(false);
ui->radioButton_2->setChecked(false);
ui->radioButton_3->setChecked(false);
ui->radioButton_4->setChecked(false);
}
void MainWindow::on_radioButton_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 4, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 1 pressed";
ui->radioButton->setChecked(true);
}
void MainWindow::on_radioButton_2_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 5, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 2 pressed";
ui->radioButton_2->setChecked(true);
}
void MainWindow::on_radioButton_3_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 6, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 3 pressed";
ui->radioButton_3->setChecked(true);
}
void MainWindow::on_radioButton_4_pressed()
{
clearAll();
lngErrorcode = eDO(*lngHandle, 7, 1);
runningErrors(lngErrorcode, __LINE__, 0);
qDebug() << "radio button 4 pressed";
ui->radioButton_4->setChecked(true);
}
void MainWindow::on_pushButton_toggled(bool checked)
{
}
void MainWindow::on_pushButton_clicked()
{
}
void MainWindow::cycle_timer_complete()
{
qDebug()<<"cycleComplete timeout";
}
void MainWindow::next_timer_complete(bool update)
{
qDebug()<<"nextExperiment timeout";
if (!update) {
selectedPin++;
}
qDebug()<<"selectedPin is " << selectedPin;
switch ( selectedPin ) {
case 4:
qDebug() << "case 4";
if (!update) {
nextExperiment->start((ui->spinBox->value())*1000*7);
}
MainWindow::on_radioButton_pressed();
break;
case 5:
qDebug() << "case 5";
nextExperiment->start((ui->spinBox_2->value())*1000*7);
MainWindow::on_radioButton_2_pressed();
break;
case 6:
qDebug() << "case 6";
nextExperiment->start((ui->spinBox_3->value())*1000*7);
MainWindow::on_radioButton_3_pressed();
break;
case 7:
qDebug() << "case 7";
nextExperiment->start((ui->spinBox_4->value())*1000*7);
MainWindow::on_radioButton_4_pressed();
break;
case 8:
qDebug() << "case 8";
MainWindow::on_pushButton_clicked(true);
break;
}
//ui->pushButton->setText("Timer Complete");
}
void MainWindow::update_timer_complete()
{
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
//I really wanted to check if stuff is working during each update.
resetHandle();
}
void MainWindow::on_pushButton_4_clicked()
{
//figure out the total cycle time
int t_total = ui->spinBox->value();
t_total += ui->spinBox_2->value();
t_total += ui->spinBox_3->value();
t_total += ui->spinBox_4->value();
//continue counting from previous state, correct for new values
int newCycleTime = timer1;
int newExpTime = timer2;
int c1 = ui->spinBox->value();
int c2 = ui->spinBox_2->value();
int c3 = ui->spinBox_3->value();
int c4 = ui->spinBox_4->value();
switch(selectedPin) {
case 4:
newExpTime += (c1 - prevSpin1)*1000*7;
newCycleTime += (c1+c2+c3+c4-prevSpin1-prevSpin2-prevSpin3-prevSpin4)*1000*7;
case 5:
newExpTime += (c2 - prevSpin2)*1000*7;
newCycleTime += (c2+c3+c4-prevSpin2-prevSpin3-prevSpin4)*1000*7;
case 6:
newExpTime += (c3 - prevSpin3)*1000*7;
newCycleTime += (c3+c4-prevSpin3-prevSpin4)*1000*7;
case 7:
newExpTime += (c4 - prevSpin4)*1000*7;
newCycleTime += (c4-prevSpin4)*1000*7;
}
cycleComplete->start(newCycleTime);
nextExperiment->start(newExpTime);
updateLCDs->start(timer3);
//change back appearance
ui->pushButton_4->setEnabled(false);
ui->pushButton->setText("STOP");
ui->radioButton->setEnabled(false);
ui->radioButton_2->setEnabled(false);
ui->radioButton_3->setEnabled(false);
ui->radioButton_4->setEnabled(false);
ui->pushButton->setChecked(true);
prevSpin1 = c1;
prevSpin2 = c2;
prevSpin3 = c3;
prevSpin4 = c4;
//no dialog open so reset
isOpen=false;
}
void MainWindow::on_radioButton_released()
{
}
void MainWindow::on_pushButton_clicked(bool checked)
{
if(checked) {
//START NRML OPERATION
//selectedPin will become 4 very shortly.
selectedPin = 3;
//figure out the total cycle time
int t_total = ui->spinBox->value();
t_total += ui->spinBox_2->value();
t_total += ui->spinBox_3->value();
t_total += ui->spinBox_4->value();
t_total *= 1000*7;
//keep track for continue option.
prevTime = t_total;
//configure timers
cycleComplete->setInterval(t_total);
nextExperiment->setInterval(0);
updateLCDs->setInterval(100);
ui->pushButton->setText("STOP");
ui->radioButton->setEnabled(false);
ui->radioButton_2->setEnabled(false);
ui->radioButton_3->setEnabled(false);
ui->radioButton_4->setEnabled(false);
ui->pushButton_4->setEnabled(false);
ui->spinBox->setEnabled(false);
ui->spinBox_2->setEnabled(false);
ui->spinBox_3->setEnabled(false);
ui->spinBox_4->setEnabled(false);
//start timers
cycleComplete->start();
nextExperiment->start();
updateLCDs->start();
//no dialog open so reset
isOpen=false;
} else {
//STOP EVERYTHING REVERT EVERYTHING
//enable continue button
ui->pushButton_4->setEnabled(true);
//revert appearance
ui->pushButton->setText("START");
ui->radioButton->setEnabled(true);
ui->radioButton_2->setEnabled(true);
ui->radioButton_3->setEnabled(true);
ui->radioButton_4->setEnabled(true);
ui->spinBox->setEnabled(true);
ui->spinBox_2->setEnabled(true);
ui->spinBox_3->setEnabled(true);
ui->spinBox_4->setEnabled(true);
//copy the current state for continuing
//+1 because finished timer is -1
timer1 = (cycleComplete->remainingTime()+1);
timer2 = (nextExperiment->remainingTime()+1);
timer3 = (updateLCDs->remainingTime()+1);
prevSpin1 = ui->spinBox->value();
prevSpin2 = ui->spinBox_2->value();
prevSpin3 = ui->spinBox_3->value();
prevSpin4 = ui->spinBox_4->value();
//stop the timers
cycleComplete->stop();
nextExperiment->stop();
updateLCDs->stop();
}
}
void MainWindow::on_exitTextBrowser_clicked()
{
ui->textBrowser->hide();
ui->exitTextBrowser->hide();
}
Strangely, the solution was rearange the body of the definition of the member function void update_timer_complete() {body}. I had to put
//I really wanted to check if stuff is working during each update.
resetHandle(); //Will call runningError() handler if problem
above
//Display new LCD values
//qDebug()<<"updateLCDs timeout";
QString minutesTop = QString::number((cycleComplete->remainingTime()/1000)/7);
QString secondsTop = QString::number((cycleComplete->remainingTime()/1000)%7);
QString minutesBot = QString::number((nextExperiment->remainingTime()/1000)/7);
QString secondsBot = QString::number((nextExperiment->remainingTime()/1000)%7);
ui->lcdNumber->display(minutesTop+":"+secondsTop);
ui->lcdNumber_2->display(minutesBot+":"+secondsBot);
minutesTop.~QString();
minutesBot.~QString();
secondsTop.~QString();
secondsBot.~QString();
For some reason, the other way around produces a crash. I would love to hear an explanation, and if one is given, I will select it as the answer.

use of qpropretyanimation desirably

In this program I have built a QPropertyanimation and add to it my item and pos() property.
I override KeyPressEvent. And with using of keys consist of j, f, z item go forward ,go back and jump.
According gravity when item jump should fall. For this purpose I call down function. But item just once jump don't fall. I also have another problem: when the first press j and f (forward and back) item animate desirably but for next times item go forward and go back all of scene.
I mean It should animated for example 40 pixel but It animated 800 pixel.
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
QPoint start;
QPoint end;
~MainWindow();
private:
QGraphicsView* view;
QGraphicsScene* scene;
void keyPressEvent(QKeyEvent* k);
MyQgraphicsObject* m;
QPropertyAnimation* pr;
QElapsedTimer* timer;
int f;
int u;
int b;
void forward();
void up();
void back();
void down();
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
view=new QGraphicsView;
scene=new QGraphicsScene;
m=new MyQgraphicsObject;
pr=new QPropertyAnimation(m,"pos");
view->setScene(scene);
view->resize(800,800);
view->setFixedSize(800,800);
setCentralWidget(view);
scene->addItem(m);
start= QPoint(0,0);
f=30;
u=-30;
b=-30;
}
void MainWindow::keyPressEvent(QKeyEvent *k)
{
switch (k->key()) {
case Qt::Key_J: {
forward();
break;
}
case Qt::Key_Z: {
up();
down();
break;
}
case Qt::Key_F: {
back();
break;
}
default:
break;
}
}
void MainWindow::forward()
{
end.setX(f);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
f+=40;
}
void MainWindow::up()
{
end.setY(u);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
u-=30;
pr->pause();
}
void MainWindow::back()
{
end.setX(b);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
b-=40;
}
void MainWindow::down()
{
u+=30;
end.setY(u);
pr->setEndValue(end);
pr->setDuration(1000);
pr->setEasingCurve(QEasingCurve::Linear);
pr->start();
}
You should not use resize and setFixedSize on view because you use it in setCentralWidget and its size will be managed by the layout. You should use setFixedSize on main window instead.
Animations are asynchonous. For example, when you call up(); down(), these functions will be executed without 1-second pause. Also, starting animation when it's already started has no effect.
Usually animations are used in such way when you know exactly where you need object to move in the next second. It's complicated to receive directives from user and change object's trajectory when the animation is already performing.
Here is an example showing correct use of animations for this task. Object can receive one directive (forward, back or jump) per second, and according animation will be performed in the next second.
Header:
class MainWindow : public QMainWindow {
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QGraphicsView* view;
QGraphicsScene* scene;
void keyPressEvent(QKeyEvent* k);
QGraphicsObject* object;
QPropertyAnimation* animation;
QPointF pos;
double speed;
enum Command {
command_none, command_jump, command_forward, command_back
};
Command next_command;
private slots:
void timeout();
};
Source:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
view = new QGraphicsView;
scene = new QGraphicsScene;
object = scene->addWidget(new QPushButton("test"));
object->setPos(0, -object->boundingRect().height());
animation = new QPropertyAnimation(object,"pos");
animation->setDuration(1000);
view->setScene(scene);
setFixedSize(800,800);
scene->addRect(-500, -200, 1000, 200);
setCentralWidget(view);
scene->addItem(object);
next_command = command_none;
speed = 100;
QTimer* timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(timeout()));
timer->start(1000);
}
MainWindow::~MainWindow() {}
void MainWindow::keyPressEvent(QKeyEvent *k)
{
switch (k->key()) {
case Qt::Key_J: {
next_command = command_forward;
break;
}
case Qt::Key_Z: {
next_command = command_jump;
break;
}
case Qt::Key_F: {
next_command = command_back;
break;
}
default:
break;
}
}
void MainWindow::timeout() {
//fall
if (pos.y() < 0) {
pos.setY(pos.y() + speed);
if (pos.y() >= 0) {
pos.setY(0);
}
}
//action
switch(next_command) {
case command_forward:
pos.setX(pos.x() + speed);
break;
case command_back:
pos.setX(pos.x() - speed);
break;
case command_jump:
if (pos.y() == 0) {
pos.setY(pos.y() - speed);
}
break;
default:
break;
}
next_command = command_none;
animation->stop();
animation->setEndValue(pos - QPointF(0, object->boundingRect().height()));
animation->start();
}

Resources