Ducktor
Ducktor

Reputation: 365

Typewriter effect in tkinter

I'm creating a text adventure in python using tkinter due to it's easy to use graphics (buttons and such)

I want to add a effect where the text looks like it's being typed out.

def displayNextPart():
    for i in buttons:
        i.destroy()
    global curPart
    for char in story[curPart]["Text"]:
        slp(.05)
        w.config(text=char)
        sys.stdout.flush()

But the window just freezes until it's finished and all it leaves me with is the last character of the string.

Can anyone help me?

Upvotes: 3

Views: 2951

Answers (3)

Faraaz Kurawle
Faraaz Kurawle

Reputation: 1192

I think this answer is the more simple and easy than any of the above answer

The Solution is:

from tkinter import *
root=Tk()
import sys
from time import sleep
words = "Typing effect in tkinter.py"
def update():
    l=[]
    for i in words:
        l.append(i)
        root.after(1000)
        b="".join(l)
        c=len(b)
        ab.set(f"{b[0:c-1]}{i}")
        a.update()
d=Button(text="click",command=update)
d.pack()
ab=StringVar()
a=Label(textvariable=ab)
a.pack()
root.mainloop()

Or just use a StringVar:

from tkinter import *

root=Tk()
words = "Typing effect in tkinter.py"
ab=StringVar()



a=Label(textvariable=ab)
a.pack()
for i in words:
      a=ab.get()
      ab.set(a+i)
      root.after(1000)
      root.update()
root.mainloop()

I have just read the letters in text, then saved that text in the StringVar, also took the previous value and added the new value to StringVar.

Upvotes: 1

TigerhawkT3
TigerhawkT3

Reputation: 49330

time.sleep() does not work properly with Tkinter applications. Use the after() method as in the following example:

import tkinter as tk

root = tk.Tk()

word = 'hello'

def go(counter=1):
    l.config(text=word[:counter])
    if counter < len(word):
        root.after(150, lambda: go(counter+1))

b = tk.Button(root, text='go', command=go)
l = tk.Label(root)
b.pack()
l.pack()

root.mainloop()

Upvotes: 5

Bryan Oakley
Bryan Oakley

Reputation: 386352

You need to let the event loop update the screen. The simplest way to do that is to write a self-repeating function using tkinter's after method.

Here's a working example. This uses a text widget, but you can just as easily update a label widget or canvas text item.

import Tkinter as tk

def typeit(widget, index, string):
   if len(string) > 0:
      widget.insert(index, string[0])
      if len(string) > 1:
         # compute index of next char
         index = widget.index("%s + 1 char" % index)

         # type the next character in half a second
         widget.after(250, typeit, widget, index, string[1:])

root = tk.Tk()
text = tk.Text(root, width=40, height=4)
text.pack(fill="both", expand=True)
typeit(text, "1.0", "Hello, this is an \nexample of some text!")

root.mainloop()

Upvotes: 3

Related Questions