I asked a question regarding updating label text (Kivy change label text with python) - it was answered and was working but I've been trying for hours trying to adapt my running code to ScreenManager so I can have multiple screens. I've cut down the code to the basic stuff I can't get working.
ScreenManager code breaks the solution, I know what the issue is I just can't resolve it. The code is working, text and time updating in the shell but not the labels, I couldn't add return self.first_screen to the Kivy def build so its not binding to the_time: _id_lbl_time - Any help/pointers would be really appreciated.
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty, StringProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition, FadeTransition
from kivy.uix.anchorlayout import AnchorLayout
from kivy.clock import Clock
import time
from datetime import datetime, timedelta
class FirstScreen(Screen):
def update_time(self, sec):
MyTime = time.strftime("%H:%M:%S")
print MyTime # to test update_time is called etc
self.the_time.text = MyTime #<---- self.the_time isn't working
class SecondScreen(Screen):
def update_text(self, sec):
MyText = 'New Text'
print MyText # to test update_text is called etc
self.the_set.text = MyText #<---- self.the_set isn't working
class MyScreenManager(ScreenManager):
pass
Builder.load_string('''
<FirstScreen>:
name: 'first'
the_time: _id_lbl_time
BoxLayout:
orientation: 'vertical'
Label
id: _id_lbl_time
text: 'Clock'
font_size: 30
BoxLayout:
Button:
text: 'New Here'
font_size: 20
size: 200, 50
size_hint: None, None
on_release: app.root.current = 'second'
<SecondScreen>:
name: 'second'
the_set: _id_lbl_set
BoxLayout:
orientation: 'vertical'
Label:
id: _id_lbl_set
text: 'New Here'
font_size: 30
BoxLayout:
Button:
text: 'Main'
font_size: 20
size: 200, 50
size_hint: None, None
on_release: app.root.current = 'first'
''')
class ScreenManagerApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(FirstScreen(name='first'))
sm.add_widget(SecondScreen(name='second'))
self.first_screen = FirstScreen()
self.sec_screen = SecondScreen()
return sm #<---- I can't return self.first_screen etc here?
def on_start(self):
Clock.schedule_interval(self.first_screen.update_time, 1) # 1 second
Clock.schedule_interval(self.sec_screen.update_text, 2)
ScreenManagerApp().run()
I can't return self.first_screen etc here?
No. There has to be a ScreenManager on top of the Screen widgets, otherwise it's just a RelativeLayout as is its definition in the source code.
You experienced a really common mistake by beginners. You used one instance FirstScreen() and SecondScreen() for ScreenManager(those are visible) and then you created another instances with:
self.first_screen = FirstScreen()
self.sec_screen = SecondScreen()
which you then used for Clock:
Clock.schedule_interval(self.first_screen.update_time, 1)
Clock.schedule_interval(self.sec_screen.update_text, 2)
and that means text properties in instances that actually aren't added anywhere as widgets were used for updating. The instances exist, so no error to trigger except the visual one → you don't see the values, because you used wrong instance.
Correct build():
def build(self):
sm = ScreenManager()
self.first_screen = FirstScreen(name='first')
self.sec_screen = SecondScreen(name='second')
sm.add_widget(self.first_screen)
sm.add_widget(self.sec_screen)
return sm
Related
I am writing a program that requires a label, a text_input, and a checkbox to be aligned on screen in that order. They should span the width of the screen and be at the same y level.
I have written this code in my .kv file which uses identical pos_hint values, but only the text_input box moves
Below is my .kv code:
<Union>:
BoxLayout:
orientation: "vertical"
BoxLayout:
orientation: "horizontal"
pos_hint_y: {"top":.85}
Label:
text: 'Session Length'
pos_hint: {"x":.3, "top":.85}
TextInput:
id: input
text: "test"
pos_hint: {"x":.5, "top":.85}
size_hint: 0.3, 0.05
background_disabled_normal: ""
disabled: not checkbox.active
on_text: app.return_text()
CheckBox:
id: checkbox
pos_hint: {"x":.7, "top":.85}
and here is my main.py
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.uix.button import Button
from kivy.uix.dropdown import DropDown
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import Screen, ScreenManager
Window.size = (309, 555)
class MenuScreen(Screen):
pass
class SetupScreen(Screen):
pass
class drop_content(DropDown):
pass
class UnionScreen(Screen):
class Checkbox_Setup(FloatLayout):
pass
class TheApp(App):
def build(self):
# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SetupScreen(name='setup'))
sm.add_widget(UnionScreen(name='union'))
return sm
def return_text(self):
text = self.root.get_screen('union').ids.input.text
print(text)
def main():
Builder.load_file('menu.kv')
app = TheApp()
app.run()
if __name__ == '__main__':
main()
Finally, here is the output I am currently getting, with the label and checkbox in line but underneath the text_input which is in the right place.
I am relatively new to kivy so any help would be greatly appreciated. Thanks in advance!
I am trying to collect data from several screens and display on last 'result' screen. For that I want to store values of different widgets in dict property and display them on the screen. The minimum demonstration:
.py:
from kivy.app import App
from collections import defaultdict
from kivy.uix.widget import Widget
from kivy.properties import (
NumericProperty, ReferenceListProperty, ObjectProperty, DictProperty
)
from kivy.vector import Vector
from kivy.clock import Clock
from kivy.uix.screenmanager import ScreenManager, Screen
import pickle
import kivy
class ResultScreen(Screen):
results = DictProperty({})
def get_values(self):
self.results = {1 : -1, 2 : -2}
class PongScreen(Screen):
pass
class TestApp(App):
def build(self):
sm = ScreenManager()
# print(f'------------{sm.manager}--------------')
sm.add_widget(PongScreen(name='menu'))
sm.add_widget(ResultScreen(name='result'))
return sm
TestApp().run()
.kv:
#:kivy 1.0.9
#:import Factory kivy.factory.Factory
<ResultScreen>:
on_enter: self.get_values()
BoxLayout:
orientation : 'vertical'
BoxLayout:
orientation : 'horizontal'
BoxLayout:
orientation : 'vertical'
Label:
text: str(root.results.keys())
<PongScreen>:
BoxLayout:
Button:
text: 'To results'
on_press: root.manager.current = 'result'
Button:
text: 'Exit'
on_press: app.stop()
I expect to get [1, 2] on the text of Label on ResultScreen. However I am getting empty list. As far as I understand it happens because initialization takes place before execution of get_values function. How can I display desired values?
Im trying to create GUI with kivy but can't figure this.Created Popup screen and trying to pick value from dropbox and add this value to my TextInput.
test.py:
from kivy.app import App
from kivy.uix.textinput import TextInput
from kivy.uix.dropdown import DropDown
from kivy.uix.spinner import Spinner
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
class MyDropDown(DropDown):
def on_select(self, data):
print('Selected value:',data)
#Lets add this data to TextInput ?
MyTextInput.text = data
#Lets check is that actual text ?
print('MyTextInput.text is:',MyTextInput.text)
#HOW CAN I ADD THIS TEXT TEXTINPUT AFTER THAT?
class MySpinner(Spinner):
dropdown_cls = ObjectProperty(MyDropDown)
class MyTextInput(TextInput):
pass
class MyTestPopup(Popup):
my_popup_spinner = ObjectProperty()
my_textinput_id = ObjectProperty()
class TestPage(Screen):
MypagePopup = ObjectProperty()
def open_my_popup(self, *args):
#Lets create my popup
self.MypagePopup = MyTestPopup()
self.MypagePopup.my_popup_spinner.values = ['Test1','Test2','Test3','Test4','Test']
self.MypagePopup.open()
class TestPageManager(ScreenManager):
pass
class test(App):
def build(self):
return TestPageManager()
if __name__=='__main__':
test().run()
test.kv:
<TestPageManager>:
TestPage:
name: 'mainpagename'
<MySpinner>:
text: 'Pick Value'
<MyDropDown>:
values: ['Test1','Test2','Test3','Test4','Test5']
<MyTextInput>:
<MyTestPopup>:
my_popup_spinner : my_popup_spinner
my_textinput_id : my_textinput_id
BoxLayout:
orientation: 'vertical'
Label:
text: 'Testing Label Area..'
pos: self.pos
size: self.size
MyTextInput:
id: my_textinput_id
MySpinner:
id: my_popup_spinner
Button:
text: 'Done'
on_release:
print('MyTextInput id is :',my_textinput_id.text)
<TestPage>:
Button:
text: 'Open Popup'
on_release: root.open_my_popup()
As you can see I created like that GUI.
But can't update TextInput after pick from spinner.How can i update this textinput after pick value from dropbox.I can't figure it out.I think i correctly describe my problem. Thanks for reading and answering.
kv = "Spinner:
on_text:
my_textinput_id.text = my_popup_spinner.text"
did this in my kv string for Builder.load_string(kv)and it works for me
you can try and implement it in you code example and see if it works.
set the id.text of the textinput = to my spinner id.text in the on_text: event of the Spinner
I am making a typing practice program, and I want to check if someone typed the correct phrase in TextInput, every time they enter a character.
I have tried using keyboard_on_key_down: root.CheckIfCorrect() to run the function and that raises an error the moment I click on the text input box.
https://pastebin.com/nqU7bXcn
Here's my code
main.py
from kivy.config import Config
Config.set('graphics', 'resizable', True)
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.core.window import Window
from kivy.properties import StringProperty
from kivy.uix.textinput import TextInput
import random
Builder.load_file("main.kv")
sentences = [
"My own brother, Aberforth, was prosecuted for practicing inappropriate charms on a goat. It was all over the papers, but did Aberforth hide? No, he did not! He held his head high and went about his business as usual! Of course, I'm not entirely sure he can read, so that may not have been bravery."
]
class TitleScreen(Screen):
def SwitchMain(self):
sm.switch_to(MainScreen(name="main"))
class MainScreen(Screen):
chosen = random.choice(sentences)
def CheckIfCorrect(self):
if self.chosen.startswith(self.ids.input.text) == True:
print("Correct")
else:
print("worng")
sm = ScreenManager()
sm.add_widget(TitleScreen(name='menu'))
sm.add_widget(MainScreen(name='settings'))
class TyperApp(App):
def build(self):
return sm
if __name__ == '__main__':
TyperApp().run()
main.kv
<TitleScreen>:
on_touch_up: root.SwitchMain()
BoxLayout:
orientation: "vertical"
Label:
text: "Welcome to Typer!"
font_size: 40
size_hint_y:2
Label:
text: "Click anything to begin..."
size_hint_y:1
<MainScreen>:
BoxLayout:
id:layout
orientation: "vertical"
Label:
id: lab
text: root.chosen
font_size: 25
padding: 10, 0
text_size: root.width, None
size: self.texture_size
size_hint_y:3
TextInput:
id: input
size_hint_y:2
multiline: False
#keyboard_on_key_down/up: root.CheckIfCorrect() This didn't work!
I expected it to print Correct in console whenever I typed correct, and Wrong when I typed incorrect. I will add more things that stop the person from typing if he typed wrong later.
I'm semi-OK with Python but brand new to Kivy, I know my problem is referencing the label ID but I can't seem to solve it and searching doesn't seem to give me what I need.
I'm trying to get a label to display the current time, so I know I have the right framework in terms of updating etc but I'm sure its all down to referencing the label ID somehow and its that I'm struggling with?
The following code runs fine, displays the labels etc until I try to update the label_text.text at which point i get an error: AttributeError: 'float' object has no attribute 'lbl_time'. I've tried str(time.strftime("%H:%M:%S")) but that doesn't solve it.
from kivy.app import App
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.properties import ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen, WipeTransition, FadeTransition
from kivy.uix.anchorlayout import AnchorLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import time
from datetime import datetime
class MainScreen(Screen):
def update_time(self):
lbl_time = ObjectProperty()
MyTime = time.strftime("%H:%M:%S")
self.lbl_time.text = MyTime
class DetailScreen(Screen):
pass
class SettingsScreen(Screen):
pass
class MyScreenManager(ScreenManager):
pass
root_widget = Builder.load_string('''
MyScreenManager:
MainScreen:
DetailScreen:
SettingsScreen:
<MainScreen>:
name: 'main'
BoxLayout:
orientation: 'vertical'
Label:
id: lbl_time
text: 'Time'
font_size: 60
Label:
text: 'Main2'
font_size: 30
GridLayout:
cols: 2
Label:
text: 'Bottom'
font_size: 30
Label:
text: 'Bottom1'
font_size: 30
<DetailScreen>:
name: 'details'
<SettingsScreen>:
name: 'settings'
''')
class ScreenManagerApp(App):
def build(self):
return root_widget
def on_start(self):
Clock.schedule_interval(MainScreen.update_time, 1)
ScreenManagerApp().run()
This was more of a Python problem rather than a Kivy one. You were calling the update_time of the class MainScreen class, not of the object/instance of the MainScreen. Basically, you would need to save a reference to the object (self.main_screen) in the build method, and then use it in the on_start.
class ScreenManagerApp(App):
def build(self):
self.main_screen = MainScreen()
return self.main_screen
def on_start(self):
Clock.schedule_interval(self.main_screen.update_time, 1)
Also you cannot access id outside of the kv language, i.e. in the python. You have to reference the id by adding a property, e.g. the_time:
<MainScreen>:
name: 'main'
the_time: _id_lbl_time
BoxLayout:
orientation: 'vertical'
Label:
id: _id_lbl_time
A minor problem is that the update_time() receives to parameters. Also, there were quite a few weird things in your code, so I couldn't run the code. I fixed all the above in the code below:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock
import time
from datetime import datetime
Builder.load_string('''
<MainScreen>:
name: 'main'
the_time: _id_lbl_time
BoxLayout:
orientation: 'vertical'
Label:
id: _id_lbl_time
text: 'Time'
font_size: 60
''')
class MainScreen(Screen):
def update_time(self, sec):
MyTime = time.strftime("%H:%M:%S")
self.the_time.text = MyTime
class ScreenManagerApp(App):
def build(self):
self.main_screen = MainScreen()
return self.main_screen
def on_start(self):
Clock.schedule_interval(self.main_screen.update_time, 1)
ScreenManagerApp().run()