Kivy 无响应且无法更改文本框中的文本

Kivy unresponsive and unable to change text in a textbox

所以这是我的代码的一部分,理论上它应该运行良好,因为我无法在其他任何地方重现该问题。

问题是,虽然 print(string) 工作得很好并且按顺序打印,但当我尝试制作一个 kivy 界面并将结果打印到 textbox 时,该界面适用于片刻,然后一切都变得迟钝,然后 Window 告诉我该程序没有响应。但是如果我查看 print 结果,它们工作正常。

另外,当我等待程序完成时,它会在一个大堆中吐出所有文本,然后完成。

那么有什么方法可以让 textbox 以与正常 print 相同的顺序打印结果?

例如)

正常打印:print('hello')

文本框打印:self.work.text += '\nhello'

P.S。如果您需要了解此代码中使用的功能,请询问

Python代码

import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.uix.togglebutton import ToggleButton
Window.clearcolor = (1, 1, 1, 1)
from kivy.uix.popup import Popup
from datetime import date
import requests
from bs4 import BeautifulSoup
import sys
import urllib.request
import urllib.parse
import re
import os
import time
from pytube import YouTube
from pydub import AudioSegment
AudioSegment.converter = "/FFmpeg/bin/ffmpeg.exe"
import eyed3

############################### functions #########################################

just some functions that work

################################################################################################################
class MyGrid(Widget):
    # url = ObjectProperty(None)
    # mod = ObjectProperty(None)
    # submit = ObjectProperty(None)

    def submit(self):

        self.work.text='starting...'

        if self.mod.state=='down':
            info=get_name_list(self.url.text,'single')
            print(info)
            self.high_audio(info)
        
        if self.mod.state=='normal':
            info=get_name_list(self.url.text,'playlist')
            print(info)
            self.high_audio(info)
        
        

    def high_audio(self,song_album_artist_list):

        for item in song_album_artist_list:
            song = str(item[0])
            artist_name = str(item[1])
            album = str(item[2])
            
            print(song+" : "+artist_name+" : "+album)
            self.work.text += song+" : "+artist_name+" : "+album
            print('............................')

            youtube_url=get_top_url(song,artist_name)

            # print(youtube_url)

            download_high_audio(youtube_url,song)

            convert(youtube_url,song)


            self.work.text += 'converting finished, applying metadata...'

            song_file = eyed3.load(output_path+"/"+song+".mp3")
            song_file.tag.artist = artist_name
            song_file.tag.album = album

            self.work.text += 'searching music...'

            art=get_music_inf(song,artist_name,album)

            if art=='':
                art=get_album_art_high(song,artist_name,album)

            if art=='':
                art=get_album_art_low(song,artist_name,album)
            
            if art=='':
                self.work.text += '****************************No artwork availiable****************************'
            
            self.work.text+=art

            try:
                response = requests.get(art)
                imagedata = response.content
                song_file.tag.images.set(3,imagedata,"image/png",u"None")
                song_file.tag.save()
            except requests.exceptions.MissingSchema:
                pass


            
            song_file.tag.save()

            self.work.text+='done'




class MyApp(App):
    def build(self):
        return MyGrid()



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

Kivy 代码


<RoundButton@Button>:
    background_color: 0,0,0,0
    canvas.before:
        Color:
            rgba: (.7,.7,.7,0.7) if self.state=='normal' else (0.82,0.96,0.92,1)
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [10,]

<RoundToggleButton@ToggleButton>:
    background_color: 0,0,0,0
    canvas.before:
        Color:
            rgba: (.7,.7,.7,0.7) if self.state=='normal' else (0.82,0.96,0.92,1)
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [10,]

<MyTextInput@TextInput>:
    background_normal: "textinput.png"
    background_color: (0.82,0.96,0.92,1) if self.focus else (1,1,1,0.5)

<MyGrid>:

    url:url
    mod:mod
    work:work

    FloatLayout:

        size: root.width, root.height

        
        MyTextInput:
            id: url
            pos_hint: {"x": 0.25, "top":0.85}
            size_hint: 0.5,0.1
            text:"Paste url"

        RoundButton:
            text: "submit"
            on_press: root.submit()
            pos_hint: {"x":0.4, "top":0.7}
            size_hint: 0.2,0.1

        RoundToggleButton:
            id: mod
            text: 'Playlist' if self.state=='normal' else 'Single'
            pos_hint: {"x":0.4, "top":0.45}
            size_hint: 0.2,0.1
        
        MyTextInput:
            id:work
            text:''
            pos_hint: {"x": 0.25,"top":0.3}
            size_hint: 0.5,0.25

有人可以告诉我问题出在哪里吗?我浪费了将近一天的时间来弄明白:(

当您 运行 print() 时,实际发生的是程序将文本作为字节流输出,然后其他一些程序(即您的终端)可以检查该流并将其显示为字符。 Python 程序还做什么并不重要,因为该字节流在其其余控制流之外。

当您使用 gui 绘制文本时,模型是不同的 - 设置 TextInput 的文本会告诉它做什么,但文本的实际呈现也是程序流程的一部分。

当你 运行 一次处理大量代码时,你会阻塞该流程,因此在你的函数开始和所有代码完成之间没有用于更新 gui 运行s 的 Kivy 代码,因此函数returns.

解决办法就是不屏蔽gui。要么将您的函数拆分为多个块,每个块使用 Clock.schedule_once 调用下一个块,或者 运行 您在线程中的 long-运行ning 函数调用。