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()
Related
I have a dropdown menu in which I would like to know which value the user has selected so I can use it later in my program. This is my .kv code:
BoxLayout:
orientation: 'horizontal'
size_hint_x: 1
Button:
pos_hint:{'center_x': .5, 'center_y': .5}
id: units_num_btn
text: '0'
size_hint_y: None
height: 44
on_parent: drop_player_numbers_units.dismiss()
on_release: drop_player_numbers_units.open(self)
DropDown:
id: drop_player_numbers_units
on_select: units_num_btn.text = '{}'.format(args[1])
on_select: app.return_player_numbers()
Button:
id: units_num_btn_1
text: '1'
size_hint_y: None
height: 35
on_release: drop_player_numbers_units.select('1')
Button:
id: units_num_btn_2
text: '2'
size_hint_y: None
height: 35
on_release: drop_player_numbers_units.select('2')
and so on.
My .py code is here:
class drop_content(DropDown):
pass
class PlayerScreen(Screen):
pass
class TheApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(PlayerScreen(name='player_setup'))
sm.current = 'player_setup'
return sm
def main():
Builder.load_file('menu.kv')
app = TheApp()
app.run()
if __name__ == '__main__':
main()
I have previously used a function such as this:
# .py example
def return_text(self):
text = self.root.get_screen('screen').ids.specific_id.text
print(text)
# .kv example
TextInput:
id: input
text: "2"
on_text: app.return_text()
which did return text using a Textinput type in my .kv file. I know it doesn't work for the dropdown menu since the text is not inputted in the same way. Do you know how I would do this?
Thanks in advance
from kivy.app import App
from kivy.uix.dropdown import DropDown
from kivy.uix.screenmanager import Screen,ScreenManager
from kivy.lang.builder import Builder
class TestScreen(Screen):
def return_player_numbers(self,play_number):
print('Test : ',play_number)
kv = '''
ScreenManager:
TestScreen:
<TestScreen>:
BoxLayout:
orientation: 'horizontal'
size_hint_x: 1
Button:
pos_hint:{'center_x': .5, 'center_y': .5}
id: units_num_btn
text: '0'
size_hint_y: None
height: 44
on_parent: drop_player_numbers_units.dismiss()
on_release: drop_player_numbers_units.open(self)
DropDown:
id: drop_player_numbers_units
on_select:
units_num_btn.text = '{}'.format(args[1])
app.root.current_screen.return_player_numbers(args[1])
app.return_player_numbers(args[1])
Button:
id: units_num_btn_1
text: '1'
size_hint_y: None
height: 35
on_release: drop_player_numbers_units.select('1')
Button:
id: units_num_btn_2
text: '2'
size_hint_y: None
height: 35
on_release: drop_player_numbers_units.select('2')
'''
class TheApp(App):
def return_player_numbers(self,play_number):
print('App : ',play_number)
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
TheApp().run()
I have found a way that I think is simpler than the current answer provided. This method uses that fact that the text on the button used to initiate the drop down changes as another button is selected. This is to show the user what they have selected. Since I want to know the text the user has selected from the drop down menu, and this is in fact the same thing that is updated on the initial button, I can just read the text from the button to obtatin my result like so:
(in .kv file)
<player_setup>
BoxLayout:
orientation: 'horizontal'
size_hint_x: 0.2
pos_hint: {'x':.4, 'y':0}
Button:
pos_hint:{'center_x': .5, 'center_y': .5}
id: tens_num_btn
text: '0'
size_hint_y: None
# size_hint_x: 0.1
height: 44
on_parent: drop_player_numbers_tens.dismiss()
on_release: drop_player_numbers_tens.open(self)
DropDown:
id: drop_player_numbers_tens
on_select:
#######
tens_num_btn.text = '{}'.format(args[1])
# this line here ^ is the one that re-formats the text of the button above to
# the selected text
app.return_player_numbers()
max_height: 120
(.py file)
def return_player_numbers(self):
player_number = self.root.get_screen('player_setup').ids.tens_num_btn.text
return player_number
This also allows me to concatenate multiple dropdown results using a single function, however it is menu specific. In my case, this works better for me
I am trying to add an action bar on top in the first screen of my project. I tried using screenmanager widget and sending the action bar as it's children like how to manage/get both of the screens. At first I tried just adding the action bar code in root.widget in the first screen, but they are showing the class for this as an invalid class.
How to add both of them? Also I can't show the buttons from top to bottom even though I added orientation : 'vertical'
import kivy
kivy.require('1.10.1')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager,Screen,FadeTransition
class SomeLayout_GridLayout(Screen):
pass
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
root_widget = Builder.load_string('''
ScreenManager:
FirstScreen:
SecondScreen:
SomeLayout_GridLayout:
<FirstScreen>:
name: 'first'
<SomeLayout_GridLayout>:
cols: 1
rows: 2
row_force_default: True
rows_minimum: {0: ActionBar.height, 1: self.height - ActionBar.height}
SomeMenu_ActionBar:
id: ActionBar
<SomeMenu_ActionBar#ActionBar>:
ActionView:
id: ActionView
ActionGroup:
id: App_ActionGroup
mode: 'spinner'
text: 'App'
ActionButton:
text: 'Settings'
on_press: app.open_settings()
ActionButton:
text: 'Quit'
on_press: app.get_running_app().stop()
ActionGroup:
id: File_ActionGroup
mode: 'spinner'
text: 'File'
ActionButton:
text: 'Open'
ActionButton:
text: 'Save'
<HiddenIcon_ActionPrevious#ActionPrevious>:
title: app.title if app.title is not None else 'Action Previous'
with_previous: False
app_icon: ''
app_icon_width: 0
app_icon_height: 0
size_hint_x: None
width: len(self.title) * 10
<HiddenText_ActionPrevious#ActionPrevious>: #
with_previous: False
on_press: print(self)
title: ''
<Hidden_ActionPrevious#ActionPrevious>:
with_previous: False
on_press: print(self)
title: ''
size_hint: None, None
size: 0, 0
BoxLayout:
orientation: 'horizontal'
BoxLayout:
Button:
text: 'Crime Prediction'
font_size: 30
on_release: app.root.current = 'second'
Button:
text: 'Forum'
font_size: 30
on_release: app.root.current = 'second'
Button:
text: 'Probable Suspect'
font_size: 30
on_release: app.root.current = 'second'
<SecondScreen>:
name: 'second'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Predict Crime Nigga!'
font_size: 50
BoxLayout:`enter code here`
Button:
text: 'Back to Main Menu'
font_size: 30
on_release: app.root.current = 'first'
Button:
text: 'get random colour screen'
font_size: 30
on_release: app.root.current = 'first'
''')
class ScreenManagerApp(App):
def build(self):
return root_widget
ScreenManagerApp().run()
Kivy App with ActionBar & ScreenManager
Declare a root widget with inheritance of BoxLayout
Add ActionBar as child of root widget
Add ScreenManager as child of root widget, and with id: sm
Snippets
BoxLayout:
orientation: 'vertical'
ActionBar:
...
ScreenManager:
id: sm
FirstScreen:
SecondScreen:
Example
main.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
class WelcomeScreen(Screen):
pass
class FirstScreen(Screen):
pass
class SecondScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
class CrimePrevention(BoxLayout):
pass
Builder.load_file("main.kv")
class TestApp(App):
title = 'Kivy ScreenManager & ActionBar Demo'
def build(self):
return CrimePrevention()
if __name__ == '__main__':
TestApp().run()
main.kv
#:kivy 1.11.0
#:import sp kivy.metrics.sp
#:import dp kivy.metrics.dp
<CrimePrevention>:
orientation: 'vertical'
canvas.before:
Color:
rgb: .6, .6, .6
Rectangle:
pos: self.pos
size: self.size
# source: 'data/background.png'
SomeMenu_ActionBar:
id: ActionBar
ScreenManager:
id: sm
WelcomeScreen:
FirstScreen:
SecondScreen:
<SomeMenu_ActionBar#ActionBar>:
ActionView:
id: ActionView
HiddenIcon_ActionPrevious:
ActionGroup:
id: App_ActionGroup
mode: 'spinner'
text: 'Jump to Screen'
ActionButton:
text: 'Crime Prediction'
on_release: app.root.ids.sm.current = 'second'
ActionButton:
text: 'Forum'
on_release: app.root.ids.sm.current = 'second'
ActionButton:
text: 'Probable Suspect'
on_release: app.root.ids.sm.current = 'second'
ActionGroup:
id: App_ActionGroup
mode: 'spinner'
text: 'App'
ActionButton:
text: 'Settings'
on_press: app.open_settings()
ActionButton:
text: 'Quit'
on_press: app.get_running_app().stop()
ActionGroup:
id: File_ActionGroup
mode: 'spinner'
text: 'File'
ActionButton:
text: 'Open'
ActionButton:
text: 'Save'
<HiddenIcon_ActionPrevious#ActionPrevious>:
title: '' # app.title if app.title is not None else 'Action Previous'
with_previous: False
app_icon: ''
app_icon_width: 0
app_icon_height: 0
size_hint_x: None
width: len(self.title) * 10
<WelcomeScreen>:
name: 'welcome'
Label:
text: 'Welcome Screen'
font_size: sp(50)
<FirstScreen>:
name: 'first'
Label:
text: 'First Screen'
<SecondScreen>:
name: 'second'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Predict Crime'
font_size: 50
BoxLayout:
Button:
text: 'Back to Main Menu'
font_size: 30
on_release: app.root.ids.sm.current = 'first'
Button:
text: 'get random colour screen'
font_size: 30
on_release: app.root.ids.sm.current = 'first'
Output
Pop up and EXE issue
Hi guys I've got problem, whenever I open my Kivy Program via Python, a popup is actually showing up
But when I convert it via Pyinstaller, it gives me an error:
How can I possibly fix this?
Python Code:
import os
os.environ["KIVY_IMAGE"] = "pil, sdl2"
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
Builder.load_file("kivy.kv")
class Rusure(Popup):
pass
class Menu(Screen):
def quit(self):
Rusure().open()
class Settings(Screen):
def bright (self,*args):
self.brightness.text = "Brightness: {}".format(str(int(args[1])))
class Play(Screen):
pass
class Sm(ScreenManager):
def __init__(self):
super().__init__()
self.add_widget(Menu(name="menu"))
self.add_widget(Settings(name="settings"))
self.add_widget(Play(name="play"))
class GoodApp(App):
def build(self):
return Sm()
GoodApp().run()
Kivy Code:
#: import rit kivy.uix.screenmanager.RiseInTransition
#: import st kivy.uix.screenmanager.SlideTransition
#: import fot kivy.uix.screenmanager.FallOutTransition
#: import Factory kivy.factory.Factory
<Menu>:
BoxLayout:
padding: 100,100,100,100
orientation: "vertical"
Label:
text: "Menu"
BoxLayout:
orientation: "horizontal"
Button:
text: "Play"
background_normal: "Image.jpg"
background_down: "ImageRel.jpg"
color: 1,1,1,1
on_press:
root.manager.transition = rit()
root.manager.current = "play"
Button:
text: "Settings"
background_color: 0.9,1,1,1
on_press:
root.manager.transition = st()
root.manager.current = "settings"
root.manager.transition.direction = "up"
Button:
text: "Quit"
background_color: 1,0.7,0,1
on_press:
root.quit()
<Settings>:
brightness: brght
BoxLayout:
padding: 100,100,100,100
orientation: "vertical"
Label:
text: "Settings"
GridLayout:
cols: 3
Label:
text: "Brightness"
Slider:
min: 0
max: 10
value: 5
on_value: root.bright(*args)
Label:
id: brght
text: "Change Value"
Button:
text: "Back"
on_press:
root.manager.transition = st()
root.manager.current = "menu"
root.manager.transition.direction = "down"
<Play>:
BoxLayout:
Label:
text: "Welcome to the game!"
Button:
text: "Back"
on_press:
root.manager.transition = fot()
root.manager.current = "menu"
<Rusure>:
title: "Are you sure?"
size_hint: 0.5,0.5
auto_dismiss: False
BoxLayout:
orientation: "vertical"
Label:
text: "Your progress will be lost"
GridLayout:
cols: 2
Button:
text: "Oh shit man!"
on_press: root.dismiss()
Button:
text: "Cancel"
on_press: root.dismiss()
I tried searching solution on the internet, but after 3 hours of searching I couldn't come up whith any answer.
I'm writing a kivy program/game. I've made one before, but was only 1 screen in total. I've started developing a new program with ideas of implementing a Screen Manager. I managed to build the Screen Manager inside of the python file, but it wasn't suitable for my long term usage, and I wanted to try my hand at a Screen Manager from the .kv file.
Any guidance will be greatly appreciated, not sure what I missed. I looked at this questionv(Kivy - Screen Manager - Accessing attribute in other class), and pieced together what I thought was right, but still can't get a screen to load - I feel this is a simple answer and I'm being blind...
main.py;
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MenuScreen(Screen):
pass
class NewGameScreen(Screen):
pass
class LoadGameScreen(Screen):
pass
class ASCIILifeApp(App):
pass
if __name__ == "__main__":
ASCIILifeApp().run()
ASCIILife.kv;
#: kivy 1.9
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#: import NewGameScreen screen
#: import LoadGameScreen screen
ScreenManager:
id: screen_manager
#transition: FadeTransition()
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: 'screen_manager'
NewGameScreen:
id: newgame_screen
name: 'NewGameScreen'
manager: 'screen_manager'
LoadGameScreen:
id: loadgame_screen
name: 'LoadGameScreen'
manager: 'screen_manager'
<MenuScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'ASCII Life'
font_size: 50
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'newgame'
Button:
text: 'Load Game'
font_size: 30
on_release: app.root.current = 'loadgame'
Button:
text: 'Settings'
font_size: 30
on_release: app.root.current = 'something'
<NewGameScreen>:
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'vertical'
Label:
text: 'Game Length in Days'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: '100'
state: 'down'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: '200'
group: 'newgame_days'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: '365'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: '3650'
group: 'newgame_days'
font_size: 30
ToggleButton:
text: 'Unlimited'
group: 'newgame_days'
font_size: 30
BoxLayout:
orientation: 'vertical'
size_hint: (1, .5)
Label:
text: 'Difficulty (Score Multiplier)'
font_size: 30
BoxLayout:
orientation: 'horizontal'
ToggleButton:
text: 'Easy (x1)'
state: 'down'
group: 'newgame_difficulty'
font_size: 30
ToggleButton:
text: 'Medium (x2.5)'
group: 'newgame_difficulty'
font_size: 30
ToggleButton:
text: 'Hard (x5)'
group: 'newgame_difficulty'
font_size: 30
<LoadGameScreen>:
BoxLayout:
orientation: 'vertical'
Label:
text: 'load a game'
font_size: 30
Widget:
canvas:
Ellipse:
pos: self.pos
size: self.size
BoxLayout:
Button:
text: 'Menu'
font_size: 30
on_release: app.root.current = 'menu'
Button:
text: 'text'
font_size: 30
Edit: Truncated kv file
The answer was using a builder to build the kv file. Knew it was something simple. File below;
main.py
#!/usr/bin/kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.properties import ObjectProperty
class MenuScreen(Screen):
pass
class NewGameScreen(Screen):
pass
class LoadGameScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
buildKV = Builder.load_file("ASCIILife.kv")
class ASCIILifeApp(App):
def build(self):
return buildKV
if __name__ == "__main__":
ASCIILifeApp().run()
To elaborate on Chazara's findings:
Either rename the kv code file according to the naming convension:
Kivy looks for a Kv file with the same name as your App class in
lowercase, minus “App” if it ends with ‘App’.
From the documentation:how to load kv language
Or just make it explicit with the builder function:
Builder.load_file('path/to/file.kv')
To elaborate on Chazara's findings even more:
i tested the code from Chazara with kivy 1.10.1dev0 and Python 3.6; i got an error saying:
kivy.uix.screenmanager.ScreenManagerException: No Screen with name "something".
to fix it, i changed in the .kv file
[...]
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'newgame'
[...]
to:
[...]
Button:
text: 'New Game'
font_size: 30
on_release: app.root.current = 'NewGameScreen'
[...]
it references the name of NewGameScreen given in the ScreenManager
ScreenManager:
[...]
NewGameScreen:
id: newgame_screen
*name: 'NewGameScreen'*
manager: 'screen_manager'
I have a basic app in Kivy with a class for each screen. I would like to have the user enter some text in one screen and for this to be displayed in a label on another screen.
I've been through all the similar posts but can't seem to get anything working.
The two classes EnterSentences and Review have ObjectProperties. Is there a way to connect these with bind? Or do I need to just structure things completely differently?
Any help much appreciated. Here's the .py file
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
class MainMenu(BoxLayout):
def enter_sentences_button(self):
self.clear_widgets()
self.add_widget(EnterSentences())
def review_button(self):
self.clear_widgets()
self.add_widget(Review())
def settings_button(self):
pass
class EnterSentences(BoxLayout):
search_box = ObjectProperty()
def main_menu(self):
self.clear_widgets()
self.add_widget(MainMenu())
class Review(BoxLayout):
sentence = ObjectProperty()
class NewApp(App):
pass
if __name__ == "__main__":
NewApp().run()
and the .kv file:
MainMenu
<MainMenu>:
orientation: 'vertical'
Label:
text: "Welcome to your Flash Card App!"
size_hint_y: 5
BoxLayout:
size_hint_y: 1
orientation: "horizontal"
Button:
text: "Enter sentences"
on_press: root.enter_sentences_button()
Button:
text: "Review"
on_press: root.review_button()
Button:
text: "Settings"
<EnterSentences>:
search_box: enter_sentence
orientation: "vertical"
Label:
text: "Enter your sentences here:"
size_hint_y: 4
TextInput:
id: enter_sentence
TextInput:
TextInput:
BoxLayout:
orientation: 'horizontal'
Button:
text: 'Main Menu'
on_press: root.main_menu()
Label:
text: ''
<Review>:
orientation: 'vertical'
Label:
size_hint_y: 4
text: root.search_box
TextInput:
size_hint_y: 1
You only have to change the kv file. You could add the text from the 3 TextInputs to 3 variables readable from the whole app:
TextInput:
+ on_text: app.sentence1=self.text
id: enter_sentence
TextInput:
+ on_text: app.sentence2=self.text
TextInput:
+ on_text: app.sentence3=self.text
Then you could access the new variables in the Review:
<Review>:
orientation: 'vertical'
Label:
size_hint_y: 4
text: app.sentence1 + "\n" + app.sentence2 + "\n" + app.sentence3
TextInput:
size_hint_y: 1