Avoid QTimer to emit timeout signal - qt

I have started Timer to wait for certain condition to be true. IF condition is true then I stop timer and dont want timeout signal to emit or execute connnected slot. But if condition is false within specified time then its allright to emit signal timeout(). But whatever is the case it always emit timeout signal. I have used blockSignals ( true ) as well and it doesnt work. Can some one please advice me.
void timerStart( QTimer* timer, int timeMillisecond )
{
timer = new QTimer( this );
timer->setInterval( timeMillisecond );
timer->setSingleShot( true );
connect( timer, SIGNAL( timeout() ), this, SLOT( noRespFrmServer( ) ) ) ;
//timer->start( timeMillisecond );
timer->start();
}
void timerStop( QTimer* timer )
{
connect( timer, SIGNAL( destroyed( timer ) ), this, SLOT( stopTimerbeforeTimeout( ) ) );
qDebug() << " we are in timer stop";
if( timer )
{
timer->stop();
timer->blockSignals( true );
delete timer;
}
}
Also in timerStop function I have tried to emit destroyed signal but I got response that it fails to connect.
pLease advice me.

void timerStart( QTimer* timer, int timeMillisecond )
{
timer = new QTimer( this );
timer->setInterval( timeMillisecond );
timer->setSingleShot( true );
connect( timer, SIGNAL( timeout() ), this, SLOT( noRespFrmServer( ) ) ) ;
//timer->start( timeMillisecond );
timer->start();
}
This doesn't actually return the timer you just created. You want something like:
QTimer *timerStart(int timeMillisecond )
{
QTimer* timer = new QTimer( this );
timer->setInterval( timeMillisecond );
timer->setSingleShot( true );
connect( timer, SIGNAL( timeout() ), this, SLOT( noRespFrmServer( ) ) ) ;
//timer->start( timeMillisecond );
timer->start();
return timer;
}
Then you can pass the returned timer into the stop function though I suggest you use deleteLater instead of straight up deleting it:
void timerStop( QTimer* timer )
{
qDebug() << " we are in timer stop";
if( timer )
{
qDebug() << " we are stopping the timer";
timer->stop();
timer->blockSignals( true );
timer->deleteLater();
}
}

Related

QSystemTrayIcon DoubleClick Activation results in two Trigger events

I'm developing an application, where I have a system tray icon. I'm trying to catch QSystemTrayIcon::DoubleClick in the system tray. For some reason I do not understand, I have been unable to catch. In its stead, I just get two QSystemTrayIcon::Trigger events. I have tried this using both Qt4 (v4.8.7) and Qt5 (v5.5.1). My platform is KDE/Plasma 5(v5.4.3), on Debian Testing. I have tested this even on LXDE available on Debian Testing.
So my question here is: is this a bug in Qt or some other issue else where?
/* My Header File */
class MyTrayIcon : public QSystemTrayIcon {
Q_OBJECT
public :
NBTrayIcon();
public slots:
void handleActivation( QSystemTrayIcon::ActivationReason reason );
private slots:
void toggleVisible();
void showInfo();
void quit();
Q_SIGNALS:
void newWindow();
};
/* My Cpp File */
MyTrayIcon::MyTrayIcon() : QSystemTrayIcon() {
setIcon( QIcon( ":/icons/newbreeze.png" ) );
connect( this, SIGNAL( activated( QSystemTrayIcon::ActivationReason ) ), this, SLOT( handleActivation( QSystemTrayIcon::ActivationReason ) ) );
QMenu *menu = new QMenu( "TrayMenu" );
menu->addAction( "&Toggle Visible Windows", this, SLOT( toggleVisible() ) );
menu->addAction( QIcon::fromTheme( "application-exit", QIcon( ":/icons/delete.png" ) ), "&Quit NewBreeze", this, SLOT( quit() ) );
setContextMenu( menu );
};
void MyTrayIcon::handleActivation( QSystemTrayIcon::ActivationReason reason ) {
qDebug() << reason;
switch( reason ) {
case MyTrayIcon::Context: {
qDebug() << "Context";
break;
};
case MyTrayIcon::MiddleClick: {
qDebug() << "Middle Click";
break;
};
case MyTrayIcon::Trigger: {
qDebug() << "Trigger";
break;
}
case MyTrayIcon::DoubleClick: {
qDebug() << "DoubleClick";
break;
};
default:{
qDebug() << reason;
break;
};
};
};
PS: I have added the code as listed above.

How to make latency of QPushButton for push?

I would like to create QPushButton which gives an opportunity to press not often than one time in 200 msec. When I use func sleep(200) all GUI thread will stop.
Waiting for your ideas!
Thankx!
Something like this:
class Controller : public QObject
{
// ...
private:
QPointer< QPushButton > btn;
private slots:
void onClicked();
void enableClick();
};
Controller::onClicked()
{
disconnect( btn, SIGNAL( clicked() ), SLOT( onClicked() ) );
QTimer::singleShot( 200, this, SLOT( enableClick() ) );
// Optional
btn->setEnabled( false );
}
Controller::enableClick()
{
connect( btn, SIGNAL( clicked() ), SLOT( onClicked() ) );
// Optional
btn->setEnabled( true );
}

Connecting QWidget to slot QStackedWidget::setCurrentWidget

I'm attempting to toggle stacked push buttons as show in the following application.
Declaration:
#include <QPushButton>
#include <QMainWindow>
#include <QStackedWidget>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
private:
QPushButton* m_button[2];
QStackedWidget *m_buttonStack;
};
Implementation (take note of the connects):
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
resize(300, 300);
m_buttonStack = new QStackedWidget( this );
m_buttonStack->setGeometry( 100, 100 , 100 , 100 );
m_button[0] = new QPushButton( this );
m_button[0]->setText( "Button 1" );
m_buttonStack->addWidget( m_button[0] );
m_button[1] = new QPushButton( this );
m_button[1]->setText( "Button 2" );
m_buttonStack->addWidget( m_button[1] );
m_buttonStack->setCurrentWidget( m_button[1] );
QObject::connect( m_button[0] , SIGNAL( clicked() ) , m_buttonStack , SLOT( setCurrentWidget( m_button[1] ) ) );
QObject::connect( m_button[1] , SIGNAL( clicked() ) , m_buttonStack , SLOT( setCurrentWidget( m_button[0] ) ) );
}
For some inexplicable reason, although QStackedWidget::setCurrentWidget is defined QObject::connect is unable to connect to it, as the following error messages, copied from the application output window, show:
Object::connect: No such slot QStackedWidget::setCurrentWidget( m_button[1] ) in ..\mainwindow.cpp:21
Object::connect: No such slot QStackedWidget::setCurrentWidget( m_button[0] ) in ..\mainwindow.cpp:22
you'll want to use a QSignalMapper
connect(m_button[0], SIGNAL(clicked()), m_signalMapper, SLOT(map()));
m_signalMapper->setMapping(m_button[0],m_button[1]);
connect(m_button[1], SIGNAL(clicked()), m_signalMapper, SLOT(map()));
m_signalMapper->setMapping(m_button[1],m_button[0]);
QObject::connect(signalMapper , SIGNAL( mapped(QWidget *) ) , m_buttonStack , SLOT( setCurrentWidget(QWidget *) ) );
You don't need to provide the actual argument(s) when refer to the function signature in the SLOT macro:
QObject::connect( m_button[0], SIGNAL( clicked() ), m_buttonStack, SLOT( setCurrentWidget( m_button[1] ) ) );
Should be something like this:
QObject::connect( m_button[0], SIGNAL( clicked() ), m_buttonStack, SLOT( setCurrentWidget( QWidget *) ) );
As you could see, even in this way, the connection will not work. I suggest to implement your own slot (without arguments) and connect your buttons clicks to it:
QObject::connect(m_button[0], SIGNAL(clicked()), this, SLOT(onButtonClicked()));
than, in the slot, you can handle the click:
void MainWindow::onButtonClicked()
{
// Get the button clicked
QPushButton *btn = qobject_cast<QPushButton *>(sender());
m_buttonStack->setCurrentWidget(btn);
}
Thus you can even remove your buttons array.

QTimer in a thread - events not processing?

I have an object that is derived from QThread and the class definition includes the Q_OBJECT macro. I created a timer within the thread so I can do some occasional checks while the thread is running; however, the timeout event is never occurring.
I've tried making the timer a singleshot as well, but no events are emitted.
Are events processed in a thread by default or do I need to do something else to have them processed?
Here's the code for how I set up the thread and timers:
void MyClass::run( void )
{
checkTimer_chA = new QTimer( this );
qDebug() << connect( checkTimer_chA, SIGNAL( timeout() ), this, SLOT( timerExpiry_chA() ) );
checkTimer_chA->start( 1000 );
// prevent multiple, simultaneous starts
if( !isRunning )
{
qDebug() << "Thread: MyClass::run";
isRunning = true;
while( isRunning )
{
getData();
processData();
yieldCurrentThread();
}
}
checkTimer_chA->stop();
delete checkTimer_chA;
}
void DAQ::timerExpiry_chA( void )
{
qDebug() << "timerExpiry_chA";
checkTimer_chA->stop();
}
If I add QApplication::processEvents(); right before the call to yieldCurrentThread(); the timer works as expected. However, this seems wrong to me.
Working with threads in Qt can sometimes be a bit of a hassle. This blog post was a real eye opener for me. In case we adopt the style proposed in the blog post to your problem we end up with a solution like below.
Consumer::Consumer():
checkTimer_(new QTimer(this))
{
QObject::connect(checkTimer_, SIGNAL(timeout()), this, SLOT(onTimerExpiration());
QObject::connect(this, SIGNAL(ready()), this, SLOT(consume());
}
bool Consumer::event(QEvent *e)
{
if (e->type() == QEvent::ThreadChange)
{
QTimer::singleShot(0, this, SLOT(start());
}
return QObject::event(e);
}
void Consumer::consume()
{
getData();
processData();
emit ready();
}
void Consumer::start()
{
checkTimer_->start(1000);
emit ready();
}
void Consumer::onTimerExpiration()
{
qDebug() << "timeout";
}
Then run it in a separate thread as follows:
...
Consumer *consumer = new Consumer();
...
QThread *thread = new QThread(this);
thread->start();
consumer->moveToThread(thread);
All child objects of Consumer will run in the context of the thread Consumer was moved to. It is possible to create a timeout signal for the Consumer class and connect it with an object that is not running in thread. Qt will ensure that the proper signal/slot types are applied to the connection once the object is moved to the thread.
I left out the whole isRunning part as I doubt you will still need it as long as you only create one Consumer.
Threads do not have their own event loops unless you explicitly create event loops in them. See http://doc.qt.io/qt-5/threads-qobject.html#per-thread-event-loop for details.
Perhaps you need an event loop running on the thread. What about changing the code to the following?
void MyClass::run( void )
{
checkTimer_chA = new QTimer( this );
qDebug() << connect( checkTimer_chA, SIGNAL( timeout() ), this, SLOT( timerExpiry_chA() ) );
checkTimer_chA->start( 1000 );
// prevent multiple, simultaneous starts
if( !isRunning )
{
qDebug() << "Thread: MyClass::run";
isRunning = true;
QTimer::singleShot(0, this, SLOT(process()));
exec();
}
checkTimer_chA->stop();
delete checkTimer_chA;
}
void MyClass::process()
{
if( isRunning )
{
getData();
processData();
yieldCurrentThread();
QTimer::singleShot(0, this, SLOT(process()));
}
else
QThread::exit();
}
void MyClass::timerExpiry_chA( void )
{
qDebug() << "timerExpiry_chA";
checkTimer_chA->stop();
}

QPainter and QTimer

How to use QPainter and QTimer to draw a real time sinusoid like
sinus( 2 * w * t + phi )
thanks.
I would assume something like this, for the interaction between QTimer and painting:
// Periodically paints a sinusoid on itself.
class SinPainter : public QWidget
{
Q_OBJECT
public:
SinPainter( QWidget *parent_p = NULL ) :
QWidget( parent_p ),
m_timer_p( new QTimer( this ) ),
m_t( 0.0 )
{
// When the timer goes off, run our function to change the t value.
connect( m_timer_p, SIGNAL( timeout() ), SLOT( ChangeT() ) );
// Start the timer to go off every TIMER_INTERVAL milliseconds
m_timer_p->start( TIMER_INTERVAL );
}
// ...
protected slots:
void ChangeT()
{
// Change m_t to the new value.
m_t += T_INCREMENT;
// Calling update schedules a repaint event, assuming one hasn't
// already been scheduled.
update();
}
protected:
void paintEvent( QPaintEvent *e_p )
{
QPainter painter( this );
// Use painter and m_t to draw your current sinusoid according
// to your function.
}
private:
QTimer *m_timer_p;
double m_t; // <-- Or whatever variable type it needs to be.
};

Resources