Home > Blockchain >  How do I update the value of text in a .kv file while time.sleep is running in python?
How do I update the value of text in a .kv file while time.sleep is running in python?

Time:09-04

I'm trying to make the text of a button change like a typewriter effect but ran into a problem. While the program is sleeping, the value of the text doesn't actually change until it's done. After 12 seconds (the text im passing over has 12 characters, and the program sleeps for 1 second after each one) the text for the button updates, but I'm trying to get it to update every character. Is there a fix for this?

import time
import asyncio
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.floatlayout import FloatLayout
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.screenmanager import FadeTransition

Builder.load_file("test.kv")


class FirstScreen(Screen):
    pass


class SecondScreen(Screen):
    pass

class CandLApp(App):

    def build(self):
        sm = ScreenManager(transition=FadeTransition())
        sm.add_widget(FirstScreen(name="first"))
        sm.add_widget(SecondScreen(name="second"))
        return sm

    def text_wait(self, text, idforbutton):
        anything = getattr(self.root.get_screen("second").ids, idforbutton)
        anything.text = ""
        for i in text:
            anything.text  = i
            print(anything.text)
            time.sleep(1) #      the value of text for the button in the second screen doesn't change until 
                          #      this entire for loop is done running


if __name__ == "__main__":
    CandLApp().run()

.kv file:

<FirstScreen>:
    Button:
        size_hint: (.274, .2)
        pos_hint: {"x":.067, "y":.049}
        font_size: 45
        color: 200/255, 0/255, 70/255, 1
        text: "Test"
        on_release: root.manager.current = "second"

<SecondScreen>:
    FloatLayout:
        Button:
            id: buttonfortext
            text: "button"
            pos_hint: {"center_x": .5, "center_y": .5}
            size_hint: .2, .2
            on_release: app.text_wait("sending this", "buttonfortext") 

CodePudding user response:

If you want to print the text in a typewriter way you can use:

import sys
from time import sleep

def typewriter_print(word)
    for char in word:
    sleep(1)
    sys.stdout.write(char)
    sys.stdout.flush()

then you can call the typewriter_print(word) like this

def text_wait(self, text, idforbutton):
        anything = getattr(self.root.get_screen("second").ids, idforbutton)
        anything.text = ""
        typewriter_print(text)

CodePudding user response:

Expanding on my answer above:

Create a callback function that goes through the characters of the text one by one, and returns False when it's done

    def handle_char(self, iterator, anything ):
        try: 
            anything  = next(iterator)
            print(anything)
            return True
        except StopIteration:
            return False

and then call this callback function every second.

   def text_wait(self, text, idforbutton):
       ...
       Clock.schedule_interval(lambda dt: self.handle_char(iter(text), anything), 1.0)
  • Related