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. GUI blocking...
Forum Updated to NodeBB v4.3 + New Features

GUI blocking...

Scheduled Pinned Locked Moved Unsolved General and Desktop
25 Posts 6 Posters 9.0k Views 2 Watching
  • 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.
  • kshegunovK kshegunov
    #define QLOCATION "\0" __FILE__ ":" QT_STRINGIFY(__LINE__)
    #define METHOD(a)   qFlagLocation("0"#a QLOCATION)
    #define SLOT(a)     qFlagLocation("1"#a QLOCATION)
    #define SIGNAL(a)   qFlagLocation("2"#a QLOCATION)
    

    However the process is rather complicated. qFlagLocation here is a function, but that's beyond the point as it's not really needed for the resolution. The macro converts the method's signature to a string, which string is then used by the Qt meta-object system to retrieve the exact function address/signal index by means of the data generated by the meta-object compiler (moc). Then Qt can call the needed method based on that string with argument type checking and such. The arguments for the slots are packed through a special utility class (e.g. see Q_ARG macro in the docs and QGenericArgument).

    JonBJ Offline
    JonBJ Offline
    JonB
    wrote on last edited by kshegunov
    #13

    @kshegunov
    [You don't show the definition of the SLOT() macro too?]
    Edit: Yeah, sorry, I've added it to the post ~kshegunov

    Ah, that is very interesting indeed, thank you.

    Note that it looks quite different from what I am writing in my code from Python/PyQt, e.g.:
    self.btnDelete.clicked.connect(self.deletePayment)

    Note how the slot-handling function is written as func not func() (i.e. function reference not call), which is much more what I expected.

    kshegunovK 1 Reply Last reply
    0
    • JonBJ JonB

      @kshegunov
      [You don't show the definition of the SLOT() macro too?]
      Edit: Yeah, sorry, I've added it to the post ~kshegunov

      Ah, that is very interesting indeed, thank you.

      Note that it looks quite different from what I am writing in my code from Python/PyQt, e.g.:
      self.btnDelete.clicked.connect(self.deletePayment)

      Note how the slot-handling function is written as func not func() (i.e. function reference not call), which is much more what I expected.

      kshegunovK Offline
      kshegunovK Offline
      kshegunov
      Moderators
      wrote on last edited by
      #14

      @JNBarchan said in GUI blocking...:

      i.e. function reference not call

      In C++ that would not be a call, but rather the signature (the declaration). It's needed to know by the meta-object system so the magic of finding the correct overloads and the correct arguments, and name to be found in the generated by moc data. The resolution to a pointer to the function is done in runtime. In Qt 5 however, a pointer-to-member should be passed (thus resolution to a an address is at compile time) and there is some very different template magic at work in that case.

      Read and abide by the Qt Code of Conduct

      JonBJ 1 Reply Last reply
      1
      • kshegunovK kshegunov

        @JNBarchan said in GUI blocking...:

        i.e. function reference not call

        In C++ that would not be a call, but rather the signature (the declaration). It's needed to know by the meta-object system so the magic of finding the correct overloads and the correct arguments, and name to be found in the generated by moc data. The resolution to a pointer to the function is done in runtime. In Qt 5 however, a pointer-to-member should be passed (thus resolution to a an address is at compile time) and there is some very different template magic at work in that case.

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

        @kshegunov said in GUI blocking...:

        In Qt 5 however, a pointer-to-member should be passed (thus resolution to a an address is at compile time) and there is some very different template magic at work in that case.

        Yes indeed, and this seems to be what the inherited Python/PyQt code I have uses (and that used to work in that code in Qt4/PyQt4 too).

        It's clearly a lot more efficient to pass a direct function address at "compile" time than to look up strings of names at runtime.

        P.S.
        Sorry if I have hijacked this thread. If you feel you want to move your exchange with me from here to its own thread I would quite understand.

        A 1 Reply Last reply
        0
        • JonBJ JonB

          @kshegunov said in GUI blocking...:

          In Qt 5 however, a pointer-to-member should be passed (thus resolution to a an address is at compile time) and there is some very different template magic at work in that case.

          Yes indeed, and this seems to be what the inherited Python/PyQt code I have uses (and that used to work in that code in Qt4/PyQt4 too).

          It's clearly a lot more efficient to pass a direct function address at "compile" time than to look up strings of names at runtime.

          P.S.
          Sorry if I have hijacked this thread. If you feel you want to move your exchange with me from here to its own thread I would quite understand.

          A Offline
          A Offline
          Aesgarth
          wrote on last edited by
          #16

          @JNBarchan said in GUI blocking...:

          P.S.
          Sorry if I have hijacked this thread. If you feel you want to move your exchange with me from here to its own thread I would quite understand.

          Feel free to carry on here, i might just learn something...

          1 Reply Last reply
          1
          • Pablo J. RoginaP Offline
            Pablo J. RoginaP Offline
            Pablo J. Rogina
            wrote on last edited by
            #17

            Feel free to carry on here, i might just learn something...

            Guys, please respect the forum etiquette. It's not good to hijack threads :-)

            Feell free to start another post for this ongoing exchange about a topic different from the original post. Thank you.

            Upvote the answer(s) that helped you solve the issue
            Use "Topic Tools" button to mark your post as Solved
            Add screenshots via postimage.org
            Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

            1 Reply Last reply
            2
            • Pablo J. RoginaP Pablo J. Rogina

              @Aesgarth loops related to GUI/user events in Qt applications are not a good idea... that's why Qt's provide its own event loop and the magic of signals.

              I assume that the QPushButtons you're using are checkable, and you may want to pay attention to the toggled(bool checked) signal so you can react to the button state changes (checked or unchecked).

              the button is turning a physical relay on and off at fixed intervals.

              I guess you're not stated your requirements well. Let's assume that if I click/check button for relay #1 it will be on for M seconds, then off for N seconds, then on for M seconds again and so on.
              So I'd use the suggestion from jsulm of using QTimer but in this case I'd use 2 timers: one with the duration of on period, and when this timer is off, the off timer is fired; and then the process will alternate until the button is unchecked where everything will stop.

              wiringPiSetup();       // only call once in the application
              QTimer timerRelay4On = new QTimer(this);
              timerRelay4On->setInterval(relay4IntervalOn);
              timerRelay4On->setSingleShot(true);
              connect(timerRelay4On, SLOT(sendLow(pin)));
              
              QTimer timerRelay4Off = new QTimer(this);
              timerRelay4Off->setInterval(relay4IntervalOff);
              timerRelay4Off->setSingleShot(true);
              connect(timerRelay4Off, SLOT(sendHigh(pin)));
              
              void MainWindow::on_pushButton_4_toggled(bool checked)
              {
                  pinMode(0, OUTPUT);
                  if (checked) {
                      // button initially checked
                      // make the ball roll... on -> off -> on -> off -> etc
                      sendHigh(0);
                  } else {
                      // button unchecked
                      // everything must stop
                      sendLow(0);
                      timerReleay4Off->stop();
                      timerReleay4On->stop();
                  }
              }
              
              void MainWindow::sendHigh(int pin)
              {
                  digitalWrite(pin, HIGH);
                  timerRelay4Off->start();
              }
              
              void MainWindow::sendLow(int pin)
              {
                  digitalWrite(pin, LOW);
                  timerRelay4On->start();
              }
              

              Spoiler alert: code was written directly in post, it might not compile as is.
              For better code standards, you may want to use meaningful constants for pin values, i.e.

              sendHigh(PIN0_RELAY_BEDROOM_LIGHT);
              

              instead of

              sendHigh(0);
              

              Happy relay control!

              A Offline
              A Offline
              Aesgarth
              wrote on last edited by
              #18

              @Pablo-J.-Rogina

              Can you explain to me what this is doing, as if explaining to a very small child...

              wiringPiSetup();       // only call once in the application
              QTimer timerRelay4On = new QTimer(this);
              timerRelay4On->setInterval(relay4IntervalOn);
              timerRelay4On->setSingleShot(true);
              connect(timerRelay4On, SLOT(sendLow(pin)));
              
              QTimer timerRelay4Off = new QTimer(this);
              timerRelay4Off->setInterval(relay4IntervalOff);
              timerRelay4Off->setSingleShot(true);
              connect(timerRelay4Off, SLOT(sendHigh(pin)));
              

              thanks.

              jsulmJ 1 Reply Last reply
              0
              • A Aesgarth

                @Pablo-J.-Rogina

                Can you explain to me what this is doing, as if explaining to a very small child...

                wiringPiSetup();       // only call once in the application
                QTimer timerRelay4On = new QTimer(this);
                timerRelay4On->setInterval(relay4IntervalOn);
                timerRelay4On->setSingleShot(true);
                connect(timerRelay4On, SLOT(sendLow(pin)));
                
                QTimer timerRelay4Off = new QTimer(this);
                timerRelay4Off->setInterval(relay4IntervalOff);
                timerRelay4Off->setSingleShot(true);
                connect(timerRelay4Off, SLOT(sendHigh(pin)));
                

                thanks.

                jsulmJ Offline
                jsulmJ Offline
                jsulm
                Lifetime Qt Champion
                wrote on last edited by jsulm
                #19

                @Aesgarth This code will not work.
                First:

                QTimer *timerRelay4On = new QTimer(this); // timerRelay4On needs to be pointer else it will not even compile
                

                Second:

                connect(timerRelay4On, SLOT(sendLow(pin)));
                connect(timerRelay4Off, SLOT(sendHigh(pin)));
                

                both connects are wrong: where are signal and pointer to receiver object? Check documentation for proper connect usage. The slots used require a parameter (pin) which cannot be passed from the timer (QTimer does not know anything about pins) - so, signal and slot will not match.
                This code can be simplified using static http://doc.qt.io/qt-5/qtimer.html#singleShot method (no need to create an instance of QTimer).

                What the source code will do after the issues were fixed: after some time (defined by relay4IntervalOn) sendLow() will be called, after some time (defined by relay4IntervalOff) sendHigh() will be called.

                https://forum.qt.io/topic/113070/qt-code-of-conduct

                A 1 Reply Last reply
                0
                • Pablo J. RoginaP Offline
                  Pablo J. RoginaP Offline
                  Pablo J. Rogina
                  wrote on last edited by
                  #20

                  To all, as previously pointed out, my code was not tested just provided as a guideline of what might be a possible approach to your requirements. Here you have the snippet of a working example for a checkable button starting the process and the ON/OFF cycle running on intervals of 3 secs ON and 1 sec OFF until the button is unchecked again when the timers are stopped. References to wiringPi library's functions are commented out since I'm not using it for this example, but for reference where they should be. No more code examples will be provided from my side. Thank you.

                  ...
                  MainWindow::MainWindow(QWidget *parent) :
                      QMainWindow(parent),
                      ui(new Ui::MainWindow)
                  {
                      ui->setupUi(this);
                  
                      timerRelay1On = new QTimer(this);
                      timerRelay1On->setInterval(3000);
                      timerRelay1On->setSingleShot(true);
                      connect(timerRelay1On, SIGNAL(timeout()), this, SLOT(sendLow()));
                  
                      timerRelay1Off = new QTimer(this);
                      timerRelay1Off->setInterval(1000);
                      timerRelay1Off->setSingleShot(true);
                      connect(timerRelay1Off, SIGNAL(timeout()), this, SLOT(sendHigh()));
                  }
                  
                  MainWindow::~MainWindow()
                  {
                      delete ui;
                  }
                  
                  void MainWindow::on_btnRelay1_toggled() {
                      pin = 0;
                  //    pinMode(pin, OUTPUT);
                      if (ui->btnRelay1->isChecked()) {
                          // button initially checked
                          // make the ball roll... on -> off -> on -> off -> etc
                          sendHigh();
                      } else {
                          // button unchecked
                          // everything must stop
                          timerRelay1Off->stop();
                          timerRelay1On->stop();
                          qDebug() << "Everything stopped!";
                      }
                  }
                  
                  void MainWindow::sendHigh()
                  {
                  //    digitalWrite(pin, HIGH);
                      qDebug() << "Pin " << pin << " HIGH";
                      timerRelay1On->start();
                      qDebug() << QDateTime::currentDateTime() << ": Timer ON started";
                  }
                  
                  void MainWindow::sendLow()
                  {
                  //    digitalWrite(pin, LOW);
                      qDebug() << "Pin " << pin << " LOW";
                      timerRelay1Off->start();
                      qDebug() << QDateTime::currentDateTime() << ": Timer OFF started";
                  }
                  

                  Upvote the answer(s) that helped you solve the issue
                  Use "Topic Tools" button to mark your post as Solved
                  Add screenshots via postimage.org
                  Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

                  A 1 Reply Last reply
                  1
                  • jsulmJ jsulm

                    @Aesgarth This code will not work.
                    First:

                    QTimer *timerRelay4On = new QTimer(this); // timerRelay4On needs to be pointer else it will not even compile
                    

                    Second:

                    connect(timerRelay4On, SLOT(sendLow(pin)));
                    connect(timerRelay4Off, SLOT(sendHigh(pin)));
                    

                    both connects are wrong: where are signal and pointer to receiver object? Check documentation for proper connect usage. The slots used require a parameter (pin) which cannot be passed from the timer (QTimer does not know anything about pins) - so, signal and slot will not match.
                    This code can be simplified using static http://doc.qt.io/qt-5/qtimer.html#singleShot method (no need to create an instance of QTimer).

                    What the source code will do after the issues were fixed: after some time (defined by relay4IntervalOn) sendLow() will be called, after some time (defined by relay4IntervalOff) sendHigh() will be called.

                    A Offline
                    A Offline
                    Aesgarth
                    wrote on last edited by
                    #21

                    @jsulm

                    Thanks. I have your code from above working, using QTimer - and behaving correctly... what i'm now trying to do is repeat the operation while the button is checked but also stopped when it is unchecked.. That sounded like an ideal solution but I haven't tried it as i couldn't work out how it worked... I guess i'll have to keep trying.

                    as another issue, when i attempt to do wiringPiSetup() as i have above it dosen't work, until a button that has it in is pushed. can i run it when the program starts? if so how?

                    1 Reply Last reply
                    0
                    • Pablo J. RoginaP Pablo J. Rogina

                      To all, as previously pointed out, my code was not tested just provided as a guideline of what might be a possible approach to your requirements. Here you have the snippet of a working example for a checkable button starting the process and the ON/OFF cycle running on intervals of 3 secs ON and 1 sec OFF until the button is unchecked again when the timers are stopped. References to wiringPi library's functions are commented out since I'm not using it for this example, but for reference where they should be. No more code examples will be provided from my side. Thank you.

                      ...
                      MainWindow::MainWindow(QWidget *parent) :
                          QMainWindow(parent),
                          ui(new Ui::MainWindow)
                      {
                          ui->setupUi(this);
                      
                          timerRelay1On = new QTimer(this);
                          timerRelay1On->setInterval(3000);
                          timerRelay1On->setSingleShot(true);
                          connect(timerRelay1On, SIGNAL(timeout()), this, SLOT(sendLow()));
                      
                          timerRelay1Off = new QTimer(this);
                          timerRelay1Off->setInterval(1000);
                          timerRelay1Off->setSingleShot(true);
                          connect(timerRelay1Off, SIGNAL(timeout()), this, SLOT(sendHigh()));
                      }
                      
                      MainWindow::~MainWindow()
                      {
                          delete ui;
                      }
                      
                      void MainWindow::on_btnRelay1_toggled() {
                          pin = 0;
                      //    pinMode(pin, OUTPUT);
                          if (ui->btnRelay1->isChecked()) {
                              // button initially checked
                              // make the ball roll... on -> off -> on -> off -> etc
                              sendHigh();
                          } else {
                              // button unchecked
                              // everything must stop
                              timerRelay1Off->stop();
                              timerRelay1On->stop();
                              qDebug() << "Everything stopped!";
                          }
                      }
                      
                      void MainWindow::sendHigh()
                      {
                      //    digitalWrite(pin, HIGH);
                          qDebug() << "Pin " << pin << " HIGH";
                          timerRelay1On->start();
                          qDebug() << QDateTime::currentDateTime() << ": Timer ON started";
                      }
                      
                      void MainWindow::sendLow()
                      {
                      //    digitalWrite(pin, LOW);
                          qDebug() << "Pin " << pin << " LOW";
                          timerRelay1Off->start();
                          qDebug() << QDateTime::currentDateTime() << ": Timer OFF started";
                      }
                      
                      A Offline
                      A Offline
                      Aesgarth
                      wrote on last edited by
                      #22

                      @Pablo-J.-Rogina

                      Thanks, very much appreciated. I'll give that a go.

                      1 Reply Last reply
                      0
                      • Pablo J. RoginaP Offline
                        Pablo J. RoginaP Offline
                        Pablo J. Rogina
                        wrote on last edited by Pablo J. Rogina
                        #23

                        @Aesgarth you need to call wiringPiSetup() only once in your application, maybe in main.cpp before starting Qt event loop, on in MainWindow constructor for instance. Also don't forget that it needs to be called with root privileges... see here.

                        Upvote the answer(s) that helped you solve the issue
                        Use "Topic Tools" button to mark your post as Solved
                        Add screenshots via postimage.org
                        Don't ask support requests via chat/PM. Please use the forum so others can benefit from the solution in the future

                        A 1 Reply Last reply
                        0
                        • Pablo J. RoginaP Pablo J. Rogina

                          @Aesgarth you need to call wiringPiSetup() only once in your application, maybe in main.cpp before starting Qt event loop, on in MainWindow constructor for instance. Also don't forget that it needs to be called with root privileges... see here.

                          A Offline
                          A Offline
                          Aesgarth
                          wrote on last edited by
                          #24

                          @Pablo-J.-Rogina said in GUI blocking...:

                          @Aesgarth you need to call wiringPiSetup() only once in your application, maybe in main.cpp before starting Qt event loop, on in MainWindow constructor for instance. Also don't forget that it needs to be called with root privileges... see here.

                          Thanks, putting it in the constructor worked - I'd put it in the wrong place earlier.

                          Re the timer issue, having tried your example above i'm getting the error
                          timerRelay1On was not declared in this scope
                          but i've probably done something wrong. I'll keep trying.

                          thanks again.

                          jsulmJ 1 Reply Last reply
                          0
                          • A Aesgarth

                            @Pablo-J.-Rogina said in GUI blocking...:

                            @Aesgarth you need to call wiringPiSetup() only once in your application, maybe in main.cpp before starting Qt event loop, on in MainWindow constructor for instance. Also don't forget that it needs to be called with root privileges... see here.

                            Thanks, putting it in the constructor worked - I'd put it in the wrong place earlier.

                            Re the timer issue, having tried your example above i'm getting the error
                            timerRelay1On was not declared in this scope
                            but i've probably done something wrong. I'll keep trying.

                            thanks again.

                            jsulmJ Offline
                            jsulmJ Offline
                            jsulm
                            Lifetime Qt Champion
                            wrote on last edited by
                            #25

                            @Aesgarth said in GUI blocking...:

                            timerRelay1On was not declared in this scope

                            Well, you have to declare timerRelay1On somewhere before you can use it. Either add it as class member to MainWindow or just do

                            QTimer *timerRelay1On = new QTimer(this);
                            

                            https://forum.qt.io/topic/113070/qt-code-of-conduct

                            1 Reply Last reply
                            1

                            • Login

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