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. How to notify table Widget from different thread that data is updated.
Forum Updated to NodeBB v4.3 + New Features

How to notify table Widget from different thread that data is updated.

Scheduled Pinned Locked Moved Unsolved General and Desktop
5 Posts 3 Posters 754 Views 1 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.
  • A Offline
    A Offline
    anoop1
    wrote on last edited by anoop1
    #1

    I have a callback function:

    def data_callback(self, data):
        for dd in data:
            index = self.get_index(dd ["ind"])
            val1= dd["val1"]
            val2 = "xx"
            self.tableWidget.item(index, 2).setText(str(val1))
            self.tableWidget.item(index, 3).setText(str(val2))
            #  self.tableWidget.itemChanged(self.tableWidget.itemAt(index, 2))
    

    This callback function get data from a websocket. The problem is that I am not able to see the updated data. I have to make some event on the table Widget (like clicking on a cell) to get the new modified data. So I am looking for a way to notify table Widget that data is modified.

    CODE::

    from PyQt5 import QtWidgets, uic
    from PyQt5.QtWidgets import QTableWidgetItem, QHeaderView
    
    
    class TEST(QtWidgets.QFrame):
        def __init__(self, api):
            self.api = api
            super(TEST, self).__init__()
            uic.loadUi('./UI/DATA.ui', self)
    
            self.data = [1, 2, 3, 4]
            self.tableWidget = self.findChild(QtWidgets.QTableWidget, 'tableWidget')
            self.pushButton = self.findChild(QtWidgets.QPushButton, 'pushButton')
    
            self.pushButton.clicked.connect(self.action_push_button)
    
            self.tableWidget.horizontalHeader().setStretchLastSection(True)
            self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
            self.tableWidget.setColumnCount(4)
            self.tableWidget.setRowCount(4)
            self.current_rows = 0
    
        def action_push_button(self):
            self.api.socket.subscribe_callback(self.data_callback)
            for dd in self.data:
                data = self.api.get_data(dd)
                val1 = data["val1"]
                val2 = data["val2"]
                self.add_row(val1, val2, "0.0", "?")
    
        def add_row(self, val1, val2, val3, val4):
            self.tableWidget.setItem(self.current_rows, 0, QTableWidgetItem(str(val1)))
            self.tableWidget.setItem(self.current_rows, 1, QTableWidgetItem(str(val2)))
            self.tableWidget.setItem(self.current_rows, 2, QTableWidgetItem(str(val3)))
            self.tableWidget.setItem(self.current_rows, 3, QTableWidgetItem(str(val4)))
            self.current_rows += 1
    
        def update_row(self, index, val1, val2):
            self.tableWidget.item(index, 2).setText(str(val1))
            self.tableWidget.item(index, 3).setText(str(val2))
    
        def data_callback(self, data):
            for val in data:
                ind = self.get_index(val["ind"])
                val1 = val["val1"]
                val2 = "XX"
                self.update_row(ind, val1, val2)
    
    JonBJ 1 Reply Last reply
    0
    • A anoop1

      I have a callback function:

      def data_callback(self, data):
          for dd in data:
              index = self.get_index(dd ["ind"])
              val1= dd["val1"]
              val2 = "xx"
              self.tableWidget.item(index, 2).setText(str(val1))
              self.tableWidget.item(index, 3).setText(str(val2))
              #  self.tableWidget.itemChanged(self.tableWidget.itemAt(index, 2))
      

      This callback function get data from a websocket. The problem is that I am not able to see the updated data. I have to make some event on the table Widget (like clicking on a cell) to get the new modified data. So I am looking for a way to notify table Widget that data is modified.

      CODE::

      from PyQt5 import QtWidgets, uic
      from PyQt5.QtWidgets import QTableWidgetItem, QHeaderView
      
      
      class TEST(QtWidgets.QFrame):
          def __init__(self, api):
              self.api = api
              super(TEST, self).__init__()
              uic.loadUi('./UI/DATA.ui', self)
      
              self.data = [1, 2, 3, 4]
              self.tableWidget = self.findChild(QtWidgets.QTableWidget, 'tableWidget')
              self.pushButton = self.findChild(QtWidgets.QPushButton, 'pushButton')
      
              self.pushButton.clicked.connect(self.action_push_button)
      
              self.tableWidget.horizontalHeader().setStretchLastSection(True)
              self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
              self.tableWidget.setColumnCount(4)
              self.tableWidget.setRowCount(4)
              self.current_rows = 0
      
          def action_push_button(self):
              self.api.socket.subscribe_callback(self.data_callback)
              for dd in self.data:
                  data = self.api.get_data(dd)
                  val1 = data["val1"]
                  val2 = data["val2"]
                  self.add_row(val1, val2, "0.0", "?")
      
          def add_row(self, val1, val2, val3, val4):
              self.tableWidget.setItem(self.current_rows, 0, QTableWidgetItem(str(val1)))
              self.tableWidget.setItem(self.current_rows, 1, QTableWidgetItem(str(val2)))
              self.tableWidget.setItem(self.current_rows, 2, QTableWidgetItem(str(val3)))
              self.tableWidget.setItem(self.current_rows, 3, QTableWidgetItem(str(val4)))
              self.current_rows += 1
      
          def update_row(self, index, val1, val2):
              self.tableWidget.item(index, 2).setText(str(val1))
              self.tableWidget.item(index, 3).setText(str(val2))
      
          def data_callback(self, data):
              for val in data:
                  ind = self.get_index(val["ind"])
                  val1 = val["val1"]
                  val2 = "XX"
                  self.update_row(ind, val1, val2)
      
      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @anoop1
      Hi and welcome.

      This callback function get data from a websocket.

      Your method has self.tableWidget. That looks like self is some UI widget, nothing to do with websocket.

      So I am looking for a way to notify table Widget that data is modified.

      The above method changes self.tableWidget, so it does not need to notify table widget itself of anything.

      OK, I think I understand what you mean. The code you show is what you have in the UI which will update the table widget as you desire. You are asking how to get to call that when data has changed from the websocket, right?

      So in your websocket code in another thread you need to define your own signal and emit that signal when it has gathered new data/wants the UI to update. In your UI code in its own thread, you will place a slot on that signal, and that can call your method above. This signal/slot approach is how we have non-UI threads inform the UI thread of something, because non-UI threads must not themselves directly call UI code.

      A 1 Reply Last reply
      1
      • JonBJ JonB

        @anoop1
        Hi and welcome.

        This callback function get data from a websocket.

        Your method has self.tableWidget. That looks like self is some UI widget, nothing to do with websocket.

        So I am looking for a way to notify table Widget that data is modified.

        The above method changes self.tableWidget, so it does not need to notify table widget itself of anything.

        OK, I think I understand what you mean. The code you show is what you have in the UI which will update the table widget as you desire. You are asking how to get to call that when data has changed from the websocket, right?

        So in your websocket code in another thread you need to define your own signal and emit that signal when it has gathered new data/wants the UI to update. In your UI code in its own thread, you will place a slot on that signal, and that can call your method above. This signal/slot approach is how we have non-UI threads inform the UI thread of something, because non-UI threads must not themselves directly call UI code.

        A Offline
        A Offline
        anoop1
        wrote on last edited by anoop1
        #3

        @JonB Hello JonB thank you for your response I have updated my code for the UI that I am using. update_row is the the function which I use to update data of specific cell when I run the function update_row without callback (directly from main thread) there is no problem I can see the updated data but when I am using update_row in callback I can't see the updated data but the data is updated I have to click on some cell to make some event and I get updated data at the cell. data_callback is the callback function called from the api and I am getting data in data_callback without any problem all I want to update the table widget data so I can see the update in the table (without doing some event like clicking on the cell). I know this is weird that table widget shows the updated data when I click on the cell maybe it causes some refresh notification or something. Can you link some examples to signal/slot method.

        JonBJ 1 Reply Last reply
        0
        • A anoop1

          @JonB Hello JonB thank you for your response I have updated my code for the UI that I am using. update_row is the the function which I use to update data of specific cell when I run the function update_row without callback (directly from main thread) there is no problem I can see the updated data but when I am using update_row in callback I can't see the updated data but the data is updated I have to click on some cell to make some event and I get updated data at the cell. data_callback is the callback function called from the api and I am getting data in data_callback without any problem all I want to update the table widget data so I can see the update in the table (without doing some event like clicking on the cell). I know this is weird that table widget shows the updated data when I click on the cell maybe it causes some refresh notification or something. Can you link some examples to signal/slot method.

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

          @anoop1
          I don't see you are saying anything different from above.

          How to notify table Widget from different thread that data is updated.

          I said what you must do in my reply: create your own signal from the thread which knows there is new data and emit it, UI thread can place a slot on that.

          If you are not familiar with signals & slots --- which is at the heart of Qt -- read https://doc.qt.io/qt-5/signalsandslots.html.

          1 Reply Last reply
          2
          • S Offline
            S Offline
            SimonSchroeder
            wrote on last edited by
            #5

            You should not call any functions on self.tableWidget from any other thread but the GUI thread if these will update the view. I had my applications crash a couple of times when I accidentally got it wrong. Only the GUI thread is allowed to paint the widgets and many functions therefore need to be called in its context.

            One way is to connect a signal from you extra thread to a slot of an object living inside the GUI thread to hand over the data and let that slot update the widget. Here is an example (sorry, I only know C++-syntax, so I am going to mix a little):

            connect(this, &MyClass::mySignal, qApp, [&](self, index, val1, val2) { self.update_row(index, val1, val2); });
            ...
            emit self.mySignal(index, val1, vals2);
            

            The other way is to explicitly put calls to these functions into the GUI thread:

            QMetaObject::invokeMethod(qApp, [&]() { self.update_row(index, val1, val2); });
            

            I am not sure how well these translate into Python (especially with lambdas). However, the first version can also be written without the lambda function.

            1 Reply Last reply
            2

            • Login

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