well I'm entirely new to kivy, it's a bit complicated but I'm trying to get on
so I'm stuck on something, I'm trying to get a text from a TextInput, but i can't, it just refuse to do it, can anyone crack it?
KV code:
<Signin>:
title:"Telegram Checker"
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
BoxLayout:
width : 600
orientation: 'vertical'
size_hint: None, None
Label:
text:"Telegram Sign-In"
TextInput:
id : tel
input_type:'tel'
width:600
multiline: False
hint_text: '+XXXXXXXXXXXXX'
size_hint: None, None
height: 50
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
padding: 20
spacing: 100
width : 600
orientation: 'vertical'
size_hint: None, None
Button:
text: "Next ->"
#size_hint: 0.5,6
height : 100
pos:self.pos
on_release : app.send_code_request()
the function that's not getting the text :
class MyApp(App):
def build(self):
self.title="Telegram Checker"
return screen_manager
def send_code_request(self):
phone = self.root.ids.tel.text
print(phone)
The code at the bottom is runnable and it passes the argument you requested. It shows this being done two ways. I suggest not using the .ids property because you can link the items at the top of the .kv class and assign type hints to the object like this:
tel: TextInput
full code:
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.lang import Builder
Builder.load_string('''
<Signin>:
# match the python object to the kivy id
# python on the left: kivy id on the right
tel: tel
title:"Telegram Checker"
AnchorLayout:
anchor_x: 'center'
anchor_y: 'center'
BoxLayout:
width : 600
orientation: 'vertical'
size_hint: None, None
Label:
text:"Telegram Sign-In"
TextInput:
id : tel
input_type:'tel'
width:600
multiline: False
hint_text: '+XXXXXXXXXXXXX'
size_hint: None, None
height: 50
AnchorLayout:
anchor_x: 'center'
anchor_y: 'bottom'
BoxLayout:
padding: 20
spacing: 100
width : 600
orientation: 'vertical'
size_hint: None, None
Button:
text: "Next ->"
#size_hint: 0.5,6
height : 100
pos:self.pos
on_release : app.send_code_request(tel.text, self)
'''
)
class Signin(Screen):
# python objects mapped in the .kv file. this is a type hint which will help with auto-complete
tel: TextInput
def __init__(self, **kwargs):
super().__init__(**kwargs)
print(f" hint text is {self.tel.hint_text}")
class MyApp(App):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_top_widget = ScreenManager()
self.signin_screen = Signin(name="sign_in")
def send_code_request(self, phone: str, your_button, *args) -> None:
# this is one way
print(f" by id {self.signin_screen.ids.tel.text}")
print(f"vale passed={phone} \nyour button {your_button} other args {args}")
def build(self):
self.title = "Telegram Checker"
self.my_top_widget.add_widget(self.signin_screen, name="sign_in")
self.my_top_widget.current = "sign_in"
return self.my_top_widget
my_app = MyApp()
my_app.run()
Related
I want to switch from login screen to menu screen based on a successful authentication, but this is the best I could do after a long search on condition-based screen transitions. Most sites say that screen-transitions in kivymd should be done using 'on-release' in .kv file, but I don't think that it would work in my code.
I've marked on the code the problematic line, which is raising the exception.
Teste.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivy.uix.screenmanager import ScreenManager, Screen
class login(Screen):
pass
class menu(Screen):
pass
Builder.load_file('lteste.kv')
class LoginApp(MDApp):
dialog = None
def build(self): #método construtor da parte visual do aplicativo
self.theme_cls.theme_style = "Light"
self.theme_cls.primary_palette = "Indigo"
self.theme_cls.accent_palette = "Blue"
self.sm = ScreenManager()
self.sm.add_widget(login(name="login"))
self.sm.add_widget(menu(name="menu"))
self.sm.current = "menu"
return self.sm
def dialog_box(self):
if not self.dialog:
self.dialog = MDDialog(
title="Log In",
text=f"Welcome {self.root.ids.user.text}!",
buttons=[MDFlatButton(text="Ok", text_color=self.theme_cls.primary_color,
on_release=self.close),],)
return self.dialog.open()
def login(self):
if self.root.ids.user.text=='1' and self.root.ids.password.text=='1':
self.sm.current = "menu" #<- problem
self.dialog_box()
return True
else:
return False
def close(self, instance):
self.dialog.dismiss()
LoginApp().run()
lteste.kv
<login>:
id: login
name: "login"
MDCard:
size_hint: None, None
size: 300, 600
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: 65
spacing: 35
orientation: 'vertical'
MDIcon:
icon: 'account'
icon_color: 0, 0, 0, 0
halign: 'center'
font_size: 180
MDTextFieldRound:
id: user
icon_left: "account-check"
hint_text: "Usuário"
foreground_color: 1, 0, 1, 1
size_hint_x: None
width: 220
font_size: 20
pos_hint: {"center_x": 0.5}
MDTextFieldRound:
id: password
icon_left: "key-variant"
hint_text: "Senha"
foreground_color: 1, 0, 1, 1
size_hint_x: None
height: 1
width: 220
font_size: 20
pos_hint: {"center_x": 0.5}
password: True
MDFillRoundFlatButton:
text: "ENTRAR"
font_size: 15
pos_hint: {"center_x": 0.5}
on_press: app.login()
MDFillRoundFlatButton:
text: "REGISTRAR-SE"
font_size: 15
pos_hint: {"center_x": 0.5}
<menu>
name: "menu"
id: menu
MDCard:
size_hint: None, None
size: 300, 600
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
padding: 65
spacing: 35
orientation: 'vertical'
MDRaisedButton:
text: "Test"
The application root does not contain the ids you want. They are in the login screen widget because you defined them under it in kivy language. It would help to store a reference on the login screen to access them. Replace
self.sm.add_widget(login(name="login"))
with
self.login_screen = login(name="login")
self.sm.add_widget(self.login_screen)
Then, you can access the widgets like so,
text=f"Welcome {self.login_screen.ids.user.text}!",
and
if self.login_screen.ids.user.text=='1' \
and self.login_screen.ids.password.text=='1':
There is an example in the Kivy Documentation on kivy.uix.widget.Widget.ids and also Accessing Widgets defined inside Kv lang in your Python code.
On the first screen, I have a checkbox that asks the user if they want their image in landscape mode. On the second screen, my code currently uses a canvas and rotates the image 90 degrees. If that box is not checked, that means the user wants the image to be portrait mode, and I need that canvas to be cleared.
my.kv
WindowManager:
MainWindow:
SecondWindow:
<MainWindow>:
id: main_window
name: "main"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
Label:
text: "Email"
color: 0,0,0,1
font_size: 32
BoxLayout:
orientation: "horizontal"
Label:
text: "Email Address:"
color: 0,0,0,1
TextInput:
size_hint_y: None
pos_hint: {'center_y': .5}
height: 38
multiline: True
padding: 10
BoxLayout:
orientation: "horizontal"
Label:
text: "Display Landscape Mode?"
color: 0,0,0,1
CheckBox:
id: checkbox_confirm_mode
on_active:
root.checkbox_click_mode(self, self.active)
pos_hint: {'center_x': .5}
BoxLayout:
orientation: "horizontal"
Label:
text: "Stretch image to fill screen?"
color: 0,0,0,1
CheckBox:
id: checkbox_confirm_stretch
on_active:
root.checkbox_click_stretch(self, self.active)
pos_hint: {'center_x': .5}
BoxLayout:
orientation: "horizontal"
Label:
text: "I double-checked that my email is typed correctly:"
color: 0,0,0,1
CheckBox:
id: checkbox_confirm_email
on_active:
root.checkbox_click(self, self.active)
root.disable_button()
pos_hint: {'center_x': .5}
BoxLayout
orientation: "vertical"
Button:
id:submit_button
text: "Submit"
disabled: True
size_hint: (0.2, None)
pos_hint: {'center_x': .5}
height: 50
on_release:
app.root.current = "second"
root.manager.transition.direction = "left"
<SecondWindow>:
id: second_window
name: "second"
canvas:
Rotate:
angle: 90
origin: self.center
Image:
source: 'Troy.png'
keep_ratio: True
allow_stretch: False
main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.config import Config
Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
class MainWindow(Screen):
def on_pre_enter(self):
Window.size = (750,400)
Window.clearcolor = (1, 1, 1, 1)
def checkbox_click(self, instance, value):
return value
def checkbox_click_mode(self, instance, value):
return value
def checkbox_click_stretch(self, instance, value):
return value
def clear_canvas(self):
self.canvas.clear()
return
def disable_button(self):
if self.ids.checkbox_confirm_email.active == False:
self.ids.submit_button.disabled = True
else:
self.ids.submit_button.disabled = False
class SecondWindow(Screen):
def on_pre_enter(self):
Window.size = (500,500)
Window.clearcolor = (0,0,0,0)
pass
class WindowManager(ScreenManager):
pass
class MyMainApp(App):
def build(self):
return kv
kv = Builder.load_file("my.kv")
if __name__ == "__main__":
MyMainApp().run()
For your current design you can control it from outside as,
First set properties in SecondWindow for setting the angle, stretch instruction etc. and then control them depending on the state of those (weak reference of the check boxes) checkbox_confirm_mode etc. from the MainWindow as,
class SecondWindow(Screen):
angle = NumericProperty(0)
allow_strech = BooleanProperty(False)
def on_pre_enter(self):
screen = self.manager.get_screen("main")
angle_value = screen.ids.checkbox_confirm_mode.active
stretch_value = screen.ids.checkbox_confirm_stretch.active
self.angle = 90*angle_value # Less calculation.
self.allow_strech = stretch_value # Less calculation.
Window.size = (500,500)
...
Now in the kvlang of SecondWindow,
<SecondWindow>:
id: second_window
name: "second"
canvas:
Rotate:
angle: root.angle
origin: self.center
Image:
source: 'Troy.png'
keep_ratio: True
allow_stretch: root.allow_strech
I want to catch a value from my first screen into my thirdscreen.
In the first, I write my name in an input field.
I go to the next window.
And I try to show my name in this last window.
So I share the code with you and I hope I will find an issue.
Python code :
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
#define ou different screens
class FirstWindow(Screen):
def envoyer(self):
name = self.ids.nom_input.text
self.ids.my_name.text = name
class SecondWindow(Screen):
pass
class ThirdWindow(Screen):
#PROBLEM HERE
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
class WindowManager(ScreenManager):
pass
class MonWidget(Widget):
pass
kv = Builder.load_file('new_window.kv')
class AwesomeApp(App):
def build(self):
Window.clearcolor = (0,0,0,0)
return kv
if __name__ == '__main__':
AwesomeApp().run()
My KV CODE :
WindowManager:
FirstWindow:
SecondWindow:
ThirdWindow:
<FirstWindow>:
name: "romain"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
id: my_name
text: "Entrez votre nom"
font_size: 32
TextInput:
id: nom_input
multiline: False
size_hint: (1, .5)
Button:
text: "Next screen"
font_size: 32
on_press: root.envoyer()
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "Mickael"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Entre votre ville"
font_size: 32
TextInput:
id: ville_input
multiline: False
size_hint: (1, .5)
Button:
text: "Vérifier les infos"
font_size: 32
on_release:
app.root.current = "foncier"
root.manager.transition.direction = "left"
Button:
text: "go back first screen"
font_size: 32
on_release:
app.root.current = "romain"
root.manager.transition.direction = "right"
<ThirdWindow>:
name: "foncier"
BoxLayout:
orientation: "vertical"
size: root.width, root.height
Label:
text: "Verifier : "
font_size: 32
Label:
id: recup_infos
text: ""
font_size: 32
color: 'white'
Button:
text: "On press"
font_size: 32
#Problem HERE
on_press: root.on_press()
Button:
text: "Précedent"
font_size: 32
on_release:
app.root.current = "Mickael"
root.manager.transition.direction = "right"
Could you help me ?
Thank you
Romain
In your on_press method:
def on_press(self):
self.ids.recup_infos.text = self.root.get_screen('FirstWindow').ids.my_name.text
self.root.get_screen('FirstWindow').ids.my_name.text isn't the correct way to get access to widgets outside of the class that you are in right now, or in this situation, screen. The correct way is to use the App.get_running_app() method:
self.ids.recup_infos.text = App.get_running_app().root.ids.First.ids.my_name.text
But before doing that, you have to give ids to the screens of your app, so that the First argument of the method demonstrated above actually makes sense:
WindowManager:
FirstWindow:
id: First
# "First" is the id of the FirstWindow class
# which can also explain why there was a "First" arg
# inside "App.get_running_app().root.ids.First.ids.my_name.text"
SecondWindow:
id: Second
ThirdWindow:
id: Third
Still confused to why this works? Let's divide the attributes of App.get_running_app().root.ids.First.ids.my_name.text into 3 parts:
App.get_running_app(): this method returns the location of your running App class, in this case AwesomeApp. This also acts as self if you were to get the variable inside the App object itself
.root.ids.First: if you read the Kivy documentation, or just simply watched Kivy course videos online, carefully, you should know that self.root.ids inside the App object returns a list of ids of the widgets inside your root widget. In this case, App.get_running_app().root.ids is doing the same thing here, and your screens are passed in the ScreenManager root widget, hence make First an available attribute in App.get_running_app().root.ids
.ids.my_name.text: same as above, App.get_running_app().root.ids.First acts the same as self if you were to run it in your FirstWindow class, which gives you the opportunity to get access to variables outside of your working classes/screens
I am trying to type in text from one screen. Press a button and move to another screen and have that text be shown in a label. I've seen a few questions that are similar to mine, but have not been able to figure out how to use the posted solutions and have been stuck for hours (Link One, Link Two, Link Three). I believe that I need to use the __init__ method somewhere because this is an instance? I tried using the first link, but the label ends up blank (the code does run). Any Advice?
main.py
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.app import App
from kivy.lang.builder import Builder
class SecondWindow(Screen):
def get_unique_text(self):
x = self.manager.get_screen("first")
y = x.ids.unique.text
return str(y)
class FirstWindow(Screen):
pass
class MainWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
kv_main = Builder.load_file('main.kv')
class MyApp(App):
def build(self):
return kv_main
if __name__ == '__main__':
MyApp().run()
main.kv
#:include First.kv
#:include Second.kv
WindowManager:
MainWindow:
FirstWindow:
SecondWindow:
<MainWindow>
name: "main"
BoxLayout:
Button:
text: "Press"
on_release:
app.root.current = "first"
First.kv
<FirstWindow#Screen>:
name: "first"
BoxLayout:
orientation: "vertical"
Label:
text: "Enter Unique Text for Saving"
font_size: 20
text_size: self.width, None
halign: 'center'
TextInput:
id: unique
hint_text: 'example: Stand25'
Button:
text: "Press"
on_release:
app.root.current = "second"
Second.kv
<SecondWindow#Screen>:
name: "second"
BoxLayout:
orientation: "vertical"
Label:
text: "Unique Text"
font_size: 20
text_size: self.width, None
halign: 'center'
Label:
text: root.get_unique_text()
font_size: 16
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
Button:
text: "Go Back"
on_release:
app.root.current = "first"
Another approach is to use the on_enter() method of a Screen in order to fetch the text. This also requires an id for the unique Label:
<SecondWindow#Screen>:
name: "second"
BoxLayout:
orientation: "vertical"
Label:
text: "Unique Text"
font_size: 20
text_size: self.width, None
halign: 'center'
Label:
id: unique # added id
# text: root.get_unique_text()
font_size: 16
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
Button:
text: "Go Back"
on_release:
app.root.current = "first"
Just add an on_enter() method to the SecondWindow class:
class SecondWindow(Screen):
def on_enter(self, *args):
self.ids.unique.text = self.get_unique_text()
def get_unique_text(self):
x = self.manager.get_screen("first")
y = x.ids.unique.text
return str(y)
In your Second.kv you can reference the text of the TextInput in the First.kv by making a couple changes to the kv files. First, in the main.kv, add an id for the FirstWindow (and eliminate the SecondWindow for now):
WindowManager:
MainWindow:
FirstWindow:
id: first # added id
# SecondWindow: # this gets added later
<MainWindow>
name: "main"
BoxLayout:
Button:
text: "Press"
on_release:
app.root.current = "first"
Then, in the Second.kv, set up the reference to the text of the TextInput:
<SecondWindow#Screen>:
name: "second"
BoxLayout:
orientation: "vertical"
Label:
text: "Unique Text"
font_size: 20
text_size: self.width, None
halign: 'center'
Label:
text: app.root.ids.first.ids.unique.text # reference to unique text
font_size: 16
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.pos
size: self.size
color: 0,0,0,1
Button:
text: "Go Back"
on_release:
app.root.current = "first"
Since the kv for SecondWindow uses app.root, it will cause an error if SecondWindow is instantiated before the root widget of the App is assigned. To avoid that, add the SecondWindow after a slight delay:
class MyApp(App):
def build(self):
Clock.schedule_once(self.add_second_screen)
return kv_main
def add_second_screen(self, dt):
self.root.add_widget(SecondWindow())
I am having trouble taking a text input value from one screen and passing it as the text in a label in another screen. I want to take the text input from a TeamNameSelect screen and have those be the text values in the labels of a GameWindow screen. I've tried going through similar questions and answers on here but have been unable to get this to work. Any help would be greatly appreciated!
.py file
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.widget import Widget
class NewGame(Screen):
pass
class GameWindow(Screen):
def teamNames(self, *args):
self.teamOne_input.text = self.manager.ids.TeamNameSelect.ids.teamOne.text
self.teamTwo_input.text = self.manager.ids.TeamNameSelect.ids.teamTwo.text
pass
class TeamNameSelect(Screen):
pass
class WinMan(ScreenManager):
pass
kv = Builder.load_file("my.kv")
sm = WinMan()
screens = [NewGame(name='goBack'), TeamNameSelect(name='teamSelect'), GameWindow(name='startGame')]
for screen in screens:
sm.add_widget(screen)
sm.current = 'goBack'
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
.kv file
<TeamNameSelect>:
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
padding: 10
Label:
text: 'Team 1 Name: '
TextInput:
id: teamOne
text: ''
multiline: False
BoxLayout:
orientation: 'vertical'
padding: 10
Label:
text: 'Team 2 Name: '
TextInput:
id: teamTwo
text: ''
multiline: False
BoxLayout:
Button:
text: 'Go Back'
on_release: root.manager.current = 'goBack'
Button:
text: 'Game On!'
on_release:
root.manager.current = 'gameWindow'
root.teamNames()
<GameWindow>:
teamOne_input: teamOne_input
teamTwo_input: teamTwo_input
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
size_hint: (1, 0.1)
Button:
text: '. . .'
on_release: root.manager.current = 'goBack'
Label:
font_size: 33
text: 'Team'
Label:
font_size: 33
id: teamOne_input
text: ''
Label:
font_size: 33
text: 'Team'
Label:
font_size: 33
id: teamTwo_input
text: ''
BoxLayout:
orientation: 'horizontal'
size_hint: (0.75,1)
Label:
font_size: 33
text: '' # Instructions on how to play game
Label:
font_size: 39
text: '' # Future playing area to develop
You have 2 preliminary errors:
There is no Screen with name "gameWindow" so I suppose the OP wanted to write "startGame".
The root in on_release is the "TeamNameSelect" that clearly has nothing that does not have the teamNames() method.
On the other hand the "manager" is not implemented in the .kv so it cannot have any "id", the solution is to access the screen with name "teamSelect" using the get_screen() method.
Considering the above, the solution is:
class GameWindow(Screen):
def teamNames(self):
select_screen = self.manager.get_screen("teamSelect")
self.teamOne_input.text = select_screen.ids.teamOne.text
self.teamTwo_input.text = select_screen.ids.teamTwo.text
Button:
text: 'Game On!'
on_release:
root.manager.current = 'startGame'
root.manager.current_screen.teamNames()