Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Mobile and Embedded
  4. Keeping the UI alive
QtWS25 Last Chance

Keeping the UI alive

Scheduled Pinned Locked Moved Unsolved Mobile and Embedded
8 Posts 4 Posters 401 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.
  • D Offline
    D Offline
    Dallas Posey
    wrote on last edited by
    #1

    Hi there,

    I have a QT 5.15 application that runs under Linux on an stm32mp157 based SOM from Digi. Has a 320x280 TFT display, 4x7 membrane keypad and an Xbee3 for communicating with other nodes. The display is managed by wayland/weston and I have a number of windows that the user sees to implement the UI. The screens are all navigated with key-presses which are signaled from a timer handler created by MainWindow. The timer handler wakes up every 100ms, scans the key-matrix and emits a signal if a key is pressed. The window objects connect to the keypress signal, one at a time of course, whichever is active, and process the keycodes appropriately. All works really well and I must say, for my first exposure to QT, I am really impressed by it!

    The problem: When the user initiates a unit of work that requires me to send data over the Xbee, the screen disappears and the user sees the underlying weston desktop. Clearly this is because the code ends up blocked down in QSerialPort somewhere (actually inside the Linux serial subsystem I would suspect). So the question is what is the best solution to keep the GUI running. What thread is the keypress signal handler running on? When a signal is handled by a slot connected to it, does it run on the signaler's thread, i.e. the timer handler thread in this case? Or does emit() cause a new thread to be created for the slots connected to it?

    Anyway I'm just looking for the best way to hand-off the work of talking to the XBee to something that won't starve the UI while it is busy chugging away at 9600 baud ...

    -Dallas

    JonBJ 1 Reply Last reply
    0
    • D Dallas Posey

      Hi there,

      I have a QT 5.15 application that runs under Linux on an stm32mp157 based SOM from Digi. Has a 320x280 TFT display, 4x7 membrane keypad and an Xbee3 for communicating with other nodes. The display is managed by wayland/weston and I have a number of windows that the user sees to implement the UI. The screens are all navigated with key-presses which are signaled from a timer handler created by MainWindow. The timer handler wakes up every 100ms, scans the key-matrix and emits a signal if a key is pressed. The window objects connect to the keypress signal, one at a time of course, whichever is active, and process the keycodes appropriately. All works really well and I must say, for my first exposure to QT, I am really impressed by it!

      The problem: When the user initiates a unit of work that requires me to send data over the Xbee, the screen disappears and the user sees the underlying weston desktop. Clearly this is because the code ends up blocked down in QSerialPort somewhere (actually inside the Linux serial subsystem I would suspect). So the question is what is the best solution to keep the GUI running. What thread is the keypress signal handler running on? When a signal is handled by a slot connected to it, does it run on the signaler's thread, i.e. the timer handler thread in this case? Or does emit() cause a new thread to be created for the slots connected to it?

      Anyway I'm just looking for the best way to hand-off the work of talking to the XBee to something that won't starve the UI while it is busy chugging away at 9600 baud ...

      -Dallas

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

      @Dallas-Posey
      I would like to try to answer briefly, in the hope it may be of some use. I am afraid I know nothing about devices, realtime or embedded systems. I just want to clarify how Qt for, say, a desktop system works.

      You have a main thread. That handles all the UI output, and also any keypress inputs. Qt is not creating multiple threads for you. The UI remains responsive so long as it is not off performing some time consuming computation.

      If threads are involved at all, where a slot runs depends on how it has been connect()ed to the signal and which thread(s) the signalling and slot object(s) live in. By default, if signalling object and slot object are both in the same thread then it defaults to DirectConnection, meaning that the slot runs in same thread as the signaller and in fact it is called immediately as a direct function call. If they are in different threads then the default is QueuedConnection: the signal is emitted from its thread but placed in queue. When the main Qt event loop is next entered the queued signal's slot is run in the thread of the slot object. Have a read of https://doc.qt.io/qt-6/threads-qobject.html#signals-and-slots-across-threads. Qt does not auto-create new threads for you, and its emit keyword us actually #defined to the empty string, so it does nothing at all in itself and is merely there for you as a programmer to "look at".

      As you describe the situation I do not see that you would need to create any threads at all, at least in my knowledge of a desktop version. You might use a blocking serial port call and hence need a thread in a "traditional" Linux application, but Qt's QSerialPort functions asynchronously so you can just use it from the main thread, acting on its readyRead() signal without blocking the UI.

      The time you do need a thread is only if you want to do heavy computation during a slot on the main thread. For example, if in response to a serial byte arriving or similar you want to calculate the first one million prime numbers that would indeed block the UI, and you could move the computation off to its own thread.

      As I said, I do not know whether this helps or applies to your particular situation or whether that has something very different going on, but maybe it gives some clarity.

      D 1 Reply Last reply
      0
      • JonBJ JonB

        @Dallas-Posey
        I would like to try to answer briefly, in the hope it may be of some use. I am afraid I know nothing about devices, realtime or embedded systems. I just want to clarify how Qt for, say, a desktop system works.

        You have a main thread. That handles all the UI output, and also any keypress inputs. Qt is not creating multiple threads for you. The UI remains responsive so long as it is not off performing some time consuming computation.

        If threads are involved at all, where a slot runs depends on how it has been connect()ed to the signal and which thread(s) the signalling and slot object(s) live in. By default, if signalling object and slot object are both in the same thread then it defaults to DirectConnection, meaning that the slot runs in same thread as the signaller and in fact it is called immediately as a direct function call. If they are in different threads then the default is QueuedConnection: the signal is emitted from its thread but placed in queue. When the main Qt event loop is next entered the queued signal's slot is run in the thread of the slot object. Have a read of https://doc.qt.io/qt-6/threads-qobject.html#signals-and-slots-across-threads. Qt does not auto-create new threads for you, and its emit keyword us actually #defined to the empty string, so it does nothing at all in itself and is merely there for you as a programmer to "look at".

        As you describe the situation I do not see that you would need to create any threads at all, at least in my knowledge of a desktop version. You might use a blocking serial port call and hence need a thread in a "traditional" Linux application, but Qt's QSerialPort functions asynchronously so you can just use it from the main thread, acting on its readyRead() signal without blocking the UI.

        The time you do need a thread is only if you want to do heavy computation during a slot on the main thread. For example, if in response to a serial byte arriving or similar you want to calculate the first one million prime numbers that would indeed block the UI, and you could move the computation off to its own thread.

        As I said, I do not know whether this helps or applies to your particular situation or whether that has something very different going on, but maybe it gives some clarity.

        D Offline
        D Offline
        Dallas Posey
        wrote on last edited by
        #3

        @JonB Thank you! That was a very informative and helpful response. So the MainWindow is running on the main thread. It starts a timer connected to a handler, scanKeyPad which signals keyCode when a key is pressed. When the timer expires I assume that scanKeyPad runs on a new thread and any object created by MainWindow with a slot that is connected to signal keyCode gets queued and runs in it's turn on the main thread? Anyway, again, your answer is both helpful and intriguing and I will read further (as you suggest).

        -Dallas

        Pl45m4P JonBJ 2 Replies Last reply
        0
        • D Dallas Posey

          @JonB Thank you! That was a very informative and helpful response. So the MainWindow is running on the main thread. It starts a timer connected to a handler, scanKeyPad which signals keyCode when a key is pressed. When the timer expires I assume that scanKeyPad runs on a new thread and any object created by MainWindow with a slot that is connected to signal keyCode gets queued and runs in it's turn on the main thread? Anyway, again, your answer is both helpful and intriguing and I will read further (as you suggest).

          -Dallas

          Pl45m4P Offline
          Pl45m4P Offline
          Pl45m4
          wrote on last edited by Pl45m4
          #4

          @Dallas-Posey said in Keeping the UI alive:

          When the timer expires I assume that scanKeyPad runs on a new thread and any object created by MainWindow with a slot that is connected to signal keyCode gets queued and runs in it's turn on the main thread?

          No, a QTimer does not create or run separate threads.
          A simple QTimer is asynchronous but still a single thread solution.
          (Same as when using Qt's Signal & Slot mechanism).

          Both are handled in the Qt Event Loop of your app's main thread (that thread that holds your Q(Gui)Application).
          Unless you create a new QTimer object in a separate thread explicitely, of course.


          If debugging is the process of removing software bugs, then programming must be the process of putting them in.

          ~E. W. Dijkstra

          1 Reply Last reply
          2
          • D Dallas Posey

            @JonB Thank you! That was a very informative and helpful response. So the MainWindow is running on the main thread. It starts a timer connected to a handler, scanKeyPad which signals keyCode when a key is pressed. When the timer expires I assume that scanKeyPad runs on a new thread and any object created by MainWindow with a slot that is connected to signal keyCode gets queued and runs in it's turn on the main thread? Anyway, again, your answer is both helpful and intriguing and I will read further (as you suggest).

            -Dallas

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

            @Dallas-Posey said in Keeping the UI alive:

            When the timer expires I assume that scanKeyPad runs on a new thread

            All as @Pl45m4 has written above. Like I said, honestly unless you create them yourself Qt does not create threads for you "behind the scenes". At least mostly, for your purposes, and keeping it simple, before I get into hot waters. Don't assume there is any threading going on.

            1 Reply Last reply
            0
            • D Offline
              D Offline
              Dallas Posey
              wrote on last edited by
              #6

              Got it. I think what kills my UI is that I have to inject an inter-character delay when I write to the serial port, this being required by other nodes in the XBee network. So I write a char, usleep(5000), write another ... until done. Unfortunately the remote nodes are pretty slow and won't work with less than 5ms between octets. I need to get that usleep outta there somehow ...

              jsulmJ 1 Reply Last reply
              0
              • D Dallas Posey

                Got it. I think what kills my UI is that I have to inject an inter-character delay when I write to the serial port, this being required by other nodes in the XBee network. So I write a char, usleep(5000), write another ... until done. Unfortunately the remote nodes are pretty slow and won't work with less than 5ms between octets. I need to get that usleep outta there somehow ...

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

                @Dallas-Posey You can use QTimer instead of waiting. Then it should also work in main thread. Or you move the serial communication into a thread. But I would first try the QTimer approach because it is easier to implement.

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

                1 Reply Last reply
                2
                • D Offline
                  D Offline
                  Dallas Posey
                  wrote on last edited by
                  #8

                  Thanks @jsulm I'll give it a go immediately!

                  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