Search code examples
pythonqtpyqtpyside

How to add type-writer effect when adding text to QTextEdit in PyQt?


I have a string and a QTextEdit. Basically, when the user clicks the mouse button, I want to add the string to the QTextEdit, but I want it to print with a "slow/type-writer" effect, so every second the next letter in the string is appended to the text edit until the end of the string.

I think I could maybe use QThread for this, but I am not quite sure how to go about it. I've only just started learning about threads and processes in school. I tried using QThread as shown below, but the program became unresponsive/crashed.

text_edit = QtWidgets.QTextEdit()
string = "This is the sentence I want to display."

thread = QtCore.QThread()
thread.start()

for c in string:
  text_edit.moveCursor(QtGui.QTextCursor.End)
  text_edit.append(c)
  thread.sleep(1)

thread.quit()

Edit:

text_edit = QtWidgets.QTextEdit()
string = "This is the sentence I want to display."

timer = QtCore.QTimer()

for c in string:
  text_edit.moveCursor(QtGui.QTextCursor.End)
  text_edit.append(c)
  timer.start(1000)
  while timer.isActive():
      # something?
  timer.stop()

Solution

  • I think you are better off using QTimer, than QThread. You can use the class methods to set a singleShot timer for some number of milliseconds in between appending each character onto the existing message. You can fire the timer inside of a method that continues to call itself until it has completely entered the message text.

    For Example:

    ...
    ...
    
    TEXT = "Some long message that will be typed out one character at a time."
    
    class Window(QWidget):
        def __init__(self, parent=None) -> None:
            super().__init__(parent=parent)
            self.textEdit = QTextEdit(self)
            self.button = QPushButton("Click Me", self)
            self.button.clicked.connect(self.insert_phrase_char)
            self.text_phrase = list(TEXT)
            layout = QVBoxLayout(self)
            layout.addWidget(self.textEdit)
            layout.addWidget(self.button)
    
        def insert_phrase_char(self):
            if len(self.text_phrase) > 0:
                cursor = self.textEdit.textCursor()
                next_char = self.text_phrase.pop(0)
                cursor.insertText(next_char)
                QTimer.singleShot(300, self.insert_phrase_char)
    
    
    app = QApplication([])
    window = Window()
    window.show()
    app.exec()
    

    enter image description here