I want to keep the value returned from 2 time.time () methods in the on_event and on_leave functions in the ReflexScreen class. I want to use these values in the MainScreen class, but when I call these functions in the MainScreen class, these functions are called again and they do not keep the current value. So it returns me a new value and the value of both is the same because I called both at the same time.
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivymd.app import MDApp
from time import sleep, time
from random import randint
from kivymd.uix.label import MDLabel
Window.size = (300, 500)
helper = """
ScreenManager:
MenuScreen:
ReflexScreen:
MainScreen:
<MainScreen>:
id: main
name: 'main'
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
elevation:10
Widget:
MDRectangleFlatButton:
text: 'P L A Y'
on_press: root.manager.current = 'menu'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
MDLabel:
id: score_label
size_hint_x: 0.45
size_hint_y: None
pos_hint: {'center_x':0.5, 'center_y':0.4}
<ReflexScreen>:
id: reflex
name: 'reflex'
Button:
id: reflex_button
text: 'Wait Change The Color'
font_size: '20sp'
pos_hint: {'center_x':0.5, 'center_y':0.5}
on_press: root.manager.current = 'main'
size_hint_x: None
size_hint_y: None
width: 300
height: 500
background_color: 1,0,0,0.8
<MenuScreen>
id: menu
name: 'menu'
BoxLayout:
orientation: 'vertical'
MDToolbar:
title: 'Test Your Reflex'
elevation:10
Widget:
MDRectangleFlatButton:
text: 'P L A Y'
on_press: root.manager.current = 'reflex'
size_hint_x: None
size_hint_y: None
width: 20
height: 30
pos_hint: {'center_x':0.5, 'center_y':0.5}
md_bg_color: 0.2,0.3,0.6,0.1
text_color: 0.2, 0.5, 0.6, 1
"""
class ReflexScreen(Screen):
def on_enter(self, *args):
"""Event fired when the screen is displayed: the entering animation is
complete."""
sleep(randint(1,6))
self.ids.reflex_button.background_color = (0,1,0,0.8)
start = time()
print(start)
self.ids.reflex_button.text = 'CLICK !!!'
return start
def on_leave(self, *args):
end = time()
print(end)
self.ids.reflex_button.background_color = (1,0,0,0.8)
return end
"""rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()"""
class MainScreen(Screen):
def on_enter(self, *args):
rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()
#reflexclass = ReflexScreen()
#final_time = reflexclass.on_leave()-reflexclass.on_enter()
#print(final_time)
final_time = (end-start)
self.ids.score_label.text = f"TIME : {str(final_time)}"
If I add the code block below between two classes and use these variables in the MainScreen class,
rscreen = ReflexScreen()
start = rscreen.on_enter()
end = rscreen.on_leave()
I can get the result I want, but if I do this, kivy will tell me self.ids.reflex_button.background_color = (0,1,0,0.8) File "kivy \ properties.pyx", line 863, in kivy.properties.ObservableDict .__ getattr__ AttributeError: 'super' object has no attribute returns '__getattr__' error.
I think the reason for this is because of this. When the window is first loaded, the name value defined in the helper is not assigned, that name value is defined for the class when the window is opened for the second time. By doing a print (self), I see that the name value returns empty the first time and full the second time. How can I solve this problem or get the time difference between clicks?
The on_enter() and on_leave() methods are called for you. You do not need to explicitly call them yourself. You also do not need to do:
rscreen = ReflexScreen()
The ReflexScreen in your GUI is created when you load your helper string. and rscreen above is not the instance that appears in your GUI.
You can get the time difference by saving the start and end time in the ReflexScreen class, and adding a method to get the time difference:
class ReflexScreen(Screen):
start = NumericProperty()
end = NumericProperty()
def on_enter(self, *args):
"""Event fired when the screen is displayed: the entering animation is
complete."""
sleep(randint(1,6))
self.ids.reflex_button.background_color = (0,1,0,0.8)
self.start = time()
print(self.start)
self.ids.reflex_button.text = 'CLICK !!!'
# return start
def on_leave(self, *args):
self.end = time()
print(self.end)
self.ids.reflex_button.background_color = (1,0,0,0.8)
# set the text of a Label in MainScreen to show time difference
self.manager.get_screen('main').ids.score_label.text = str(self.end - self.start)
# return end
# a method to get the time difference
def get_time_diff(self):
return self.end - self.start
Haven't tested this code, so there may be some errors.
Related
I am searching for a way to animate my MDCard when expanding or collapsing.
In my example, when I click my MDIconButton I want an animation that slowly expands or collapses the card.
I know there is an MDExpansionsPanel widget but for now, I'm not interested in using this. Is there an easy way to implement an animation that is similar to the ExpansionPanel?
main.kv
MDScreen:
MDBoxLayout:
orientation: "vertical"
MDCard:
id: card
orientation: "vertical"
md_bg_color: .7, .7, .7, 1
padding: dp(20)
size_hint: .5, None
height: self.minimum_height
pos_hint: {"center_x": .5}
MDIconButton:
icon: "chevron-down"
on_press: app.on_chevron()
Widget:
<Box>:
orientation: "vertical"
size_hint_y: None
height: self.minimum_height
main.py
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.uix.boxlayout import MDBoxLayout
from kivymd.uix.label import MDLabel
Window.size = {320, 600}
class Box(MDBoxLayout):
pass
class MainApp(MDApp):
def build(self):
self.is_expanded = False
return Builder.load_file("main.kv")
def on_chevron(self):
self.is_expanded = not self.is_expanded
card_layout = self.root.ids.card
if self.is_expanded:
item = Box()
for i in range(10):
item.add_widget(MDLabel(text=f"Lbl: {i}", size_hint=(1, None), height=20))
card_layout.add_widget(item)
else:
card_layout.remove_widget(card_layout.children[0])
if __name__ == "__main__":
MainApp().run()
You can use Animation to do that. Here is a modified version of your on_chevron() method that uses Animation:
def on_chevron(self):
self.is_expanded = not self.is_expanded
card_layout = self.root.ids.card
if self.is_expanded:
item = Box()
labels = []
for i in range(10):
# initialze Label with 0 height and font_size
l = Label(text=f"Lbl: {i}", color=(0,0,0,1), font_size=0, size_hint=(1, None), height=0)
item.add_widget(l)
labels.append(l)
card_layout.add_widget(item)
self.animate_labels(labels)
else:
card_layout.remove_widget(card_layout.children[0])
def animate_labels(self, labels):
anims = []
for i in range(len(labels)):
anims.append(Animation(height=20, font_size=15)) # animate height and font_size
for i in range(len(labels)):
anims[i].start(labels[i]) # start animations
I switched your MDLabel to Label just because MDLabel meddles with sizes. There may be a way to do this with the MDLabel.
I am working on the same issue from my previous post. Now I added screen manager, and I can switch to different pages.
why is my kivy program not calling the function from another class?
I am still confused about OOP with GUIs, however I tried the following, and none of them worked.
I tried to add an instance of Screen 1() in the main app(), and it did nothing. Then, I tried to add the contractor method init into Screen_1() and it says I don't have a build method. And few other ideas that didn't work at all.
Then I realized that there is no link between Screen_Manager() and Screen_1() because all of my methods are in Screen_1(), but the build method is returning Screen_Manager(). On my kv file, there is this code:
<Screen_Manager>:
Screen_1:
Screen_2:
isn't this is where the program "links" between the Screen_Manager() class to other classes?
if someone can help me understand what I am not understanding and help me correct my problem, it would help me to learn about kivy. I understand, <> is like apply to rules, which has 2 widgets screen 1 and screen 2, and also have their own rules.
here is my main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.lang.builder import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.modules import keybinding
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
class Screen_Manager(ScreenManager):
pass
class Screen_1(Screen):
main_display = ObjectProperty()
text_input = ObjectProperty()
def plus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value + 1)
def minus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value - 1)
def up(self):
self.main_display.text = self.text_input.text
self.text_input.text = ''
class Keyboard(Widget):
def __init__(self, instance):
super().__init__()
self.a = instance
self.keyboard = Window.request_keyboard(None, self)
self.keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'enter':
self.a.up()
return True
class Screen_2(Screen):
pass
class MainApp(App):
def build(self):
self.title = "Number Control App"
self.sm = Screen_Manager()
key = Keyboard(self.sm)
return self.sm
if __name__=="__main__":
MainApp().run()
my kv file
<Screen_Manager>:
Screen_1:
Screen_2:
<Screen_1>:
name: "first"
main_display: display_1
text_input: text_input_1
#------inherenting from BoxLayout
BoxLayout:
orientation: "vertical"
#------begining of conent--
BoxLayout:
size_hint_y: 1
#-nexted content------
Label:
id: display_1
text: "0"
font_size: "150sp"
background_color: 0.1, 0.5, 0.6,
#--------
BoxLayout:
size_hint_y: .35
orientation: "horizontal"
#-nexted content------
Button:
text: "-"
font_size : "60sp"
on_press: root.minus_1()
#-nexted content------
Button:
text: "+"
font_size : "35sp"
background_color: (0, 1, 0, 1)
on_press: root.plus_1()
#--------
BoxLayout:
size_hint_y: .15
orientation: "horizontal"
#-nexted content-------
Button:
text: "Config"
size_hint_x: .25
on_release:
root.manager.current = "second"
root.manager.transition.direction = "left"
#-nexted content-------
TextInput:
id: text_input_1
size_hint_x: 1
hint_text: "Enter your initial # here"
multiline: False
#-nexted content-------
Button:
text: "Up"
size_hint_x: .25
on_press: root.up()
<Screen_2>:
name: "second"
Button:
text: "Go Back"
on_press:
app.root.current = "first"
root.manager.transition.direction = "right"enter code here
thanks again for taking the time to help.
Not sure I understand your question, but pressing Enter in your TextInput executed your code:
self.a.up()
but a in your KeyBoard is the Screen_Manager as set at the line:
self.sm = Screen_Manager()
key = Keyboard(self.sm)
and Screen_Manager has no up method. You can fix that by changing the code in your KeyBoard code to:
self.a.current_screen.up()
Note that this will only work when the current screen is Screen_1.
I'm not that new to Python so I have a basic understanding but I wouldn't say that I'm all that great either.
I've been having a tonne of problems with a brazilian jiujitsu app that I'm trying to make in Kivy. I am trying to get the text from a button that has been pressed in one window, and then use that text in a label for the next window that shows. The former window I have given the class name GuardWindow() and the latter window is called SweepSubTranPage().
I have managed to send the name of the button from my kivy file to the class GuardsWindow() easily enough, and the line self.guardlabel = instance.text works fine and retrieves the button name perfectly. My main problem however is sending that name over to the SweepSubTranPage() so that i can access it in my kivy file.
Here is the Python code:
class GuardsWindow(Screen):
guardButtonName = ObjectProperty(None)
def send_guard_type(self, instance, **kwargs):
self.guardButtonName = instance.text # retrieves the button name
def sender(self): # my attempt at sending it to the other class
return self.guardButtonName
class SweepSubTranPage(Screen):
pageTitle = ObjectProperty(None)
gw = GuardsWindow()
pageTitle.text = gw.sender()
kv = Builder.load_file("my.kv")
class MyMainApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyMainApp().run()
And here is the Kivy file code:
<GuardsWindow>
name: "GuardsHomepage"
ScrollView:
bar_width: 10
do_scroll_x: False
do_scroll_y: True
scroll_type: ["bars", "content"]
BoxLayout:
orientation: "vertical"
size_hint: 1, 2
padding: 10
spacing: 10
Button: # these are the buttons that i am getting the text from
text: "Full Guard"
on_press:
root.send_guard_type(self) # this sends the button
on_release:
app.root.current = "SweepSubTranPage"
root.manager.transition.direction = "left"
Button:
text: "Half Guard"
on_press:
root.send_guard_type(self) # this sends the button
on_release:
app.root.current = "SweepSubTranPage"
root.manager.transition.direction = "left"
<SweepSubTranPage>
name: "SweepSubTranPage"
pageTitle: title
BoxLayout:
orientation: "horizontal"
size_hint: 1, 0.1
Label: # this is the label that I need the text for
id: title
font_size: 40
size_hint: 1, 1
When I run the code above, I get the error:
File "C:/Users/bensw/PycharmProjects/BJJ Tracker/main.py", line 36, in <module>
class SweepSubTranPage(Screen):
File "C:/Users/bensw/PycharmProjects/BJJ Tracker/main.py", line 40, in SweepSubTranPage
pageTitle.text = gw.sender()
AttributeError: 'kivy.properties.ObjectProperty' object has no attribute 'text'
I hope I have been clear enough in explaining my issue. If you have any questions please ask!
Thank you so much!!
In your send_guard_type() method you can access another Screen using the manager property of any Screen, and the get_screen() method of the ScreenManager. Something like this:
def send_guard_type(self, instance, **kwargs):
self.guardButtonName = instance.text # retrieves the button name
self.manager.get_screen("SweepSubTranPage").ids.title.text = instance.text
OK, I try to make my first App in Kivy and I have a Problem with multiple Instances of my Root Widget.
I need to add widgets to my app while running. (to display a spreadsheet)
But because of the multiple instances of the Root Widget, I can't access the widgets with the kivy ids lookup object.
https://kivy.org/docs/guide/lang.html
I made three Buttons to display the problem in the console
Button -1-, -2-, and -3-
Please explain me why there are multiple instances and how I can prevent it, so the code will work.
Thanks for your help!
File --> Match.py
#!python
from __future__ import print_function
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
import gc
class my_gc():
def search_g(self):
for obj in gc.get_objects():
if isinstance(obj, Root):
try:
print(obj.ids)
except:
print('fail')
#Root Widget
class Root(BoxLayout):
sm = ObjectProperty(None)
sc0 = ObjectProperty(None)
sc1 = ObjectProperty(None)
sc2 = ObjectProperty(None)
sc3 = ObjectProperty(None)
mylbl0 = StringProperty('screen 0')
mylbl1 = StringProperty('screen 1')
mylbl2 = StringProperty('screen 2')
mylbl3 = StringProperty('screen 3')
def find_ids(self):
print(self.ids)
class Screen_Manager(ScreenManager):
pass
class Screen_0(Screen):
pass
class Screen_1(Screen):
pass
class Screen_2(Screen):
pass
class Screen_3(Screen):
pass
class Match(App):
rootwidget = Root()
sm = Screen_Manager()
gc = my_gc()
def build(self):
pass
Match().run()
File --> Match.kv
#Root Widget (BoxLayout)
Root:
sm: sm
sc1: sc0
sc1: sc1
sc1: sc2
sc1: sc3
BoxLayout:
spacing: '20dp'
orientation: 'vertical'
Screen_Manager:
id: sm
Screen_0:
id: sc0
name: 'sc0'
manager: 'sm'
BoxLayout:
id: box_0-0
Label:
id: lbl_0
text: app.rootwidget.mylbl0
Label:
id: lbl_0-1
text: root.mylbl0
Screen_1:
id: sc1
name: 'sc1'
manager: 'sm'
Label:
id: lbl1
text: root.mylbl1
Screen_2:
id: sc2
name: 'sc2'
manager: 'sm'
Label:
id: lbl2
text: root.mylbl2
Screen_3:
id: sc3
name: 'sc3'
manager: 'sm'
Label:
id: lbl3
text: root.mylbl3
#Tab-Buttons
BoxLayout:
size_hint: 1 , None
height: '60dp'
orientation: 'horizontal'
Button:
text: '-0-'
on_press: root.sm.current = sc0.name
Button:
text: '-1-'
on_press: root.sm.current = sc1.name
Button:
text: '-2-'
on_press: root.sm.current = sc2.name
Button:
text: '-3-'
on_press: root.sm.current = sc3.name
Button:
text: '<'
size_hint: None , 1
width: '60dp'
on_press: root.sm.current = root.sm.previous()
Button:
text: '>'
size_hint: None , 1
width: '60dp'
on_press: root.sm.current = root.sm.next()
Button:
text: '-b1-'
size_hint: None , 1
width: '60dp'
#on_press: root.search_g() #<-- doesn't work
on_press: app.gc.search_g() #<-- works
Button:
text: '-b2-'
size_hint: None , 1
width: '60dp'
on_press: root.find_ids() #<-- doesn't work
on_press: app.rootwidget.find_ids() #<-- works
Button:
text: '-b3-'
size_hint: None , 1
width: '60dp'
on_press: print(root.mylbl1) #<-- works
on_press: print(app.rootwidget.mylbl1) #<-- works
Mutilple Instance - Root Widget
As per your code, you don't have mutiple instances of the root widget. Your root widget is Root: as per the kv file, match.kv.
root.search_g()
It doesn't work because your root which is the class Root(BoxLayout) does not have the search_g() method.
root.find_ids - works
When I commented off app.rootwidget.find_ids, the call to root.find_ids works i.e. it printed the ids. The keyword root is available only in rule definitions and represents the root widget of the rule (the first instance of the rule). When your kv file is parsed, kivy collects all the widgets tagged with id’s and places them in self.ids dictionary type property.
app.rootwidget.find_ids
It works but there were no ids because it is referencing to the method find_ids in the initiated object, class Root. The rootwidget is just a variable by name and it is a different object than the one from Root:
From the attached screen shot, you will notice that the object locations for root.find_ids and app.rootwidget.find_ids are different.
Adding Widgets Dynamically
To add widgets dynamically into your app while it is running, you have to do the following. For an example, please refer to my other post at Kivy/python : when i click row then it shows error IndexError: list index out of range
Python Script - match.py
Add an import statement as follow:
from kivy.properties import ObjectProperty
Declare a variable (e.g. container) or ObjectProperty type e.g. in the class Root
class Root(BoxLayout):
container = ObjectProperty(None)
Remove all widgets added dynamically before adding
Add widgets dynamically.
kv File - match.kv
Define a layout e.g. BoxLayout or GridLayout in your kv file.
Give an id to the layout e.g. container in your kv file.
Hook up the ObjectProperty to the id
Root:
container: container
...
# Container for adding widgets dynamically
BoxLayout:
id: container
Solution
The solution is to declare an ObjectProperty, rootwidget as follow:
snippet
class Match(App):
rootwidget = ObjectProperty(None)
title = "Solution App"
gc = my_gc()
def build(self):
self.rootwidget = Root()
return self.rootwidget
match.py
#!python
from __future__ import print_function
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
import gc
class my_gc():
def search_g(self):
print("my_gc.search_g called")
for obj in gc.get_objects():
if isinstance(obj, Root):
try:
print("obj={0}, ids={1}".format(obj, obj.ids))
for key, value in obj.ids.items():
print(" key={0}, value={1}".format(key, value))
except:
print('fail')
# Root Widget
class Root(BoxLayout):
sm = ObjectProperty(None)
sc0 = ObjectProperty(None)
sc1 = ObjectProperty(None)
sc2 = ObjectProperty(None)
sc3 = ObjectProperty(None)
mylbl0 = StringProperty('screen 0')
mylbl1 = StringProperty('screen 1')
mylbl2 = StringProperty('screen 2')
mylbl3 = StringProperty('screen 3')
def find_ids(self):
print("Root.find_ids called")
print("self={0}, self.ids={1}".format(self, self.ids))
for key, value in self.ids.items():
print(" key={0}, value={1}".format(key, value))
class Screen_Manager(ScreenManager):
pass
class Screen_0(Screen):
pass
class Screen_1(Screen):
pass
class Screen_2(Screen):
pass
class Screen_3(Screen):
pass
class Match(App):
rootwidget = ObjectProperty(None)
title = "Solution App"
gc = my_gc()
def build(self):
self.rootwidget = Root()
return self.rootwidget
if __name__ == "__main__":
Match().run()
match.kv
#Root Widget (BoxLayout)
<Root>:
sm: sm
sc1: sc0
sc1: sc1
sc1: sc2
sc1: sc3
BoxLayout:
spacing: '20dp'
orientation: 'vertical'
Screen_Manager:
id: sm
Screen_0:
id: sc0
name: 'sc0'
manager: 'sm'
BoxLayout:
id: box_0-0
Label:
id: lbl_0
text: root.mylbl0
Label:
id: lbl_0-1
text: root.mylbl0
Screen_1:
id: sc1
name: 'sc1'
manager: 'sm'
Label:
id: lbl1
text: root.mylbl1
Screen_2:
id: sc2
name: 'sc2'
manager: 'sm'
Label:
id: lbl2
text: root.mylbl2
Screen_3:
id: sc3
name: 'sc3'
manager: 'sm'
Label:
id: lbl3
text: root.mylbl3
#Tab-Buttons
BoxLayout:
id: secondBoxLayout
size_hint: 1 , None
height: '60dp'
orientation: 'horizontal'
Button:
text: '-0-'
on_press: root.sm.current = sc0.name
Button:
text: '-1-'
on_press: root.sm.current = sc1.name
Button:
text: '-2-'
on_press: root.sm.current = sc2.name
Button:
text: '-3-'
on_press: root.sm.current = sc3.name
Button:
text: '<'
size_hint: None , 1
width: '60dp'
on_press: root.sm.current = root.sm.previous()
Button:
text: '>'
size_hint: None , 1
width: '60dp'
on_press: root.sm.current = root.sm.next()
Button:
text: '-b1-'
size_hint: None , 1
width: '60dp'
on_press:
print("\non_press: {}".format(self.text))
# root.search_g() #<-- doesn't work
print(" app.gc_search_g()")
app.gc.search_g() #<-- works
Button:
text: '-b2-'
size_hint: None , 1
width: '60dp'
on_press:
print("\non_press: {}".format(self.text))
print(" root.find_ids()")
root.find_ids() #<-- works
print("\n app.root.find_ids()")
app.rootwidget.find_ids() #<-- works
Button:
text: '-b3-'
size_hint: None , 1
width: '60dp'
on_press:
print("\non_press: {}".format(self.text))
print(root.mylbl1) #<-- works
print(app.rootwidget.mylbl1) #<-- works
Output
Hy, the problem is that with the current code, which is at this point preety much nothing but a text editor, when ever I try to make a scrollable label in the kv language and call it on the main screen at the push of a button, I get no error, theres just nothing there. I should mention that the text is taken from a stored file, and the only version that works is with a regular label. This is the code, I know its a bit long but its preety easy to understand so stay with me. Any sort of input is greatly apreciated and I thank you for taking the time.
#kivy.require("1.8.0")
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.uix.scatter import Scatter
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.properties import StringProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Line
from kivy.uix.gridlayout import GridLayout
kv = '''
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManager:
transition: FadeTransition()
MainScreen:
AddScreen:
AppendScreen:
<ScatterTextWidget>:
orientation: 'vertical'
TextInput:
id: main_input
font_size: 14
size_hint_y: None
height: root.height - botones_layout.height
font_color: [0.1,0.3,0.9,1]
focus: True
foreground_color: [0.2,0.5,0.9,1]
cursor_color: [0,0,1,1]
BoxLayout:
id: botones_layout
orientation: 'horizontal'
height: 30
Button:
id: home_button
text: "Back Home"
Button:
id: save_button
text: "Save to file"
on_press: root.saveToFile("Archive.txt", main_input.text)
<AppendTextWidget>:
orientation: 'vertical'
TextInput:
text: root.text
id: main_input
font_size: 14
size_hint_y: None
height: root.height - botones_layout.height
font_color: [0.1,0.3,0.9,1]
focus: True
foreground_color: [0.2,0.5,0.9,1]
cursor_color: [0,0,1,1]
BoxLayout:
id: botones_layout
orientation: 'horizontal'
height: 30
Button:
id: home_button
text: "Back Home"
on_release: app.root.current = "main"
Button:
id: save_button
text: "Save"
on_press: root.append(main_input.text)
#This does not work <--- <--- <---
<ScrollableLabel>:
Label:
text: root.text
font_size: 15
text_size: self.width, None
color: [0,255,0,1]
padding_x: 20
size_hint_y: None
pos_hint: {"left":1, "top":1}
height: self.texture_size[1]
<MainScreen>:
name: "main"
FloatLayout:
# This does work
Label:
text: root.text
font_size: 15
text_size: self.width, None
color: [0,255,0,1]
padding_x: 20
size_hint_y: None
pos_hint: {"left":1, "top":1}
height: self.texture_size[1]
ActionBar:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: "Text"
with_previous: False
ActionOverflow:
ActionButton:
text: "New"
on_release: app.root.current = "add"
ActionButton:
text: "Update"
on_press: root.clicked()
ActionButton:
text: "Add"
on_release: app.root.current = "append"
<AddScreen>:
name: "add"
FloatLayout:
ScatterTextWidget
<AppendScreen>:
name: "append"
FloatLayout:
AppendTextWidget
'''
class ScatterTextWidget(BoxLayout):
def saveToFile(self,name,text):
f = open(name, "w")
f.write("\n\n\n" + " " + ">>>" + text + "test"*500)
f.close()
class AppendTextWidget(BoxLayout):
text = StringProperty("")
def append(self,text):
with open("Archive.txt", "a") as f:
f.write("\n" + " " + ">>>" + text)
f.close()
class ScrollableLabel(ScrollView):
text = StringProperty('')
pass
class MainScreen(Screen):
text = StringProperty("")
def clicked(self):
with open("Archive.txt", "r") as f:
contents = f.read()
self.text = contents
pass
class AddScreen(Screen):
pass
class AppendScreen(Screen):
pass
class MyApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
MyApp().run()
Why it works:
Your text in MainScreen is updated from file, then passed to Label and the text is loaded. ScrollableLabel.text stays unchanged.
Why it doesn't work as you expect:
There's no communication between your classes, therefore only text changed is an actual self.text = MainScreen.text
How to make it work:
Either use something on a global range, i.e. variable in your App class, then a = App.get_running_app() and access variable through a.<variable> or use __init__ to initialize your ScrollableLabel inside the MainScreen and pass it the text
So it's basically a duplicate of this and that one is a duplicate of an older unsimplified question.