Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QTimer inside a for loop
QtWS25 Last Chance

QTimer inside a for loop

Scheduled Pinned Locked Moved Unsolved General and Desktop
13 Posts 4 Posters 1.6k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • N Offline
    N Offline
    n_moosavi
    wrote on last edited by n_moosavi
    #1

    Dear all
    I'm new to QT and face some problems with Qtimer.
    I want to have a loop that in each iteration sends a packet with a serial port.
    There is a problem with Qtimer inside the loop since it only works for the last iteration and just sends the last packet through serialport?
    what can I do to fix it?
    here is the for loop:
    for(int i=1;i<5;i++)
    {
    send[2]=LightState(i);
    connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
    timer->setSingleShot(true);
    timer->start(timestate[i]);
    }
    void Trafficlight::senddata()
    {
    if(serialport->isOpen()){
    serialport->write(send);
    qDebug() <<"sending data:"<<send.toHex();
    }else{
    qDebug() <<"Port is not open, data:" << send.toHex();
    }
    }

    JonBJ 1 Reply Last reply
    0
    • N n_moosavi

      Dear all
      I'm new to QT and face some problems with Qtimer.
      I want to have a loop that in each iteration sends a packet with a serial port.
      There is a problem with Qtimer inside the loop since it only works for the last iteration and just sends the last packet through serialport?
      what can I do to fix it?
      here is the for loop:
      for(int i=1;i<5;i++)
      {
      send[2]=LightState(i);
      connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
      timer->setSingleShot(true);
      timer->start(timestate[i]);
      }
      void Trafficlight::senddata()
      {
      if(serialport->isOpen()){
      serialport->write(send);
      qDebug() <<"sending data:"<<send.toHex();
      }else{
      qDebug() <<"Port is not open, data:" << send.toHex();
      }
      }

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by
      #2

      @n_moosavi
      Hello and welcome.

      You have a single timer instance, and you start(timestate[i]); it 4 times with a different timestate[i] each time. This will end up with just the one timer started on the final timestate[i] value.

      It is hard to know what you are wanting to achieve here. Do you want 4 distinct QTimers for each of the timestate[i] values? Does each timer want to count its time (delay) from when the first one was started, or does each timestate value want to count/delay from when the previous one timed out?

      N 1 Reply Last reply
      1
      • JonBJ JonB

        @n_moosavi
        Hello and welcome.

        You have a single timer instance, and you start(timestate[i]); it 4 times with a different timestate[i] each time. This will end up with just the one timer started on the final timestate[i] value.

        It is hard to know what you are wanting to achieve here. Do you want 4 distinct QTimers for each of the timestate[i] values? Does each timer want to count its time (delay) from when the first one was started, or does each timestate value want to count/delay from when the previous one timed out?

        N Offline
        N Offline
        n_moosavi
        wrote on last edited by
        #3

        @JonB Thanks for your reply.
        Actually i want a timer that for example after 1000s sends 1, then after 2000s from when the first one was started, sends2.
        so the timestate is [1000, 2000,3000,4000] and the packet is [1 2 3 4].

        JonBJ 1 Reply Last reply
        0
        • N n_moosavi

          @JonB Thanks for your reply.
          Actually i want a timer that for example after 1000s sends 1, then after 2000s from when the first one was started, sends2.
          so the timestate is [1000, 2000,3000,4000] and the packet is [1 2 3 4].

          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @n_moosavi
          So you can implement in one of two ways, as you choose:

          • Create 4 separate QTimer (singleshot) instances, all connected to same senddata() slot, each one with each of the timeout durations in your timestate array.

          • Create one QTimer (singleshot). Keep a member variable to count through timestate so you know where you have got to. On the timeout, apart from doing the sendata(), advance the counter, if it's not at end calculate the difference between the value in timestate for this time's value and the previous one, re-load the single QTimer instance with that (all would be 1000 given the values you presently show in timestate).

          N 1 Reply Last reply
          2
          • JonBJ JonB

            @n_moosavi
            So you can implement in one of two ways, as you choose:

            • Create 4 separate QTimer (singleshot) instances, all connected to same senddata() slot, each one with each of the timeout durations in your timestate array.

            • Create one QTimer (singleshot). Keep a member variable to count through timestate so you know where you have got to. On the timeout, apart from doing the sendata(), advance the counter, if it's not at end calculate the difference between the value in timestate for this time's value and the previous one, re-load the single QTimer instance with that (all would be 1000 given the values you presently show in timestate).

            N Offline
            N Offline
            n_moosavi
            wrote on last edited by n_moosavi
            #5

            @JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
            .But still, only the last timer works and sends data.

                    timer = new QTimer(this);
                    send=1;
                    connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
                    timer->setSingleShot(true);
                    timer->start(timestate[0]);
            
                    timerr = new QTimer(this);
                    send=2;
                    connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
                    timerr->setSingleShot(true);
                    timerr->start(timestate[1]);
            
                    timerrr = new QTimer(this);
                    send=3;
                    connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
                    timerrr->setSingleShot(true);
                    timerrr->start(timestate[2]);
            
            JonBJ M 2 Replies Last reply
            0
            • N n_moosavi

              @JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
              .But still, only the last timer works and sends data.

                      timer = new QTimer(this);
                      send=1;
                      connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
                      timer->setSingleShot(true);
                      timer->start(timestate[0]);
              
                      timerr = new QTimer(this);
                      send=2;
                      connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
                      timerr->setSingleShot(true);
                      timerr->start(timestate[1]);
              
                      timerrr = new QTimer(this);
                      send=3;
                      connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
                      timerrr->setSingleShot(true);
                      timerrr->start(timestate[2]);
              
              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @n_moosavi
              These should work. Put qDebug() << "senddata()"; as the first statement in senddata() and see how many times it outputs.

              N 1 Reply Last reply
              0
              • N n_moosavi

                @JonB For the first way. I tried as follows. I have created 3 separate QTimer:{timer,timerr,timerrr}
                .But still, only the last timer works and sends data.

                        timer = new QTimer(this);
                        send=1;
                        connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
                        timer->setSingleShot(true);
                        timer->start(timestate[0]);
                
                        timerr = new QTimer(this);
                        send=2;
                        connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
                        timerr->setSingleShot(true);
                        timerr->start(timestate[1]);
                
                        timerrr = new QTimer(this);
                        send=3;
                        connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
                        timerrr->setSingleShot(true);
                        timerrr->start(timestate[2]);
                
                M Offline
                M Offline
                mpergand
                wrote on last edited by mpergand
                #7

                @n_moosavi

                QTimer as a counter using dynamic property:

                MainWindow::MainWindow(QWidget *parent)
                    : QMainWindow(parent)
                {
                    auto* timer=new QTimer;
                    timer->setProperty("count",5);
                    connect(timer,&QTimer::timeout,this, &MainWindow::timeout);
                    timer->start(1000);
                }
                
                void MainWindow::timeout()
                {
                    QTimer* timer=qobject_cast<QTimer*>(sender());
                    if(timer==nullptr) return; // error wrong sender
                
                    int count=timer->property("count").toInt()-1;
                    timer->setProperty("count",count);
                
                    qDebug()<<__FUNCTION__<<count;
                    
                    // call sendData() here
                
                    if(count<=0)
                        {
                        timer->stop();
                        delete timer;
                        }
                }
                
                
                N 1 Reply Last reply
                0
                • JonBJ JonB

                  @n_moosavi
                  These should work. Put qDebug() << "senddata()"; as the first statement in senddata() and see how many times it outputs.

                  N Offline
                  N Offline
                  n_moosavi
                  wrote on last edited by n_moosavi
                  #8

                  @JonB Dear JohB.
                  I added the qDebug() << "senddata()"; to the senddata. Then i run
                  It outputs 3 times and each time with the last packet. It sends the last packet 3 times.
                  I tested it with switch/case but it still sends the last packet .
                  for (int i = 0; i < 4; i++)
                  {
                  switch(timestate[i]) {
                  case 1000:
                  send[2]=LightState(0);
                  connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
                  timer->setSingleShot(true);
                  timer->start(timestate[0]);
                  case 2000:
                  send[2]=LightState(1);
                  connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
                  timerr->setSingleShot(true);
                  timerr->start(timestate[1]);
                  case 3000:
                  send[2]=LightState(2);
                  connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
                  timerrr->setSingleShot(true);
                  timerrr->start(timestate[2]);
                  }
                  }

                  JonBJ 1 Reply Last reply
                  0
                  • Kent-DorfmanK Offline
                    Kent-DorfmanK Offline
                    Kent-Dorfman
                    wrote on last edited by
                    #9

                    there really needs to be a "required reading" section for Qt, before people ask questions. As we see again, trying to use sequential/procedural programming instead of the event driven model.

                    staggering timer events only needs a single timer implementation. in the callback from Qtimer(1000ms)::TimerExpired() execute a switch sstatement based on a static var that is incremented every time the timer expires. in the "case" segments put your light (on/off) logic.

                    N 1 Reply Last reply
                    1
                    • N n_moosavi

                      @JonB Dear JohB.
                      I added the qDebug() << "senddata()"; to the senddata. Then i run
                      It outputs 3 times and each time with the last packet. It sends the last packet 3 times.
                      I tested it with switch/case but it still sends the last packet .
                      for (int i = 0; i < 4; i++)
                      {
                      switch(timestate[i]) {
                      case 1000:
                      send[2]=LightState(0);
                      connect(timer, SIGNAL(timeout()), this, SLOT(senddata()));
                      timer->setSingleShot(true);
                      timer->start(timestate[0]);
                      case 2000:
                      send[2]=LightState(1);
                      connect(timerr, SIGNAL(timeout()), this, SLOT(senddata()));
                      timerr->setSingleShot(true);
                      timerr->start(timestate[1]);
                      case 3000:
                      send[2]=LightState(2);
                      connect(timerrr, SIGNAL(timeout()), this, SLOT(senddata()));
                      timerrr->setSingleShot(true);
                      timerrr->start(timestate[2]);
                      }
                      }

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by JonB
                      #10

                      @n_moosavi
                      So you know your senddata() slot is being hit 3 times, which was the objective of the exercise. What you do in senddata() is up to you, you seem to write(send);. And that will be in whatever state you left it after your for ... switch loop, which perhaps means send[2]=LightState(2);, and that is what you are complaining about.

                      Since the loop runs when you are setting the timers up, not when the timers expire, if you change send[] there that will affect when all the timers expire, which is perhaps not what you want. So you need to alter code in that light.

                      N 1 Reply Last reply
                      0
                      • Kent-DorfmanK Kent-Dorfman

                        there really needs to be a "required reading" section for Qt, before people ask questions. As we see again, trying to use sequential/procedural programming instead of the event driven model.

                        staggering timer events only needs a single timer implementation. in the callback from Qtimer(1000ms)::TimerExpired() execute a switch sstatement based on a static var that is incremented every time the timer expires. in the "case" segments put your light (on/off) logic.

                        N Offline
                        N Offline
                        n_moosavi
                        wrote on last edited by n_moosavi
                        #11

                        @Kent-Dorfman thanks for your help, I'm new to QT, and I know that I should work harder.

                        1 Reply Last reply
                        0
                        • M mpergand

                          @n_moosavi

                          QTimer as a counter using dynamic property:

                          MainWindow::MainWindow(QWidget *parent)
                              : QMainWindow(parent)
                          {
                              auto* timer=new QTimer;
                              timer->setProperty("count",5);
                              connect(timer,&QTimer::timeout,this, &MainWindow::timeout);
                              timer->start(1000);
                          }
                          
                          void MainWindow::timeout()
                          {
                              QTimer* timer=qobject_cast<QTimer*>(sender());
                              if(timer==nullptr) return; // error wrong sender
                          
                              int count=timer->property("count").toInt()-1;
                              timer->setProperty("count",count);
                          
                              qDebug()<<__FUNCTION__<<count;
                              
                              // call sendData() here
                          
                              if(count<=0)
                                  {
                                  timer->stop();
                                  delete timer;
                                  }
                          }
                          
                          
                          N Offline
                          N Offline
                          n_moosavi
                          wrote on last edited by
                          #12

                          @mpergand thanks for your help

                          1 Reply Last reply
                          0
                          • JonBJ JonB

                            @n_moosavi
                            So you know your senddata() slot is being hit 3 times, which was the objective of the exercise. What you do in senddata() is up to you, you seem to write(send);. And that will be in whatever state you left it after your for ... switch loop, which perhaps means send[2]=LightState(2);, and that is what you are complaining about.

                            Since the loop runs when you are setting the timers up, not when the timers expire, if you change send[] there that will affect when all the timers expire, which is perhaps not what you want. So you need to alter code in that light.

                            N Offline
                            N Offline
                            n_moosavi
                            wrote on last edited by
                            #13

                            @JonB thanks for your help

                            1 Reply Last reply
                            0

                            • Login

                            • Login or register to search.
                            • First post
                              Last post
                            0
                            • Categories
                            • Recent
                            • Tags
                            • Popular
                            • Users
                            • Groups
                            • Search
                            • Get Qt Extensions
                            • Unsolved