How to "print" in pyqt5 while inside a function?

Viewed 112

I'm creating a program (for web scraping) and I would like to create a place that shows what the script is doing (as it is already possible through print's on the console) but in the PyQt5 textEdit. (the script is inside of a function on python file)

However while the function/script is running the GUI crashes and does not show anything until the end of the function/script.

I made a simplified version to help understand the problem and make it easier to solve. If it works on this one it will probably work on the other.

Python File

print('iniciando programa...')
from PyQt5 import uic, QtWidgets
import time

def F_exemplof(): #function thats print index in 2 seconds
    for a in range(20):
        print('Print index: ' + str(a))
        W_exemplogui.textEdit.append('Print index: ' + str(a))
        time.sleep(2)


# Importing the GUI
app = QtWidgets.QApplication([])
W_exemplogui = uic.loadUi('testegui.ui')

# Buttons
W_exemplogui.pushButton.clicked.connect(F_exemplof)
#W_exemplogui.pushButton_2.clicked.connect()


# Show window
W_exemplogui.show()
app.exec()

testegui.ui

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>383</width>
    <height>304</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>MainWindow</string>
  </property>
  <widget class="QWidget" name="centralwidget">
   <layout class="QGridLayout" name="gridLayout" rowstretch="0">
    <item row="0" column="0">
     <widget class="QFrame" name="frame">
      <property name="styleSheet">
       <string notr="true">background-color: rgb(90, 90, 90);</string>
      </property>
      <property name="frameShape">
       <enum>QFrame::StyledPanel</enum>
      </property>
      <property name="frameShadow">
       <enum>QFrame::Raised</enum>
      </property>
      <layout class="QGridLayout" name="gridLayout_2">
       <item row="1" column="1">
        <widget class="QPushButton" name="pushButton">
         <property name="styleSheet">
          <string notr="true">color: rgb(255, 255, 255);</string>
         </property>
         <property name="text">
          <string>Iniciar</string>
         </property>
        </widget>
       </item>
       <item row="1" column="0">
        <widget class="QPushButton" name="pushButton_2">
         <property name="styleSheet">
          <string notr="true">color: rgb(255, 255, 255);</string>
         </property>
         <property name="text">
          <string>Cancelar</string>
         </property>
        </widget>
       </item>
       <item row="0" column="0" colspan="2">
        <widget class="QTextEdit" name="textEdit">
         <property name="styleSheet">
          <string notr="true">background-color: rgb(240, 240, 240);</string>
         </property>
        </widget>
       </item>
      </layout>
     </widget>
    </item>
   </layout>
  </widget>
 </widget>
 <resources/>
 <connections/>
</ui>
1 Answers

Time-consuming tasks must be executed in a secondary thread to avoid blocking the GUI, and signals must be used to send information to the main thread.

import threading
import time

from PyQt5 import uic, QtCore, QtWidgets


class Task(QtCore.QObject):
    messageChanged = QtCore.pyqtSignal(str)

    def start(self):
        threading.Thread(target=self._execute, daemon=True).start()

    def _execute(self):
        for a in range(20):
            print("Print index: " + str(a))
            self.messageChanged.emit("Print index: " + str(a))
            time.sleep(2)


def main():
    app = QtWidgets.QApplication([])
    W_exemplogui = uic.loadUi("testegui.ui")
    task = Task()
    W_exemplogui.pushButton.clicked.connect(task.start)
    task.messageChanged.connect(W_exemplogui.textEdit.append)
    W_exemplogui.show()
    app.exec_()


if __name__ == "__main__":
    main()
Related