title: How can I update the text in real time while doing the calculations in a QLabel, without the interface freezing?
body: <p>I have a problem regarding the real-time update in a Q Label, because when I click the "start" button, the screen stays static for a few seconds while it performs the calculations, but what I need is that in the QLabel the status messages are displayed while advancing with the simulation. I have tried with the use of threads, but I do not understand it very well since it does not work out, if someone could help me with this I would appreciate it, since I do not handle much the Thread issue in Pyqt5. (I do not understand)
  Thank you very much</p>
  
  <p>I attach both the code and the images of the interface:</p>
  
  <hr>
  
  <p><strong>INTERFACE</strong></p>
  
  <p>Before execution:</p>
  
  <p><a href="https://i.stack.imgur.com/yErjv.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/yErjv.jpg" alt="enter image description here"></a></p>
  
  <p>During execution:</p>
  
  <p><a href="https://i.stack.imgur.com/qPMSf.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/qPMSf.png" alt="enter image description here"></a></p>
  
  <p>After execution:</p>
  
  <p><a href="https://i.stack.imgur.com/N09Cf.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/N09Cf.jpg" alt="enter image description here"></a></p>
  
  <hr>
  
  <p><strong>Codigo</strong></p>
  
  <pre><code>import sys
  from PyQt5.QtWidgets import QStyleFactory,QApplication, QMainWindow,QFileDialog
  from PyQt5.uic import loadUi
  from PyQt5.QtGui import QTextCursor
  from PyQt5.QtCore import *
  import random
  import time
  import pandas as pd
  
  
  parametros = [['Area', 0, 5]]
  
  class simulacion(QMainWindow):
  
      def __init__(self, parent=None):
  
          QMainWindow.__init__(self, parent)
          loadUi('simulacion.ui', self)
          self.setStyle(QStyleFactory.create('Fusion'))
          self.numsim = 10000000
  
          self.pushButton.clicked.connect(self.calibracion)
          self.pushButton_2.clicked.connect(self.save)
  
      def cerrar(self):
          self.close()
  
      def calibracion(self):
          self.montecarlo(self.numsim)
  
      def generar_aleatorio(self):
          aleatorio = []
          for i in range(len(parametros)):
              aleatorio.append(random.uniform(parametros[i][1],parametros[i][2]))
          return aleatorio
  
      def area(self,x1):
          area = 3.1416 * x1**2
          return area
  
      def estado(self,starttime,last_print,contador, n, area):
          global ult_print
          acttime = time.time()
          if acttime - last_print &gt;= 2:
              avg_time_per_run = (acttime - starttime) / (contador + 1)
              timestr = time.strftime("%H:%M:%S", time.gmtime(round(avg_time_per_run * (n - (contador + 1)))))
  
              text = ('Simulacion %i de %i - Tiempo estimado restante: %s\n' % (contador, n,timestr)+'Area = %5.3f' % (area)+'\n\n')
  
              self.textEdit.moveCursor(QTextCursor.End)
              self.textEdit.insertPlainText(text)
              self.textEdit.moveCursor(QTextCursor.End)
  
              ult_print = time.time()
              return text
  
      def montecarlo(self,n):
          QApplication.processEvents()
          global ult_print
          text='Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
          self.textEdit.setText(text)
          self.textEdit.moveCursor(QTextCursor.End)
          ult_print = time.time()
          starttime = time.time()
          contador = 0
          self.data=[]
          self.num_sim=[]
  
          QApplication.setOverrideCursor(Qt.WaitCursor)
  
          while contador &lt; n:
              contador +=1
              #Generar el numero aleatorio
              z = self.generar_aleatorio()
              #Simulacion del modelo con el numero aleatorio
              y = self.area(z[0])
              #Calculo de la funcion objetivo
              self.estado(starttime,ult_print,contador,n,y)
  
          QApplication.setOverrideCursor(Qt.CustomCursor)
  
  
      def save(self):
          file,_=QFileDialog.getSaveFileName(self,'Guardar Archivo de Simulación','','(*.csv)')
  
          if file:
              columns= []
              for valor in self.num_sim:
                  columns.append('Simulación '+str(valor))
              #print(columns)
  
              df = pd.DataFrame(self.data,index=columns)
              a = df.transpose()
              a.to_csv(file,sep=';',index=False,encoding='utf-8')
  
  if __name__ == "__main__":
      app = QApplication(sys.argv)
      widget = simulacion()
      widget.show()
      sys.exit(app.exec_())
  </code></pre>
  
  <p>Here I show the separate code of the call of simulacion.ui</p>
  
  <p><strong>Codigo</strong></p>
  
  <pre><code>import sys
  from PyQt5.QtWidgets import QStyleFactory,QApplication, 
  QMainWindow,QFileDialog
  from PyQt5.uic import loadUi
  from PyQt5.QtGui import QTextCursor
  from PyQt5.QtCore import *
  import random
  import time
  import pandas as pd
  
  '''This part of the code calls the window designed in QTDesigner'''
  
  class simulacion(QMainWindow):
  
      def __init__(self, parent=None):
  
          QMainWindow.__init__(self, parent)
          loadUi('simulacion.ui', self)
          self.setStyle(QStyleFactory.create('Fusion'))
          self.numsim = 10000000
  
          self.pushButton.clicked.connect(self.calibracion)
          self.pushButton_2.clicked.connect(self.save)
  
      def cerrar(self):
          self.close()
  
      def calibracion(self):
          self.montecarlo(self.numsim)
  
      def save(self, data):
          file,_=QFileDialog.getSaveFileName(self,'Guardar Archivo de Simulación','','(*.csv)')
          if file:
              df = pd.DataFrame(data)
              df.to_csv(file,sep=';',index=False,encoding='utf-8')
  if __name__ == "__main__":
  app = QApplication(sys.argv)
  widget = simulacion()
  widget.show()
  sys.exit(app.exec_())
  </code></pre>
  
  <p>This part of the code is where I describe the functions that will be used within the Monte Carlo algorithm. where the texts that are specified should be shown in the QTextEdit It is important to mention that in the Montecarlo function, the data list is generated, which is what keeps all the simulations performed. This variable is necessary so that the save function in the simulation class can be executed</p>
  
  <pre><code>parametros = [['Area', 0, 5]]
  
  def generar_aleatorio():
      aleatorio = []
      for i in range(len(parametros)):
          aleatorio.append(random.uniform(parametros[i][1],parametros[i][2]))
          return aleatorio
  
  def area(x1):
      area = 3.1416 * x1**2
      return area
  
  def estado(starttime,last_print,contador, n, area):
      global ult_print
      acttime = time.time()
      if acttime - last_print &gt;= 2:
          avg_time_per_run = (acttime - starttime) / (contador + 1)
          timestr = time.strftime("%H:%M:%S", time.gmtime(round(avg_time_per_run * (n - (contador + 1)))))
  
          text = ('Simulacion %i de %i - Tiempo estimado restante: %s\n' % (contador, n,timestr)+'Area = %5.3f' % (area)+'\n\n')
  
          self.textEdit.moveCursor(QTextCursor.End)
          self.textEdit.insertPlainText(text)
          self.textEdit.moveCursor(QTextCursor.End)
  
          ult_print = time.time()
          return text
  
  def montecarlo(n):
          global ult_print
          text='Iniciando iteraciones con {} repeticiones...\n\n'.format(n)
          #self.textEdit.setText(text)
          #self.textEdit.moveCursor(QTextCursor.End)
          ult_print = time.time()
          starttime = time.time()
          contador = 0
          data=[]
          num_sim=[]
          #QApplication.setOverrideCursor(Qt.WaitCursor)
  
          while contador &lt; n:
              contador +=1
              #Generar el numero aleatorio
              z = generar_aleatorio()
              #Simulacion del modelo con el numero aleatorio
              y = area(z[0])
              #Calculo de la funcion objetivo
              estado(starttime,ult_print,contador,n,y)
              data.append(list(z+y))
  
          #QApplication.setOverrideCursor(Qt.CustomCursor)
  </code></pre>