How to keep the same label text between two screens kivy - python

I'm new to kivy and python so my code isn't perfect.
I'm trying to make a program with 2 screens, a first screen where there is a label with a text that is not defined and that can change and a second screen that keeps the same text as the first screen.
I've been searching for a week and I tried to make a global variable that I edit and that becomes the text of the second label but it doesn't work.
I also tried with String. property () or object. property () but I didn't get any more results and I didn't really understand how to use it.
Any help would be welcome <3
(sorry for my english)
Here is a part of my code that I have simplified as much as possible:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MenuScreen>:
label_wid : ratio
FloatLayout:
Button:
text: "options"
pos: 270, 240
size_hint: .30, .10
background_color: 0,1,0,0.75
on_press: root.manager.current = 'settings'
Label:
id:ratio
text: ""
pos: 0,90
font_size:30
color:1,0,0,1
<SettingsScreen>:
label_wid2 : ratio
FloatLayout:
Label:
id:ratio
text: str(root.texte2())
pos: 0,90
font_size:30
color:1,0,0,1
""")
u=""
class MenuScreen(Screen):
def texte(self):
global u
u= self.label_wid.text = 'exemple'
pass
class SettingsScreen(Screen):
def texte2(self):
self.label_wid2.text=u
pass
class Quizz(App):
def build(self):
self.title = 'Quizz'
Window.clearcolor = (0, 1, 1, 0.25)
return sm
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
if __name__ == '__main__':
Quizz().run()
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_string("""
<MenuScreen>:
label_wid : ratio
FloatLayout:
Button:
text: "options"
pos: 270, 240
size_hint: .30, .10
background_color: 0,1,0,0.75
on_press: root.manager.current = 'settings'
Label:
id:ratio
text: ""
pos: 0,90
font_size:30
color:1,0,0,1
<SettingsScreen>:
label_wid : ratio
FloatLayout:
Label:
id:ratio
text: root.texte2()
pos: 0,90
font_size:30
color:1,0,0,1
""")
u=""
class MenuScreen(Screen):
def texte(self):
global u
u= self.label_wid.text = 'exemple'
pass
class SettingsScreen(Screen):
def texte2(self, text):
u
pass
class Quizz(App):
def build(self):
self.title = 'Quizz'
Window.clearcolor = (0, 1, 1, 0.25)
return sm
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))
if __name__ == '__main__':
Quizz().run() ```

Using a StringProperty in the ScreenManager and another in SettingsScreen provide a source of text for both Labels in the different Screens. And changing the StringProperty can change both Labels:
from kivy.app import App
from kivy.clock import Clock
from kivy.properties import StringProperty
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
class MenuScreen(Screen):
pass
class SettingsScreen(Screen):
# this is the text to be used when the first Label text is not '1'
theOtherText = StringProperty('Not One')
class MyScreenManager(ScreenManager):
# This is the text that both Labels may display
theText = StringProperty('0')
kv = """
MyScreenManager:
MenuScreen:
name: 'menu'
SettingsScreen:
name: 'settings'
<MenuScreen>:
label_wid : ratio
FloatLayout:
Button:
text: "options"
pos: 270, 240
size_hint: .30, .10
background_color: 0,1,0,0.75
on_press: root.manager.current = 'settings'
Label:
id:ratio
# Use theText Property from MyScreenManager
text: root.manager.theText
pos: 0,90
font_size:30
color:1,0,0,1
<SettingsScreen>:
label_wid : ratio
FloatLayout:
Label:
id:ratio
# Use theText Property from MyScreenManager
text: '1' if root.manager.theText == '1' else root.theOtherText
pos: 0,90
font_size:30
color:1,0,0,1
"""
class Quizz(App):
def build(self):
self.title = 'Quizz'
Window.clearcolor = (0, 1, 1, 0.25)
Clock.schedule_once(self.change_text, 4)
return Builder.load_string(kv)
def change_text(self, dt):
print('changing text')
self.root.theText = '1'
if __name__ == '__main__':
Quizz().run()
Building the MyScreenManager in the kv eliminates the need to check if the manager attribute of the Screens is set. That simplifies the logic in the kv. Then the line in kv:
text: '1' if root.manager.theText == '1' else root.theOtherText
sets the text of the second Label to 1 if the first Label text is 1, otherwise it is set to the value of theOtherText in the SettingsScreen.
I have added a Clock.schedule_once() just for testing.

Related

Access to variables from Popup class in .kv file

I need light/dark theme. I can make it work but I want another solution (I know about KivyMD too but in this case I don't want to use it).
In short: I have multiple screens and on all screens there is a Popup button.
On the Popup, there are two buttons: light and dark. So when I press light or dark it should changes the background color of the screens.
My problem is that I don't know how to access to Popup class from the .kv file. Could you give me a solution or a hint how to achive this?
Minimal code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.properties import ListProperty
Builder.load_string("""
<FirstScreen>:
canvas.before:
Color:
#--------------> how to access to popup class from here?
#rgba: ???.my_background_color
rgba: 240/255, 240/255, 240/255, 1
Rectangle:
pos: self.pos
size: self.size
Button:
text: 'Popup'
size_hint: 0.5, 0.5
on_release:
root.the_popup()
<MyPopup>
size_hint: 0.75 , 1
title: 'T H E M E'
BoxLayout:
Button:
text: 'D A R K'
on_release:
root.dark()
Button:
text: 'L I G H T'
on_release:
root.light()
"""
)
class FirstScreen(Screen):
def the_popup(self):
the_popup = MyPopup()
the_popup.open()
class MyPopup(Popup):
my_background_color = ListProperty([240/255, 240/255, 240/255, 1])
def light(self):
self.my_background_color = [240/255, 240/255, 240/255, 1]
def dark(self):
self.my_background_color = [48/255, 48/255, 48/255, 1]
class myApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(FirstScreen(name='first'))
return sm
if __name__ == '__main__':
myApp().run()

Kivy: How to check the location of a drag behavior item

Not much code yet, but I am trying to make the buttons stay if they are on the right side, but if they are on the left, to disappear. I am not sure if this is possible, but if you are able to help, I would love it!main.py:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.behaviors import DragBehavior
from kivy.uix.button import Button
Builder.load_file('main.kv')
class DragButton(DragBehavior, Button):
pass
class MainScreen(Widget):
pass
class WorkingApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
WorkingApp().run()
​
main.kv
<DragButton>
drag_rectangle: self.x, self.y, self.width, self.height
drag_timeout: 10000
drag_distance: 0
text: 'Hi'
size_hint: (1, .5)
<MainScreen>
BoxLayout:
size: root.width, root.height
orientation: 'horizontal'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Widgets'
size_hint: (1, .25)
DragButton:
DragButton:
DragButton:
Splitter:
sizable_from: 'left'
Label:
text: 'Check If they are here'
One way to do this is to bind a method to the center_x property of the DragButtons. That method can then check the position of the DragButton, and remove it, if it is to the right of the Splitter:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.behaviors import DragBehavior
from kivy.uix.button import Button
Builder.load_file('main.kv')
class DragButton(DragBehavior, Button):
pass
class MainScreen(Widget):
splitter = ObjectProperty(None)
boxlayout = ObjectProperty(None)
def dragged(self, dragButton):
if dragButton.center_x > self.splitter.x:
self.boxlayout.remove_widget(dragButton)
class WorkingApp(App):
def build(self):
return MainScreen()
if __name__ == '__main__':
WorkingApp().run()
with some small modifications to the 'kv':
<DragButton>
drag_rectangle: self.x, self.y, self.width, self.height
drag_timeout: 10000
drag_distance: 0
text: 'Hi'
size_hint: (1, .5)
<MainScreen>
splitter: split
boxlayout: box
BoxLayout:
size: root.width, root.height
orientation: 'horizontal'
BoxLayout:
id: box
orientation: 'vertical'
Label:
text: 'Widgets'
size_hint: (1, .25)
DragButton:
on_center_x: root.dragged(self)
DragButton:
on_center_x: root.dragged(self)
DragButton:
on_center_x: root.dragged(self)
Splitter:
id: split
sizable_from: 'left'
Label:
text: 'Check If they are here'
Key modifications are the addition of ids in the kv for the Splitter and the BoxLayout and methods bound to the center_x property of each DragButton. In the python, ObjectProperties for those new ids and the dragged() method are added to the MainScreen class. The dragged() method just checks if the center of the DragButton is roght of the Splitter and removes that DragButton if it is.

Pass a list to/from Kivy textinput dialog

I have a list to display to the user but I want to break each section to a separate textinput as it will make more sense that way. I then need to be able to capture those changes and update my variable.
I need to get the variables to display correctly tlmanualreg being backgroundManualReg[0] and on closeit() store the changes back to a list.
EDIT: Updated with bare bones popup project to test variable exchanging.
from kivy.properties import StringProperty
from os.path import join, dirname
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.app import App
import json
Builder.load_string("""
<-MyPopup#Popup>:
tlpos:tlpos
tlmanualreg:tlmanualreg
cols: 1
GridLayout:
cols:3
Label:
text: "Location"
Label:
text: "Dist from Center (mm)"
Label:
text: "Corners of sheet (for manual-align)"
Label:
text: "Top-Left:"
TextInput:
id: tlpos
text: root.backgroundTLPOS
TextInput:
id: tlmanualreg
text: root.backgroundTLManualReg
Button:
size_hint_y:.1
text: 'Update Variables'
on_press: root.closeit()
""")
class ScreensApp(App):
def build(self):
content = MyPopup()
_popup = Popup(content=content, auto_dismiss=False)
_popup.open()
class MyPopup(Popup):
backgroundManualReg = [[551, 218], [3168, 319], [519, 1617], [3190, 1589]]
backgroundTLPOS = StringProperty("[0, 0]")
backgroundTLManualReg = StringProperty("[1,1],[2,2]")
def __init__(self, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.ids.tlmanualreg.text = str([1, 1])
self.backgroundTLManualReg = str(self.backgroundManualReg[0])
def closeit(self):
self.backgroundTLPOS = self.tlpos.text
print("backgroundTLPOS: ", self.backgroundTLPOS)
print("backgroundTLManualReg: ", self.ids.tlmanualreg.text)
print("backgroundManualReg: ", self.backgroundManualReg)
if __name__ == '__main__':
ScreensApp().run()
In the following example, we are:
Using dictionary. The key of the dictionary is use as Kivy widget's id and also as a reference to update the values.
Dynamically adding widgets as per item (key, value) in the dictionary
Retrieving data using for child in reversed(self.container.children) and isinstance(child, TextInput)
Example
main.py
from kivy.properties import StringProperty, DictProperty
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
import ast
Builder.load_string("""
<HeaderCell#Label>
text_size: self.size
halign: "left"
valign: "middle"
canvas.before:
Color:
rgba: 1, 0.502, 0, 1
Rectangle:
pos: self.pos
size: self.size
<MyPopup>:
title: 'My Popup'
container: container
GridLayout:
cols: 1
GridLayout:
cols: 3
size_hint_y: 0.1
HeaderCell:
text: "Location"
HeaderCell:
text: "Dist from Center (mm)"
HeaderCell:
text: "Corners of sheet (for manual-align)"
GridLayout:
id: container
cols:3
Button:
size_hint_y:.1
text: 'Update Variables'
on_press: root.closeit()
""")
class ScreensApp(App):
def build(self):
_popup = MyPopup(auto_dismiss=False)
_popup.open()
class MyPopup(Popup):
backgroundTLPOS = StringProperty("[0, 0]")
bgManualRegDict = DictProperty({'Top-Left': [551, 218], 'Top-Right': [3168, 319],
'Bottom-Left': [519, 1617], 'Bottom-Right': [3190, 1589]})
def __init__(self, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.populate_rows()
def populate_rows(self):
for key, value in self.bgManualRegDict.items():
location = Label(text="{}:".format(key), valign="middle")
location.bind(size=location.setter('text_size'))
bgTLpos = TextInput(text="{}".format(self.backgroundTLPOS))
bgTLmanualReg = TextInput(id="{}".format(key), text="{}".format(value))
self.container.add_widget(location)
self.container.add_widget(bgTLpos)
self.container.add_widget(bgTLmanualReg)
def closeit(self):
print("\ncloseit:")
for child in reversed(self.container.children):
if isinstance(child, TextInput):
if child.id in self.bgManualRegDict.keys():
print("\tid={0}, text={1}".format(child.id, child.text))
self.bgManualRegDict[child.id] = ast.literal_eval(child.text)
print("\n\tself.bgManualRegDict=", self.bgManualRegDict)
if __name__ == '__main__':
ScreensApp().run()
Output

Kivy Update Label Text with Variable

Question: How do I update Label text in this scenario?
Python code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
class SearchForPart(Widget):
def searchforpart(self):
Barty = 'text update';
demogar = DemoGarage()
demogar.ids.scrollref.UpdateParam(Barty)
class ScrollableLabel1(ScrollView):
text_variable_1 = StringProperty()
def __init__(self, **kwargs):
super(ScrollableLabel1, self).__init__(**kwargs)
self.text_variable_1 = 'initial'
def UpdateParam(self, param):
self.param = param
self.text_variable_1 = param
print(param)
class AnotherScreen(Screen):
pass
class MainScreen(Screen):
pass
class DemoGarage(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("garagemainexample.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kv code:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
DemoGarage:
<BigButton#Button>:
font_size: 40
size_hint: 0.5, 0.15
color: 0,1,0,1
<MainScreen>:
name: "main"
FloatLayout:
BigButton:
on_release: app.root.current = "demogarage"
text: "Demo Garage"
pos_hint: {"x":0.25, "top": 0.4}
<DemoGarage>:
name: "demogarage"
ScrollableLabel1:
id:scrollref
SearchForPart:
id:searchpart
<ScrollableLabel1>:
Label:
id: mylabel
text: root.text_variable_1
font_size: 20
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
padding_y: 10
padding_x: 140
<SearchForPart>:
size_hint: 1,1
FloatLayout:
Label:
text: "Search for Part:"
font_size: 30
pos_hint: {"x": 0.95, "y": 0.85}
color: 0,1,0,1
size_hint: 0.3, 0.2
TextInput:
id: partname
multiline: False
font_size: 30
pos_hint: {"x": 0.85, "y": 0.15}
color: 0,1,0,1
on_text_validate: root.searchforpart()
size_hint: 1, 0.5
After initializing program, the Label text is successfully initialized and outputs 'initial text'.
Once the 'searchforpart' method runs (as a response to hitting enter in search box), even though 'print(param)' prints 'text update', the label text isn't updated.
Question: How do I update Label text in this scenario?
Am I misunderstanding a core concept of how changes to the Kivy event loop are triggered?
Use a Kivy property:
from kivy.properties import StringProperty
class (YourClass):
text_variable_1 = StringProperty()
When you reference this property in kv, and its value changes, the gui will automatically update. If you don't use a property this doesn't happen because the kv code has no way to know the value changed.
Also, you don't have to follow pep8, but the property name should start with a lower case letter - it probably doesn't matter for your example, but can matter in kv if you try to set the property there.

Kivy - Adding Buttons To Screen Through Python

I am trying to make a screen view with buttons. The problem is that the amount of buttons needed each time will change, therefore I am not able to use the kv file to make theses buttons. I am having trouble adding buttons through the normal python code. Any help is appreciated.
import kivy
import webbrowser
import MSQLHandler
kivy.require('1.10.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Label
from kivy.uix.widget import Widget
from kivy.uix.listview import ListItemButton
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition, CardTransition, SwapTransition, FadeTransition, WipeTransition, FallOutTransition, RiseInTransition, NoTransition
from kivy.lang import Builder
from kivy.uix.button import Button
class Login_Failed(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Loged_In(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Registers(Screen):
def changeScreen(self, next_screen):
self.manager.current = next_screen
class Login_Screen(Screen):
teacher_connect_image = ObjectProperty()
username_text_input = ObjectProperty()
password_text_input = ObjectProperty()
teacherid_text_input = ObjectProperty()
def LoginButton(self):
if self.teacherid_text_input.text == "":
Number = 0
else:
Number = int(self.teacherid_text_input.text)
MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number)
def changeScreen(self, next_screen):
self.manager.current = next_screen
if MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is True:
print("Returns True")
changeScreen(self, "Loged_In")
elif MSQLHandler.LoginSystem(self.username_text_input.text, self.password_text_input.text, Number) is False:
print("Returns False")
changeScreen(self, "Login_Failed")
else:
print("Null")
class ScreenManagerr(ScreenManager):
pass
class MainKivyFrameApp(App):
def build(self):
Registers().add_widget(Button(text="Helpp"))
return ScreenManagerr()
mainFrame = MainKivyFrameApp()
mainFrame.run()
If you look to where the app is being built, you will see: Registers().add_widget(Button(text="Helpp"))
This is where I have tried to add a Button to the screen of Registers. This doesn't give me any errors, but it still does not show the button.
Solution
In the kv file, add an event (on_enter or on_pre_enter) in each screen and bind it to a callback method as shown in the following snippets and example. Remember to remove the widgets that were added dynamically before leaving the current screen, by adding an event (on_leave or on_pre_leave).
Snippets
<Registers>:
on_pre_enter: self.add_buttons(n)
on_leave: self.remove_buttons()
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.properties import ObjectProperty, NumericProperty
class MyScreenManager(ScreenManager):
total_button = NumericProperty(2)
class Login(Screen):
login = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (400, 300)
def check_password(self, instance, password):
if password == "pwd":
instance.current = "registers"
class Registers(Screen):
container = ObjectProperty(None)
def on_pre_enter(self):
Window.size = (800, 600)
def add_buttons(self, n):
print("Registers: n={}".format(n))
for i in range(n):
self.container.add_widget(Button(text="Button #{}".format(i), id=str(i)))
def remove_buttons(self, *args):
for child in [child for child in self.container.children]:
self.container.remove_widget(child)
class Welcome(Screen):
pass
class TestApp(App):
title = "ScreenManager - Add Widgets Dynamically"
def build(self):
return MyScreenManager()
if __name__ == "__main__":
TestApp().run()
test.kv
#:kivy 1.10.0
#:import SwapTransition kivy.uix.screenmanager.SwapTransition
<MyScreenManager>:
transition: SwapTransition()
Login:
Registers:
on_pre_enter:
self.add_buttons(app.root.total_button)
on_leave:
self.remove_buttons()
Welcome:
<Login>:
id: login
name: "login"
login: login
GridLayout:
size_hint: (0.5, 0.5)
pos_hint: {"center_x": 0.5, "center_y": 0.6}
rows: 3
padding: 20
Label:
size_hint: (0.2, 0.2)
text:"Password:"
font_size: 30
halign: "center"
valign: "middle"
TextInput:
id: password
size_hint: (0.2, 0.06)
cursor_blink: True
font_size: 20
multiline: False
password: True
Button:
text: "Continue"
size_hint: (0.2, 0.08)
on_release:
root.login.check_password(root.manager, password.text)
<Registers>:
name:'registers'
container: container
BoxLayout:
orientation: 'vertical'
Button:
text: 'Return to Login'
on_press: root.manager.current = 'login'
Button:
text: 'Next Screen'
on_press: root.manager.current = 'welcome'
BoxLayout:
id: container
orientation: 'vertical'
<Welcome>:
name:'welcome'
BoxLayout:
Label:
text: 'Welcome!'
Button:
text: 'Return to Registers'
on_press:
app.root.total_button = 5
root.manager.current = 'registers'
Output

Categories

Resources