So this is a part of my code, and in theory, it should be working well because I could not replicate the problem anywhere else.
The problem is that while the print(string)
works very well and prints in order, when I try to make a kivy interface and instead print the results on to a textbox
, the interface works for a moment, then goes all laggy af then Window tells me that the program is unresponsive. But if I look at the print
results, they are working just fine.
Also when I wait for the program to finish, when it finishes, it it spits out all the text in one big heap and then finishes.
So is there any way to make textbox
print out results in the same order as a normal print
would work?
ex)
normal print: print('hello')
textbox print: self.work.text += '\nhello'
P.S. If you need to know the functions that is used in this code, please ask
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()
<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
Can somebody please tell me what the problem is? I wasted almost a day trying to figure it out :(
When you run print()
, what actually happens is the text gets output by the program as a stream of bytes, and then some other program (i.e. your terminal) can inspect that stream and display it as characters. It doesn't matter what else the Python program does, because that byte stream is external to the rest of its control flow.
When you draw your text with a gui, the model is different - setting the text of the TextInput tells it what to do, but the actual rendering of the text is also part of the program's flow.
When you run lots of code all at once, you block that flow, so no Kivy code for updating the gui runs between your function starting and all the code finishing so the function returns.
The solution is to not block the gui. Either split your function into chunks, each of which calls the next one using Clock.schedule_once
, or run your long-running function call in a thread.