Set Delay Timer



  • Hi
    I make a Programm using C++ and Netbeans with a lot of pushbutton

    I would like to do something like this
    When i click the button, it should change to the Position i want and Change the border style or maybe Background to red or whatever and after maybe 300ms it should Change back to normal
    The part with changing Position worked for me.

    I used to Google but I didn found any solution. I try something like this but itsnot work

    void Game::buttonClicked(QWidget* _button){
    // Clicked button identifire with QSignalMapper
        QPushButton* b = dynamic_cast<QPushButton*>(_button);           //cast widget to pushbutton
        int index = layout->indexOf(_button);                           // find out the index of button in gridlayout
        int row, col,ax,bx;
        if(index != -1){                                
        layout->getItemPosition(index,&row,&col,&ax,&bx);               // get the koordinate of this item
        }
        
              // Set border color
            //b->setStyleSheet("border:2px solid #ff0000"); or set Background color
            b->setStyleSheet("background-color:green");
    
    //make delay time here to Show this Color for only a specific amoun of time like Sleep(MS) in Windows.h
    // TODO
    //QThread:usleep() seem not work, QTimer i think also dont work
    
                  b->setStyleSheet(""); // set stylesheet back
          
         }
             }
    

    Any Solution for this?

    Thanks



  • You made it way more complicated than necessary. no need to use QSignalMapper either

    connect(button,&QPushButton::clicked,[button]()->void{
    button->setStyleSheet(QStringLiteral"background-color:green"));
    QTimer::singleShot(300,[button]()->void{button->setStyleSheet(QString());});
    });
    


  • This post is deleted!

  • Lifetime Qt Champion

    Hi and welcome to devnet,

    Can you post the code that is triggering the error ?


  • Moderators

    @Yrandom said in Set Delay Timer:

    connect(b,&QPushButton::click(),b->void{

    Why did you add () after click?
    The correct name of the slot is http://doc.qt.io/qt-5/qabstractbutton.html#clicked, so it must be:

    connect(b,&QPushButton::clicked,[b]()->void{
    ...
    


  • @Yrandom You got a lot of good advise from the others. I'll try to add to that.
    If you don't wan't do rewrite your code too much, you can change your fuction to something like this.

    void VerschiebeSpiel::buttonClicked(QWidget* _button){
        QPushButton* b = dynamic_cast<QPushButton*>(_button);  
        int index = layout->indexOf(_button);   
        int row, col,ax,bx;
        
        if(index != -1){                                
            layout->getItemPosition(index,&row,&col,&ax,&bx);
        }
    
        if(b){//check if valid cast
            b->setStyleSheet("background-color:green");
            //Timer + Lambda-function to reset the button after 1000 msec
            QTimer::singleShot(1000,this,[=]{b->setStyleSheet("background-color:red");});
        }
    }       
    

  • Lifetime Qt Champion

    To both: use qobject_cast when dealing with QObject based classes.



  • @J.Hilk

    thx for this example
    it works great.

    also just mention: i found out other solution for that

    using processevents and currenttime
    but i want to unterstand how this part work

    QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
    

    What is the 100(maxtime) mean ? because i just need to process the Event again (Loop all Event) and the current time will increase automatically.
    I dont need to put 100 as Parameter and it still work

    Thx all for the answer

    
    // Delay time for button color
    void ss::delay(int millisecondsToWait )
    {
        QTime dieTime = QTime::currentTime().addMSecs( millisecondsToWait );
        while( QTime::currentTime() < dieTime )
        {
            QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
        }
    }
    

  • Moderators

    @Yrandom said in Set Delay Timer:

    QCoreApplication::processEvents

    Check documentation http://doc.qt.io/qt-5/qcoreapplication.html#processEvents-1
    "Processes pending events for the calling thread for maxtime milliseconds or until there are no more events to process, whichever is shorter."
    Keep in mind that your solution isn't nice from design point of view and will consume a lot of CPU power.



  • @Yrandom said in Set Delay Timer:

    VerschiebeSpiel.cpp.cc: In member function 'void erschiebeSpiel::buttonClicked(QWidget*)':

    That's not where you should put the connect. my code snippet should go just after you create the button (in the constructor?)

    while( QTime::currentTime() < dieTime )
    {
    QCoreApplication::processEvents( QEventLoop::AllEvents, 100 );
    }

    This is just bad design. you are blocking the main thread and forcing the event loop to kinda keep the UI responsive. Nasty



  • @Yrandom

    Usually during a while loop, all other tasks are suspendet until the loop or more precisely the function returns. That includes the paint/repaint event that is triggered by setStyleSheet().

    QCoreApplication::processEvents() is an uncomely way to tell your app, "That with the function, do whatever else is qued".
    The Int value you pass to processEvents is a max value in -I believe -ms, you give other Processes to finish their stuff, after that time your code after the call gets processed again.

    a While loop now is calling that every eventloop-cycle

    My advice, don't use it, if you have other options.



  • A wait function like this:

    void wait(float sec)
    {
        QElapsedTimer timer;
        timer.start();
    
        while(! timer.hasExpired(sec*1000))
            QCoreApplication::processEvents();
    }
    

    allows you to simpy do that:

    b->setStyleSheet("background-color:green");
    wait(0.3);
    b->setStyleSheet("background-color:red");
    

    Pretty and clean isn't it ?



  • @mpergand said in Set Delay Timer:

    while(! timer.hasExpired(sec*1000))
        QCoreApplication::processEvents();
    

    Pretty and clean isn't it ?

    No, it's not!

    Do not use QCoreApplication::processEvents if you can avoid it!



  • @mpergand said in Set Delay Timer:

    Pretty and clean isn't it ?

    No it is not. it uses 75% of one of my CPU cores for absolutely nothing



  • @j.hilk Do not use QCoreApplication::processEvents if you can avoid it!

    Why ?
    Explain any good reason to avoid it.



  • @mpergand said in Set Delay Timer:

    @j.hilk Do not use QCoreApplication::processEvents if you can avoid it!

    Why ?
    Explain any good reason to avoid it.

    At least used in such a loop->
    @VRonin said in Set Delay Timer:

    No it is not. it uses 75% of one of my CPU cores for absolutely nothing

    Its also contrarian to the event-driven programming approach



  • @VRonin said in Set Delay Timer:

    No it is not. it uses 75% of one of my CPU cores for absolutely nothing

    For .3 sec not a big deal.
    I agree, that it's should by used for short period only (< 1 sec)

    The main drawback I know (i use the same principle on MacOS) is that it can leading to some reentrant call in some cases.



  • @mpergand said in Set Delay Timer:

    For .3 sec not a big deal.

    It is. especially on mobile/embedded hardware. it's just bad design especially when alternatives based of QEventLoop exist (but of course use the async is ALWAYS the best design)



  • @VRonin said in Set Delay Timer:

    It is. especially on mobile/embedded hardware. it's just bad design especially when alternatives based of QEventLoop exist (but of course use the async is ALWAYS the best design)

    Ok, add a small QThread::sleep should do the job as well.

    Please, can you post an example of a wait function with a QEventLoop instead.



  • add a small QThread::sleep should do the job as well

    it does not, reason in link below

    can you post an example of a wait function with a QEventLoop instead.

    https://forum.qt.io/topic/78715/why-my-timer-is-not-emit-timeout-signal



  • WOW. All the discussion :)
    First off all, thx for the answer.
    I have one more question to fullfill my Project. I dont want to start new Topic.

    I have a class GameKonfiguration
    and class MainWindow
    and the main()

    #include "Konfiguration.h"
    #include "MainWindow.h"
        
    int main(int argc, char *argv[]) {
        // initialize resources, if needed
        // Q_INIT_RESOURCE(resfile);
    
        QApplication app(argc, argv);
        
        MainWindow *window = new MainWindow(&app);
        window->show();
    
        Konfiguration *konfiguration = new Konfiguration(&app,window);
        konfiguration->show();
    
        return app.exec();
    }
    

    in main

    Now I make this Programm so far, that when i start, both Windows open and i can Change configuration and the gamefield show and user can Play and actually i can quit the game via configuration. everything fine

    Now I want to Combine the menu bar from mainwindow and use the menu bar to open my configuration window.
    However the Problem i have is now, i cant include Header a in Header b and Header b in Header a.

    // mainwindow Header file
    #include "ui_MainWindow.h"
    #include <QApplication>
    //some Header here
    
    //try
    #include "Konfiguration.h"
    //-- not work because in Konfiguration.h i already include mainwindow.h in oder to use for the Slot etc
    
    
    using namespace std;
    
    class MainWindow : public QMainWindow {
       Q_OBJECT
    private:
        Ui::MainWindow widget;
        QApplication *app;
        // Try
    Konfiguration *confi;
        
    public:
        MainWindow(QApplication*);
      //some function
        
    signals:
        public slots:
          // function etc ........
           void openConfi();
    };
    
     
    
    
    // in mainwindow.cpp
    // Open Game Configuration
        QObject::connect(widget.SpielKonfiguration,SIGNAL(triggered()),this,SLOT(openConfi()));
        
        // End Game
        QObject::connect(widget.SpielBeenden,SIGNAL(triggered()),app,SLOT(quit()));
    
     // Configuration Window
    void MainWindow::openConfi(){
        // in this Slot , the configuration window should open
    confi->show();
    }
    
    

    Konfiguration.h and cpp

    #ifndef KONFIGURATION_H
    #define KONFIGURATION_H
    
    
    #include <QApplication>
    #include "MainWindow.h"
    // some Header here....
    
    class Konfiguration : public QDialog{
        Q_OBJECT
        
    private:
        QApplication *app;
      // here i create mainwindow pointer to Setup the gamefield
        MainWindow *spielFenster;    
           //some code here
    public:
        Konfiguration(QApplication*, MainWindow*);
        virtual ~Konfiguration();     
    
        public slots:
            void clearText();
    //      void updateTextN(QString);
    //      void updateTextM(QString);
    };
    
    
    //konfiguration.cpp
    
    // use the mainwindow pointer to set Slot 
    
      //Set N, M in VerschiebeSpiel
     QObject::connect(editN,SIGNAL(textChanged(QString)),spielFenster,SLOT(setN(QString)));
     QObject::connect(editM,SIGNAL(textChanged(QString)),spielFenster,SLOT(setM(QString)));
    
    
    

    So how can I open the Konfiguration Window via the Menu bar of Mainwindow but I can still use the Konfiguration to configure the MainWindow ?

    Muss be simple for you guys, but quite hard for newbie :)

    thx for your help


  • Qt Champions 2016

    @Yrandom

    the circular includes problem can often be solved with a forward of the class

    so instead of ( in the other class header)
    #include <myclass>

    you just
    do

    class MyClass; // this is a forward

    and you are allowed to have
    class Other {
    MyClass * mc;

    Since all the use of the Myclass functions, are in the CPP file, it works.

    In the CPP file you then include the actual header.

    Not sure i explained it good :(

    Please see
    http://stackoverflow.com/questions/625799/resolve-header-include-circular-dependencies



  • @mrjj
    thx for the quick answer.

    Now I got build successfull but when I start the Programm and klick on menubar set configuration
    I got Windows disconnection and have to quit

    here is what i Changed

    ///////////////////////////////
    // in mainwindow.h
    // mainclass mainwindow
    #include <QMenuBar>
    #include <QAction>
    
    class Konfiguration; // this is the other class
    
    using namespace std;
    
    class MainWindow : public QMainWindow {
       Q_OBJECT
    private:
    Konfiguration *confi;
    //code
    }
    
    //////////////////////////
    //mainwindow.cpp
    #include "mainwindow.h"
    #include "Konfiguration.h"
    
     // Configuration Window
    void MainWindow::openConfi(){
    //
    // try to add something like confi = new Konfiguration(&app,this) like in the main() is not working either.
    //
        confi->show();
    // Debugger stoppt at show()
    }
    
    // in Konfiguration.h
    #include "MainWindow.h"
    
    class Konfiguration : public QDialog{
        Q_OBJECT
        
    private:
    code
    }
    
    
    
    

  • Qt Champions 2016

    @Yrandom said in Set Delay Timer:

    Konfiguration *confi;

    Did you remeber to new it ?

    Konfiguration *confi; is just a pointer :)

    you MUST do
    confi = new Konfiguration()

    before using it for anything



  • @mrjj

    :D my bad
    i did that but i pas the function by reference

    void MainWindow::openConfi(){
    //
     //try to add something like confi = new Konfiguration(&app,this) like in the main() is not working either.
    // pass by reference mistake :D
        confi->show();
    // Debugger stoppt at show()
    }
    
    //
    // IT work now. :D
    //
    
    


  • I wonder if this could be achieved using Property Animation instead of using timers and stylesheet manipulation.


Log in to reply