I could really really need some help with my actually quite simple Python Kivy Problem! I have a Kivy scrollview and want to add some text by clicking a button. After every click the scrollview should automatically scroll to the new text line. But for some reason it only works every second time. The text switches between jumping to the top and jumping to the new text line. And when the text is at the bottom and you scroll manually (or just click into the scrollview field) then the text jumps to the top. I want to be able to scroll by hand, but the text should not jump without clicking "Add text". When "Add text" is clicked however then it should scroll to the new text line as described.
import kivy
from kivy.config import Config
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.uix.scrollview import ScrollView
from kivy.clock import mainthread
import threading
kivy.require("2.0.0")
Config.set('kivy', 'keyboard_mode', 'systemandmulti')
class MainMenu(GridLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols = 1
self.rows = 3
self.infowindow = ScrollableInfo(height=Window.size[1]*0.8, size_hint_y=None)
self.add_widget(self.infowindow)
self.addtextbutton = Button(text="Add Text")
self.addtextbutton.bind(on_press=self.add_text_thread)
self.add_widget(self.addtextbutton)
def addtext(self, *_):
self.infowindow.update_scrollview(f"This is some new Text")
def add_text_thread(self, *args):
threading.Thread(target=self.addtext, daemon=True).start()
class ScrollableInfo(ScrollView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.layout = GridLayout(cols=1, size_hint_y=None)
self.add_widget(self.layout)
self.text_history = Label(size_hint_y=None, markup=True)
self.layout.add_widget(self.text_history)
@mainthread
def update_scrollview(self, newinfo):
self.text_history.text += '\n' + newinfo
self.layout.height = self.text_history.texture_size[1]+15
self.text_history.height = self.text_history.texture_size[1]
self.text_history.text_size = (self.text_history.width*0.98, None)
self.scroll_y = 0
class Textadding(App):
def build(self):
self.screen_manager = ScreenManager()
self.mainmenu_page = MainMenu()
screen = Screen(name="MainMenu")
screen.add_widget(self.mainmenu_page)
self.screen_manager.add_widget(screen)
return self.screen_manager
if __name__ == "__main__":
counting_app = Textadding()
counting_app.run()
Thank you very much in advance for any help!
If I understand you correctly, you want something like this. Your code has a lot of bugs and is very cumbersome, so I've rewritten it completely. I also do not recommend changing the UI in a secondary thread (add widgets, play animations) this is a bad practice and in kivy == 2.1.0dev0
it can cause an error.
from kivy.app import App
from kivy.lang import Builder
kv = """
Screen:
BoxLayout:
spacing: 10
orientation: "vertical"
ScrollView:
id: scroll_view
always_overscroll: False
BoxLayout:
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
Label:
id: label
size_hint: None, None
size: self.texture_size
Button:
text: "Add Text"
size_hint_y: 0.2
on_release: app.add_text()
"""
class TextAdding(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.text_counter = 0
def build(self):
return Builder.load_string(kv)
def add_text(self):
self.root.ids.label.text += f"Some text {self.text_counter}\n"
self.text_counter += 1
self.root.ids.scroll_view.scroll_y = 0
if __name__ == "__main__":
TextAdding().run()