简体   繁体   中英

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

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") 

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)

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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM