title: Emit signals from Worker threads to Main window and back using @pyqtSlot decorators
body: <p>I'm currently learning to build GUI's using PyQt5 and here is my problem:
  I have 2 Threads. The first one is <code>QThread</code> object which generates some data.
  The other one is <code>QObject</code> function which runs in <code>QThread</code> using <code>.moveToThread</code> method and processes data received from my so-called data generator. On main window I emit signal to do some stuff with value returned from generator separately from main thread in order to avoid freezing GUI.
  The processing looks like:</p>
  <ul>
  <li>receive data;</li>
  <li>append it to list;</li>
  <li>if list is full enough to make some calculations -&gt; emit the result back to GUI;</li>
  <li>wait some time (e.g. 3 secs) and start again the reception of data.</li>
  </ul>
  <p>The problem is in the last point. I freeze the thread after calculations on list items, but it does not block signal emitted from the GUI, so when <code>time.sleep(3)</code> is up, my list already contains 3 items, but I need to start it from 0.
  Commented fragments of code are my thoughts on how to do it using <code>@pyqtSlot</code> decorators and <code>QtCore.pyqtSignal()</code> but it doesn`t work.</p>
  <p>Let me know if any clarification is needed, maybe I missed something.</p>
  <p>Will be glad for any help.</p>
  <p>Here is my code:</p>
  <pre><code>import sys
  from PyQt5.QtWidgets import QWidget, QPushButton, QApplication, QGridLayout, QLabel
  from PyQt5.QtCore import QObject, QThread, pyqtSlot
  from PyQt5 import QtCore
  import random
  import time
  
  
  class DataThread(QThread):
      output = QtCore.pyqtSignal(list)
  
      def __init__(self):
          super().__init__()
          self._run_flag = True
  
      def run(self):
          while self._run_flag:
              value = round(random.random(), 4)
              value_x2 = value * 2
              values = [value, value_x2]
              self.output.emit(values)
              # print(value)
              time.sleep(1)
  
      def stop(self):
          self._run_flag = False
          self.quit()
  
  
  class CalculationsThread(QObject):
      # accepting signals from main data generator thread
      calculations_result = QtCore.pyqtSignal(float)
      calc_value = QtCore.pyqtSignal(float)
      # emitting signal from this thread
      kill = QtCore.pyqtSignal()
      deny_access = QtCore.pyqtSignal(bool)
  
      def __init__(self, parent=None):
          super(CalculationsThread, self).__init__(parent)
          self.list_of_heights = []
  
      @pyqtSlot(float)
      def work(self, value):
          # self.deny_access.emit(True)
          self.list_of_heights.append(value)
          self.calculations_result.emit(len(self.list_of_heights))
          if len(self.list_of_heights) == 10:
              result = sum(self.list_of_heights) / len(self.list_of_heights)
              self.calculations_result.emit(result)
              self.list_of_heights = []
              # self.deny_access.emit(False)
              time.sleep(3)
  
  
  class WinForm(QWidget):
      variable_value = QtCore.pyqtSignal(float)
  
      def __init__(self, parent=None):
          super(WinForm, self).__init__(parent)
          self.setWindowTitle('QThreads example')
          self.change_flag = 0
          self.calculations_flag = 0
          self.list_from_data_generator_thread = []
          self.thread = None
          self.calculations_worker = None
          self.thread1 = None
          self.label = QLabel('Label')
  
          self.startBtn = QPushButton('Start')
          self.startBtn.clicked.connect(self.start_data_generator)
  
          self.endBtn = QPushButton('Stop')
          self.endBtn.clicked.connect(self.stop_data_generator)
  
          self.output1_btn = QPushButton(&quot;Value 1&quot;)
          self.output1_btn.clicked.connect(self.show_value_1)
          self.output2_btn = QPushButton(&quot;Value 2&quot;)
          self.output2_btn.clicked.connect(self.show_value_2)
  
          self.calculations_label = QLabel(&quot;Calculations result: &quot;)
          self.calculations_button = QPushButton(&quot;Start calculations&quot;)
          self.calculations_button.clicked.connect(self.start_calculations)
  
          layout = QGridLayout()
  
          layout.addWidget(self.label, 0, 0)
          layout.addWidget(self.startBtn, 1, 0)
          layout.addWidget(self.endBtn, 1, 1)
          layout.addWidget(self.output1_btn, 2, 0)
          layout.addWidget(self.output2_btn, 2, 1)
          layout.addWidget(self.calculations_label, 3, 0)
          layout.addWidget(self.calculations_button, 3, 1)
  
          self.setLayout(layout)
  
      @pyqtSlot(list)
      # @pyqtSLot(bool)
      def set_label_text(self, value):
  
          # if access_flag:
          self.variable_value.emit(value[1])
          # if not access flag:
          # pass
          if self.change_flag == 0:
              self.label.setText(f&quot;1: {value[0]}&quot;)
          if self.change_flag == 1:
              self.label.setText(f&quot;2: {value[1]}&quot;)
  
      def start_data_generator(self):
          self.startBtn.setEnabled(False)
          self.endBtn.setEnabled(True)
          self.thread = DataThread()
          self.thread.output.connect(self.set_label_text)
          self.thread.start()
          self.endBtn.clicked.connect(self.thread.stop)
  
      def stop_data_generator(self):
          self.thread.output.disconnect(self.set_label_text)
          self.startBtn.setEnabled(True)
          self.endBtn.setEnabled(False)
  
      @pyqtSlot(float)
      def output_calculations(self, value):
          self.calculations_label.setText(f&quot;Calculations result: {value}&quot;)
  
      def start_calculations(self):
          self.calculations_worker = CalculationsThread()
          self.thread1 = QThread()
          self.calculations_worker.moveToThread(self.thread1)
  
          self.variable_value.connect(self.calculations_worker.work)
          self.calculations_worker.calculations_result.connect(self.output_calculations)
          self.calculations_worker.kill.connect(self.thread1.quit)
  
          self.thread1.start()
  
          self.calculations_button.clicked.disconnect(self.start_calculations)
          self.calculations_button.setText(&quot;Stop calculations&quot;)
          self.calculations_button.clicked.connect(self.thread1.quit)
          self.calculations_button.clicked.connect(self.stop_calculations)
  
      def stop_calculations(self):
          self.calculations_worker.calculations_result.disconnect(self.output_calculations)
          self.calculations_button.clicked.disconnect(self.stop_calculations)
          self.calculations_button.clicked.disconnect(self.thread1.quit)
          self.calculations_button.setText(&quot;Start calculations&quot;)
          self.calculations_button.clicked.connect(self.start_calculations)
  
      def show_value_1(self):
          self.change_flag = 0
  
      def show_value_2(self):
          self.change_flag = 1
  
  
  if __name__ == '__main__':
      app = QApplication(sys.argv)
      form = WinForm()
      form.show()
      sys.exit(app.exec_())
  
  </code></pre>