How to store to list in kivy? - python
I am making kivy app, something like project manager. I've got problem, i'll try to describe it.
In my app you can create new "project" by pressing button, then open the project and create some task. I need to store "project" into list or dictioniares. I've been thinking about this problem whole week and I can't solve. Do you have any ideas? I include my py. file and my kv. file here.
If you have some improvments to my codes, come here with them.
My python file:
from kivy.app import App
import sys
from kivy.storage.jsonstore import JsonStore
from kivy.uix.screenmanager import ScreenManager,Screen, SlideTransition, RiseInTransition
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.checkbox import CheckBox
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.core.window import Window
from kivy.uix.image import Image
from kivy.uix.checkbox import CheckBox
from kivy.core.window import Window
from kivy.graphics import Color, Ellipse, Rectangle, Line
from kivy.uix.spinner import Spinner
from kivy.uix.stencilview import StencilView
Window.size = (400, 650)
Window.clearcolor = (0,0,0,0)
kv = Builder.load_file('main.kv')
c = 0
class MS(Screen, Widget):
def on_exit(self):
sys.exit()
class SES(Screen):
pass
class OPS(Screen, BoxLayout):
themes = ["DARK","LIGHT"]
def __init__(self, **kwargs):
super(OPS, self).__init__(**kwargs)
label = Label(text="COLOR THEME:", size_hint=(.2,.1), pos_hint={"x":.25,"top":.9})
self.add_widget(label)
tgbt = ToggleButton(text="DARK", size_hint=(.2, .1), pos_hint={"x":.5,"top":.9},background_normal="",background_color =(0,0,0,0))
self.add_widget(tgbt)
tgbt2 = ToggleButton(text="LIGHT", size_hint=(.2, .1), pos_hint={"x": .7, "top": .9},background_normal="", background_color= (1,1,1,1))
self.add_widget(tgbt2)
class PRS(Screen, BoxLayout):
widgets1 = []
l1x = .1
l1top = .87
txt1x = .4
txt1top = .88
ck1x = .64
ck1top = .88
chtop = 0.88
deltop = 0.88
projects = []
def changer(self,*args):
self.manager.current = 'task'
def changer2(self, *args):
self.manager.current = 'main'
def new_pr(self, *args):
txt1 = TextInput(multiline=False,size_hint=(0.3,0.05), pos_hint={'x':self.txt1x,"top":self.txt1top})
self.add_widget(txt1)
label1 = Label(text="YOUR PROJECT NAME:",size_hint=(0.2,0.04),pos_hint={"x":self.l1x,"top":self.l1top})
self.add_widget(label1)
check1 = CheckBox(active=False, size_hint=(0.2,0.05), pos_hint={"x":self.ck1x,"top":self.ck1top})
self.add_widget(check1)
print(self.projects)
self.widgets1.append(check1)
self.widgets1.append(label1)
self.widgets1.append(txt1)
self.l1top = self.l1top - .07
self.txt1top = self.txt1top - .07
self.ck1top = self.ck1top - .07
spinner = Spinner(text="OPTIONS", values="DELETE",background_normal="",background_color =(200/255.0, 194/255.0, 136/255.0,1))
button = Button(text="OPEN",color=(200 / 255.0, 194 / 255.0, 136 / 255.0, 1), size_hint=(0.1,0.05), pos_hint={"x":0.77, "top":self.chtop})
self.add_widget(button)
self.widgets1.append(button)
button2 = Button(text = "DELETE",color=(200 / 255.0, 194 / 255.0, 136 / 255.0, 1), size_hint=(0.13,0.05), pos_hint={"x":0.87,"top":self.deltop})
self.add_widget(button2)
self.widgets1.append(button2)
self.chtop = self.chtop - 0.07
self.deltop = self.deltop - 0.07
button.bind(on_press= self.changer)
button2.bind(on_release= self.remover)
def remover(self, *args):
for i in self.widgets1:
self.remove_widget(i)
self.l1top = .88
self.deltop = .88
self.chtop = .88
self.ck1top = .88
self.txt1top = .88
def __init__(self, **kwargs):
super(PRS, self).__init__(**kwargs)
bt1 = (Button(text="NEW PROJECT",pos_hint={"x":.0,"top":1},size_hint=(.5,.1)))
self.add_widget(bt1)
bt2 = (Button(text="BACK",pos_hint={"x":.5,"top":1},size_hint=(.5,.1)))
self.add_widget(bt2)
bt1.bind(on_release=self.new_pr)
bt2.bind(on_release=self.changer2)
def clear_screen(self):
self.canvas.clear()
class TASKS(Screen, BoxLayout):
task1 = []
tinpx = 0.25
tinptop = .83
chkx = 0.76
chktop = .84
showed = False
def note(self, *args):
self.showed = True
if self.showed == True:
textinput = TextInput(multiline=True,size_hint=(.4,.5), pos_hint={"x":0.56,"top":self.chktop-0.1})
self.add_widget(textinput)
while self.showed == False:
self.remove_widget(textinput)
break
def change(self, *args):
self.showed = False
def changer(self,*args):
self.manager.current = 'project'
def new_task(self, *args):
txt1 = TextInput(multiline=False, size_hint=(.2,.04), pos_hint={"x":self.tinpx, "top":self.tinptop})
self.add_widget(txt1)
chck1 = CheckBox(active=False, size_hint = (.2, .05), pos_hint = {"x":self.chkx,"top":self.chktop})
self.add_widget(chck1)
notes = Button(text="NOTES", color=(200 / 255.0, 194 / 255.0, 136 / 255.0, 1), size_hint=(.2,.05), pos_hint={"x":0.56,"top":self.chktop})
notes.bind(on_press=self.note)
notes.bind(on_release=self.change)
self.add_widget(notes)
self.tinptop = self.tinptop - .07
self.chktop = self.chktop - .07
def __init__(self, **kwargs):
super(TASKS, self).__init__(**kwargs)
self.add_widget(Label(text="TASK NAME", size_hint=(.2,.04), pos_hint={"x":0.25,"top":.88}))
self.add_widget(Label(text="COMPLETE", size_hint = (.2,.04), pos_hint={"x":0.75,"top":.88}))
bt1 = Button(text="NEW TASK",color=(0,0,0),size_hint=(.5,.1), pos_hint = {"x":0, "top":1},background_normal="",background_color =(200/255.0, 194/255.0, 136/255.0,1))
self.add_widget(bt1)
homebt = Button(text="BACK",color=(0,0,0),size_hint=(.5, .1), pos_hint={"x":0.5,"top":1},background_normal="",background_color =(200/255.0, 194/255.0, 136/255.0,1))
self.add_widget(homebt)
homebt.bind(on_release=self.changer)
bt1.bind(on_release=self.new_task)
class Help(Screen, Widget):
pass
class MApp(App):
title = "PROJECT MANAGER"
def build(self):
wid = PRS(size_hint=(None, None), size=Window.size)
sm = ScreenManager()
sm.add_widget(MS(name = "main"))
sm.add_widget(SES(name = "second"))
sm.add_widget(OPS(name = "options"))
sm.add_widget(PRS(name="project"))
sm.add_widget(TASKS(name="task"))
sm.add_widget(Help(name="help"))
return sm
if __name__ == "__main__":
MApp().run()
My kv. file:
<MS>:
GridLayout:
cols:7
GridLayout:
cols:2
Button:
text : "NEW"
color:0,0,0
on_release:app.root.current="project"
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
Button:
text : "OPTIONS"
color:0,0,0
on_release:app.root.current="options"
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
Button:
text : "LOAD"
color:0,0,0
on_release:app.root.current="second"
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
Button:
text : "HELP"
color:0,0,0
on_release:app.root.current="help"
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
Button:
text : "Next"
color:0,0,0
on_release:app.root.current="second"
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
Button:
id:bt1
text : "Exit"
color:0,0,0
background_normal:""
background_color:(200/255.0, 194/255.0, 136/255.0,1)
on_release:app.stop()
<SES>:
name:"second"
Button:
text:"back"
color:0,0,0
on_release:
app.root.current="main"
<OPS>:
name:"options"
BoxLayout:
Button:
size_hint:.5,.2
pos_hint : {"x":.5,"top":.15}
text: "HOME"
color:0,0,0
on_release:app.root.current="main"
<PRS>:
name:"project"
<TASKS>:
name:"task"
<Help>:
name:"help"
GridLayout:
Label:
text:"COMING SOON!!!"
color:0,0,0
Thaks for help, time and effort.
Micheno
Here is simple example of my problem.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
class Test(BoxLayout):
x1 = 0.2
top1 = 0.9
widgets = []
def adder(self, *args):
lb1 = Label(text="HELLO WORLD", pos_hint={"x":self.x1,"top":self.top1})
self.add_widget(lb1)
self.x1 = self.x1 - 0.05
self.top1 = self.top1 - 0.05
self.widgets.append(lb1)
def remover(self, *args):
for i in self.widgets:
self.remove_widget(i)
self.x1=0.2
self.top1 = 0.9
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
bt1 = Button(text="ADD", pos_hint={"x":.1,"top":1}, size_hint=(0.2,0.4))
self.add_widget(bt1)
removebt = Button(text = "REMOVE",pos_hint={"x":.4,"top":1}, size_hint=(0.2,0.4))
self.add_widget(removebt)
removebt.bind(on_release=self.remover)
bt1.bind(on_release=self.adder)
class APP(App):
def build(self):
return Test()
if __name__ == "__main__":
APP().run()
If i want to delete only one label it will delete all. Just try to copy and run it
Just remove the last Label in the list:
def remover(self, *args):
if len(self.widgets) > 0:
self.remove_widget(self.widgets.pop(-1))
OK i could delete last that's improvement, but my problem is like this. What if I with button "ADD" I add text and button to remove the text and the button itself. Here is my new example with yours improvment.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.core.window import Window
Window.size = (400, 650)
class Test(BoxLayout):
x1 = 0.1
top1 = 0.9
widgets = []
def adder(self, *args):
lb1 = Label(text="HELLO WORLD", pos_hint={"x":self.x1,"top":self.top1})
self.add_widget(lb1)
removebt = Button(text = "REMOVE",pos_hint={"x":self.x1-0.1,"top":self.top1}, size_hint=(0.5,0.1))
self.add_widget(removebt)
self.widgets.append(removebt)
removebt.bind(on_release=self.remover)
self.widgets.append(lb1)
self.top1 = self.top1 - 0.05
def remover(self, *args):
if len(self.widgets) > 0:
self.remove_widget(self.widgets.pop(-1))
self.x1=0.2
self.top1 = 0.9
def __init__(self, **kwargs):
super(Test, self).__init__(**kwargs)
bt1 = Button(text="ADD", pos_hint={"x":.1,"top":1}, size_hint=(1,0.4))
self.add_widget(bt1)
bt1.bind(on_release=self.adder)
class APP(App):
def build(self):
return Test()
if __name__ == "__main__":
APP().run()
Related
kivy transition between screens
i made a gui with python kivy with a starting screen that has a button in it which generates new screens when pressed, and it also generates new buttons so its easier to pick the screen i need to get in focus but i can't get it working properly cause i can't generate buttons on the newly made screens when they aren't in focus, the script only generates buttons for the screen in focus it seems from kivy.app import App from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.textinput import TextInput from kivy.uix.floatlayout import FloatLayout from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition class ScreenManagement(ScreenManager): def __init__(self, **kwargs): super(ScreenManagement, self).__init__(**kwargs) sm = ScreenManagement(transition=FadeTransition()) class newtab(Screen): def __init__(self, **kwargs): super(newtab, self).__init__(**kwargs) self.bt1=(Button(text="New tab", size_hint =(.1, .1) ,pos_hint ={'center_x':.1, 'center_y':.94})) self.add_widget(self.bt1) self.bt1.bind(on_release=self.new_tab) self.txt1 = TextInput(text='',size_hint =(.1, .1), pos_hint ={'center_x':.2, 'center_y':.75}, multiline=True) self.add_widget(self.txt1) def transition(self, instance): self.manager.current = (instance.text) for item in sm.screen_names: self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84})) self.add_widget(self.bt2) self.bt2.bind(on_release=self.transition) def new_tab(self, *args): n = len(self.manager.screen_names) ##number of screens+1 screen = newtab(name="screen {}".format(n)) #make new screen and give it number self.manager.add_widget(screen) self.manager.current = "screen 0" for item in sm.screen_names: self.bt2=(Button(text=item, size_hint =(.1, .1) ,pos_hint ={'center_x':(.1*sm.screen_names.index(item)+.1), 'center_y':.84})) self.add_widget(self.bt2) self.bt2.bind(on_release=self.transition) sm.add_widget(newtab(name='screen 0')) class Application(App): def build(self): return sm if __name__ == "__main__": Application().run()
I suppose that below is what you expected to get. But I agree with #ApuCoder that you may look for TabbedPanel functionality. from kivy.app import App from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.textinput import TextInput from kivy.uix.floatlayout import FloatLayout from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition class ScreenManagement(ScreenManager): def __init__(self, **kwargs): super(ScreenManagement, self).__init__(**kwargs) sm = ScreenManagement(transition=FadeTransition()) class newtab(Screen): def __init__(self, **kwargs): super(newtab, self).__init__(**kwargs) self.bt1 = (Button(text="New tab", size_hint=(.1, .1), pos_hint={'center_x': .1, 'center_y': .94})) self.add_widget(self.bt1) self.bt1.bind(on_release=self.new_tab) self.txt1 = TextInput(text='', size_hint=(.1, .1), pos_hint={'center_x': .2, 'center_y': .75}, multiline=True) self.add_widget(self.txt1) # add all present screen buttons to newly created screen for i, screen in enumerate(sm.screens): self.bt2 = (Button(text=screen.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * i + .1), 'center_y': .84})) self.add_widget(self.bt2) self.bt2.bind(on_release=self.transition) # add this newly created screen button to all screens for screen in sm.screens + [self]: screen.bt2 = (Button(text=self.name, size_hint=(.1, .1), pos_hint={'center_x': (.1 * len(sm.screens) + .1), 'center_y': .84})) screen.add_widget(screen.bt2) screen.bt2.bind(on_release=screen.transition) def transition(self, instance): self.manager.current = instance.text def new_tab(self, *args): n = len(self.manager.screen_names) ##number of screens+1 screen = newtab(name="screen {}".format(n)) # make new screen and give it number self.manager.add_widget(screen) self.manager.current = "screen 0" sm.add_widget(newtab(name='screen 0')) class Application(App): def build(self): return sm if __name__ == "__main__": Application().run()
Why is my navigation code not working? kivy python
I have a screen manager ThirdWindow which is supposed to change the screen when B1 is clicked basically a navigation thing. Please note ThirdWindow is a a different class. callback is called when B1 is clicked. it changes the screen with the help of ThirdWindow I think. I used self.manager.current it didn't worked, I also tried using it by making ThirdWindow a def in class Dre but the results were same. The print statement is not getting printed that is inside def callback(self, instance) so I think the def is not getting called on_click at all. How can I fix that? Thanks import kivy from kivy.app import App from kivy.core.audio import SoundLoader from kivy.uix.gridlayout import GridLayout from kivy.uix.label import Label from kivy.uix.textinput import TextInput from kivy.uix.button import Button from kivy.uix.stacklayout import StackLayout from kivy.uix.relativelayout import RelativeLayout from kivy.graphics import Rectangle from kivy import platform from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager, Screen class MainWindow(Screen): pass class ThirdWindow(ScreenManager): def load(self): sm = ScreenManager sm.add_widget(Dre(name='Dre')) sm.add_widget(SecondWindow(name='SecondWindow')) self.sm.current = 'Dre' class Dre(RelativeLayout): def __init__(self, **kwargs): super(Dre, self).__init__(**kwargs) self.color = [254/255, 102/255, 37/255, 1] self.H_color = [254/255, 102/255, 37/255] self.sound_theme = None self.init_audio() self.kv = Builder.load_file('Levels.py') if platform in ('linux', 'win', 'macosx'): with self.canvas.before: self.bg = Rectangle(size=self.size, source='Neo.png') self.bind(pos=self.update_bg) self.bind(size=self.update_bg) else: with self.canvas.before: self.bg = Rectangle(size=self.size, source='Neon.png') self.bind(pos=self.update_bg) self.bind(size=self.update_bg) def update_bg(self, *args): if platform in ('linux', 'win', 'macosx'): self.bg.pos = self.pos self.bg.size = self.size self.add_widget(Label(text='D R E A M S', pos_hint={'center_x': .5, 'center_y': .8}, font_size='60dp', font_name='Roboto-Bold.ttf', color=self.H_color)) B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15), pos_hint={'center_x': .5, "center_y": .3}, background_color = self.color, background_normal='') # B1.bind(on_press=return self.kv) self.add_widget(B1) else: self.bg.pos = self.pos self.bg.size = self.size self.add_widget(Label(text='D R E A M S', pos_hint={'center_x': .5, 'center_y': .8}, font_size='30dp', font_name='Roboto-Bold.ttf', color=self.H_color)) B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15), pos_hint={'center_x': .5, "center_y": .3}, background_color=self.color, background_normal='', on_press=self.callback) self.add_widget(B1) def callback(self, instance): print('working') self.manager.current = 'SecondWindow' def init_audio(self): self.sound_theme = SoundLoader.load('Bg_theme.mp3') self.sound_theme.volume = 1 self.sound_theme.loop = True if self.sound_theme: self.sound_theme.play() print('okay') else: print('not okay') class SecondWindow(Screen): def __init__(self, **kwargs): super(SecondWindow, self).__init__(**kwargs) self.color = [254 / 255, 102 / 255, 37 / 255, 1] if platform in ('linux', 'win', 'macosx'): with self.canvas.before: self.bg = Rectangle(size=self.size, color=self.color) class LabApp(App): def build(self): return Dre() if __name__ == '__main__': LabApp().run()``` if you provide any solution please provide it in .py file.
Many issues with your code. First, you have defined a ScreenManager class (ThirdWindow), but you have not created an instance of it or included it in your GUI. In order to use a ScreenManager to manage Screens, you must add it to your GUI. I would suggest modifying your LabApp class to use ThirdWindow: class LabApp(App): def build(self): return ThirdWindow() and modify ThirdWindow to replace the load() method with an __init__() method: class ThirdWindow(ScreenManager): def __init__(self, **kwargs): super(ThirdWindow, self).__init__(**kwargs) self.add_widget(Dre(name='Dre')) self.add_widget(SecondWindow(name='SecondWindow')) Since the Dre class is being used as a Screen, it must be redefined as a Screen: class Dre(Screen): and you can add the callback to the creation of the B1 Button: B1 = Button(text='P L A Y', font_name='Roboto-Bold.ttf', size_hint=(.2, .15), on_release=self.callback, pos_hint={'center_x': .5, "center_y": .3}, background_color = self.color, background_normal='')
Kivy - Saving object's values changed in Popup, so that after closing it, when I open the popup again it opens with new values
I want to change some button labels of a class in a popup and retain the new label after reopening the popup. If you run my app, you can see that after pressing "Press me" button, a popup appears with a button with a label "Default", after pressing on it, it changes the label to "New". I want to be able to close the popup, press the "Press me" button and see the button in a popup with a label "New". My .py file from kivy.uix.floatlayout import FloatLayout from kivy.core.window import Window from kivy.uix.popup import Popup from kivy.app import App from kivy.uix.widget import Widget import time Window.clearcolor = (1, 1, 1, 1) Window.size = (800, 480) class MyGrid(Widget): def btn(self): show_popup(T, "Window") class T(FloatLayout): pass def show_popup(tab, name): show = tab() popupWindow = Popup(title = name, content = show, size_hint = (None,None), size = (800,384), auto_dismiss = True) popupWindow.open() return popupWindow class TimeApp(App): def build(self): return MyGrid() if __name__ == "__main__": TimeApp().run() my .kv file <MyGrid> Button: text: "Press me" on_press: root.btn() <T>: Button: pos_hint: {"center_x": 0.5, "center_y": 0.5} text: "Default" on_press: self.text = "New"
One way that you can do it, is by keeping a reference to the popup. The py side: Window.clearcolor = (1, 1, 1, 1) Window.size = (800, 480) class MyGrid(Widget): def __init__(self, **kwargs): super(MyGrid, self).__init__(**kwargs) self.popupWindow = Popup(content=T(), size_hint=(None, None), size=(800, 384), auto_dismiss=True) def btn(self): self.show_popup("Window") def show_popup(self, name): self.popupWindow.title = name self.popupWindow.open() class T(FloatLayout): pass class TimeApp(App): def build(self): return MyGrid() if __name__ == "__main__": TimeApp().run()
Why I have to click twice to scroll? Scrollable Label in kivy, python
I have a following problem: I need to write an app, where I will show proper answers for every question. I wrote with kivy some code and I'm struggling with one thing. I created a page. There is a button for showing answers, but after one press I only see a part of my answers and I can't scroll. But, when I press a button second time, everything is good. Could you tell me why is that? How to repair it? I would like to see all answers after pressing a button once and be able to scroll. import kivy 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 Screen, ScreenManager from kivy.uix.scrollview import ScrollView from kivy.uix.boxlayout import BoxLayout from kivy.core.window import Window from kivy.config import Config Config.set('graphics', 'resizable', True) import os import sys class MyApp(App): def build(self): self.screen_manager = ScreenManager() self.answers = Answers() screen = Screen(name = "Answers") screen.add_widget(self.answers) self.screen_manager.add_widget(screen) return self.screen_manager class Answers(GridLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.rows = 3 self.label = Label(text = "Answers: ", font_size = 40) self.add_widget(self.label) self.button = Button(text="Show answers") self.button.bind(on_press=self.showanswers) self.add_widget(self.button) self.scroll = ScrollableLabel(height = Window.size[1]*0.75, size_hint_y = None) self.add_widget(self.scroll) def showanswers(self, instance): f = open("text.txt", "r") lines = f.readlines() ScrollableLabel.update(self.scroll, lines) myapp.screen_manager.current = "Answers" class ScrollableLabel(ScrollView): def __init__(self, **kwargs): super().__init__(**kwargs) self.layout = GridLayout(cols = 1, size_hint_y = None) self.add_widget(self.layout) self.lines = Label(size_hint_x = 1, size_hint_y = None, text_size = (self.width, None)) self.scroll_to_point = Label() self.scroll_to_point.bind(texture_size=self.scroll_to_point.setter('size')) self.layout.add_widget(self.lines) self.layout.add_widget(self.scroll_to_point) def update(self, lines): self.lines.text = '\n' for i in range(len(lines)): self.lines.text += '\n ' +str(i+1) + ". " + lines[i] self.layout.height = self.lines.texture_size[1] self.lines.height = self.lines.texture_size[1] self.lines.text_size = (self.lines.width*0.75, None) self.scroll_to(self.scroll_to_point) f = open("text.txt", 'a+') for i in range(30): f.write("Important text \n") f.close() myapp = MyApp() myapp.run()
I think your widget heights are not updating correctly, and to correct that requires doing some binding. Since the 'kv' language automatically does bindings, I have provided an answer that uses 'kv': from kivy.app import App from kivy.lang import Builder from kivy.uix.label import Label from kivy.uix.gridlayout import GridLayout from kivy.uix.button import Button from kivy.uix.screenmanager import Screen, ScreenManager from kivy.uix.scrollview import ScrollView from kivy.core.window import Window from kivy.config import Config Config.set('graphics', 'resizable', True) class MyApp(App): def build(self): self.screen_manager = ScreenManager() self.answers = Answers() screen = Screen(name = "Answers") screen.add_widget(self.answers) self.screen_manager.add_widget(screen) return self.screen_manager class Answers(GridLayout): def __init__(self, **kwargs): super().__init__(**kwargs) self.rows = 3 self.label = Label(text = "Answers: ", font_size = 40) self.add_widget(self.label) self.button = Button(text="Show answers") self.button.bind(on_press=self.showanswers) self.add_widget(self.button) self.scroll = ScrollableLabel(height = Window.size[1]*0.75, size_hint_y = None) self.add_widget(self.scroll) def showanswers(self, instance): f = open("text.txt", "r") lines = f.readlines() self.scroll.update(lines) myapp.screen_manager.current = "Answers" class ScrollableLabel(ScrollView): def update(self, lines): self.ids.lines.text = '\n' for i in range(len(lines)): self.ids.lines.text += '\n ' +str(i+1) + ". " + lines[i] Builder.load_string(''' <ScrollableLabel>: size_hint_y: None GridLayout: cols: 1 size_hint_y: None height: self.minimum_height # adjust height to handle the Label Label: id: lines size_hint_y: None height: self.texture_size[1] # set height based on text ''') f = open("text.txt", 'a+') for i in range(30): f.write("Important text \n") f.close() myapp = MyApp() myapp.run() I believe the two instances of size_hint_y: None and the corresponding height rules are the key. Note that I also changed: ScrollableLabel.update(self.scroll, lines) to: self.scroll.update(lines)
How to center text horizontally in a Kivy text input?
I want to center a single line of text in Kivy text input. I'm going to use padding widget.padding = [ (self.textinput.width - width of line) / 2, 20, 0, 0] but i can't find the width of the line. How can I calculate or access the width of the line?
There is an internal TextInput._get_text_width method you can use to calculate proper padding: from kivy.app import App from kivy.uix.floatlayout import FloatLayout from kivy.lang import Builder Builder.load_string(''' <MyWidget>: TextInput: multiline: False on_text: root.update_padding(args[0]) padding_x: self.width/2 # initial padding ''') class MyWidget(FloatLayout): def update_padding(self, text_input, *args): text_width = text_input._get_text_width( text_input.text, text_input.tab_width, text_input._label_cached ) text_input.padding_x = (text_input.width - text_width)/2 class MyApp(App): def build(self): return MyWidget() if __name__ == '__main__': MyApp().run()
The solution above almost worked for me. Sometimes the padding wouldn't be updated correctly. Here is my slight change, setting text_width as a NumericProperty: In Kivy: <CenteredTextInput#TextInput>: multiline: False on_text: root.update_padding() padding_x: (self.width - self.text_width) / 2 In Python: class CenteredTextInput(TextInput): ''' A centered TextInput. ''' text_width = NumericProperty() '''The text width ''' def update_padding(self, *args): ''' Update the padding so the text is centered ''' self.text_width = self._get_text_width( self.text, self.tab_width, self._label_cached )
You could make a textinput behind a button, and make the button visualize as the text input. When pushing the button, put the focus to the textinput, and update the buttons text. I have made an example here. from kivy.uix.textinput import TextInput from kivy.uix.boxlayout import BoxLayout from kivy.uix.floatlayout import FloatLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.clock import Clock from kivy.app import App from kivy import require require('1.9.1') class MyWidget(BoxLayout): def __init__(self,**kwargs): super(MyWidget,self).__init__(**kwargs) self.orientation = "vertical" self.cur = False self.textinput = TextInput(text='',halign="center",multiline=False) self.textinput.bind(text=self.on_text) self.button = Button(background_normal="",background_color=[0,0,0.1,1],font_size="40sp") self.button.bind(on_release=self.button_click) self.my_float_layout = FloatLayout() self.my_float_layout.add_widget(self.textinput) self.my_float_layout.add_widget(self.button) self.add_widget(Label(text="type text below",font_size="40sp")) self.add_widget(self.my_float_layout) Clock.schedule_interval(self.cursor, 0.5) def cursor(self,dt): # function to visualize a cursor if self.textinput.focus: cur_pos = self.textinput.cursor[0] if not self.cur: self.button.text = self.textinput.text[:cur_pos] + "|" + self.textinput.text[cur_pos:] self.cur = True else: self.button.text = self.textinput.text[:cur_pos] + " " + self.textinput.text[cur_pos:] self.cur = False elif self.cur: self.button.text = self.textinput.text + " " self.cur = False def on_text(self, *args): # function to set the button text self.button.text = self.textinput.text def button_click(self,*args): # function to focus the input self.textinput.focus = True class MyApp(App): def build(self): return MyWidget() if __name__ == "__main__": MyApp().run()