Python Kivy Dyanmic Class not defined - python

I keep getting a Name Error reporting "name TripButton is not defined" although I have a button called TripButton defined in the same .kv file.
#:kivy 1.11.1
<TripButton#Button>:
size_hint: (0.15,0.15)
pos_hint: {'y':0.84}
text:"Test Text"
<MyPopup>:
size_hint: 0.5, 0.5
auto_dismiss: False
title: 'New Trip'
BoxLayout:
orientation: 'vertical'
TextInput:
id: trip_name
multiline: False
BoxLayout:
size_hint_y: None
height: 30
Button:
text: 'Submit'
on_release:
root.parent.parent.add_widget(TripButton(text=trip_name.text, size_hint=(1,0.1)))
root.dismiss()
Button:
text: 'Cancel'
on_release: root.dismiss()
<FirstScreen>:
name: 'first'
FloatLayout:
BoxLayout:
size_hint: (0.95, 0.95)
pos_hint: {'center_x':0.5, 'center_y':0.5}
orientation: "vertical"
canvas.before:
Color:
rgba: (1, 0, 0, 1) # Red color
Rectangle:
pos: self.pos
size: self.size
BoxLayout:
TripButton:
Button:
text: 'Add Trip'
font_size: 12
size_hint: (0.1, 0.1)
pos_hint: {'right':1, 'bottom':1}
on_release: app.open_popup()
pos_hint: {'right':1, 'bottom':1}
on_release: app.open_popup()
I tried declaring the TripButton class above and below the MyPopup class and that didn't work. I compared my code with the kivy documentation for dynamic classes and the from what I can tell I'm matching the syntax. I tried importing the Button class in both the python file and the .kv file and that hasn't worked.
To clarify all of this is in the same .kv file in the same directory as the python file. the app runs until I click the submit button in MyPopup then the program crashes and I get the NameError. This is what I have in my python file.
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
class FirstScreen(Screen):
pass
class MyPopup(Popup):
pass
class MyApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(FirstScreen(name='first'))
sm.current = 'first'
return sm
def open_popup(self):
p = MyPopup()
p.open()
def add_button(self):
pass
if __name__ == '__main__':
MyApp().run()
What am I doing wrong? What else I can try? Thanks for your time.

To access classes defined within kv file use kivy.factory.Factory
Add id attribute to your button's BoxLayout, so replace following part of kv file:
BoxLayout:
TripButton:
with
BoxLayout:
id: trip_buttons
TripButton:
then replace:
root.parent.parent.add_widget(TripButton(text=trip_name.text, size_hint=(1,0.1)))
with:
app.root.current_screen.ids.trip_buttons.add_widget(kivy.factory.Factory.TripButton(text=trip_name.text, size_hint=(1,0.1)))
You also duplicated following lines within last button definition on first screen. Replace:
pos_hint: {'right':1, 'bottom':1}
on_release: app.open_popup()
pos_hint: {'right':1, 'bottom':1}
on_release: app.open_popup()
with
pos_hint: {'right':1, 'bottom':1}
on_release: app.open_popup()

Related

I can't read the value of text input in Kivy

My problem is when I want to display the value given by the user in the Text input text field.
When I want to get the text value from the input I get an empty value and I cannot display anything in the label field .
Here is my code :
The kv file :
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
text: root.text_input_1
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
Label:
text: root.Display_text
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()
The py file :
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
# different layouts:
class MainGridLayout(GridLayout):
text_input_1 = StringProperty()
Display_text = StringProperty()
def on_button_plus(self):
print(f'{self.text_input_1}')
# run application:
class CalculatorApp(App):
pass
CalculatorApp().run()
I have created a function in MainGridLayout, on_new_text, that takes as a parameter a TextInput and updates text_input_1 with its value.
In the kv file I have set the on_text property of the TextInput to the on_new_text function and gave the TextInput as a parameter. Every time you modify the text input, the on_new_text function will be called, modifying the text_input_1 property.
You can find more properties like on_text in the kivy documentation.
The kv file:
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
on_text: root.on_new_text(self)
Label:
text: root.Display_text
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()
The py file:
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
# different layouts:
class MainGridLayout(GridLayout):
text_input_1 = StringProperty()
Display_text = StringProperty()
def on_new_text(self, text_input):
self.text_input_1 = text_input.text
def on_button_plus(self):
print(f'{self.text_input_1}')
class CalculatorApp(App):
pass
CalculatorApp().run()
Actually, you don't need the variables text_input_1 and Display_text. To display the text from the my_text_input on the label you can add text: my_text_input.text instead of text: root.Display_text. Now, when the text of my_text_input changes, the label's text will change automatically and you don't need any functions. In on_button_plus() method you can do the same and print my_text_input's text using its text property (from all MainGridLayout's ids you take only my_text_input and print its text). The line text: root.text_input_1 unnecessary, too.
Here is my editted version of your code:
The .py file
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.gridlayout import GridLayout
class MainGridLayout(GridLayout):
def on_button_plus(self):
print(f'{self.ids.my_text_input.text}')
class CalculatorApp(App):
pass
CalculatorApp().run()
The .kv file
MainGridLayout:
<MainGridLayout>:
cols: 1
rows: 2
BoxLayout:
orientation: 'vertical'
TextInput:
id: my_text_input
hint_text :'Operations'
multiline:False
pos_hint: {'center_x': 0.5, 'center_y': 0.705}
size_hint: 0.95, 0.5
font_size: '30dp'
Label:
text: my_text_input.text # change the text automatically
font_size: '45dp'
StackLayout:
Button:
text:"+"
spacing: .2, .2
size: 85, 85
size_hint: None, None
on_press: root.on_button_plus()

Kivy - Get InputText From Other Screen

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())

Using KIVY Popup I have NameError

Last time I solved the error thanks to you.
However, due to my lack of skills,
I looked up a lot of data but couldn't solve the error.
If I click information Button happen this error message.
File "", line 27, in
NameError: name 'Factory' is not defined
I want to make Project. This Picture. But The Button location always not good.
This is My Python KIVY code
#project.kv file
kv = '''
BoxLayout:
orientation: 'vertical'
Upper_bar:
size_hint: (1, 0.1)
Label:
text: 'Select Mode'
BoxLayout:
padding: [90, 40]
size_hint: (1, 0.5)
orientation: 'horizontal'
Button:
size_hint: (0.5, 1)
text: 'Object'
BoxLayout:
Button:
size_hint: (0.5, 1)
text: 'Street'
<Upper_bar>:
BoxLayout:
Button:
size_hint: (0.3, 1)
text: 'Information'
on_press: Factory.InformationPop().open()
<InformationPop#Popup>:
size_hint: 0.5, 0.5
tittle: 'Information'
auto_dismiss: True
BoxLayout:
orientation: 'vertical'
Label:
text:
"""Name:
Student Number:
E-mail: """
Button:
text:
'Close'
on_press:
root.dismiss()
size_hint_y: None
height: '40dp'
'''
class Upper_bar(BoxLayout):
pass
class AIObjectCameraApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
AIObjectCameraApp().run()
You just forgot to add the import of Factory at the top of your kv string:
#:import Factory kivy.factory.Factory

Passing a text input between screens in Kivy

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()

Kivy select screen in .py-file and use in .kv-file

I'm trying to make a list of screens and randomly select one of them in this python file (other code is not included here, like builder etc):
class selectionScreen
testScreen = StringProperty('Screen1')
def screenSelector(self)
screenList = ['Screen1', 'Screen2']
testNumber = random.randint(0, 1)
testScreen = screenList[testNumber]
return testscreen
I then want to choose this screen in my .kv-file, which looks somewhat like this, but also includes screen 1 and 2
ScreenManager:
SelectionScreen:
name: 'SelectionScreen'
Screen0:
name: 'Screen0'
Screen1:
name: 'Screen1'
<SelectionScreen>:
BoxLayout:
Button:
text: "Click when ready"
size_hint: .6, .5
font_size: 10
on_press: root.screenSelector()
on_release: root.manager.current = 'Screen0'
<Screen0>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Next"
on_release: root.manager.current = str(root.testScreen)
The SelectionScreen is working fine, but now I am not able to reach screen0. When removing the line
on_press: root.screenSelector()
I can, however, do this.
Thank you in advance for any help!
Problem
You are not able to reach screen0 because it is not in your screenList.
The variable, testScreen defined in method screenSelector is a local variable, which is not the same class variable, testScreen defined in class selectionScreen.
Undefined variable, return testscreen due to typo error.
At Screen0, the code, on_release: root.manager.current = str(root.testScreen) will cause an AttributeError: 'Screen0' object has no attribute 'testScreen'
Solution
In order to reach Screen0, you have to do the following:
Python Script
Add Screen0 into the variable, screenList
Replace random.randint(0, 1) with random.randint(0, 2)
Replace testScreen with self.testScreen in method screenSelector
kv file
Define an id, e.g. id: selection_screen
Reference it, e.g. root.manager.ids.selection_screen.testScreen
Add on_press call to screenSelector in the other screens, e.g. on_press: root.manager.ids.selection_screen.screenSelector()
Example
main.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import StringProperty
import random
class ScreenManager(ScreenManager):
pass
class SelectionScreen(Screen):
testScreen = StringProperty('Screen1')
def screenSelector(self):
screenList = ['Screen0', 'Screen1', 'Screen2']
testNumber = random.randint(0, 2)
self.testScreen = screenList[testNumber]
return self.testScreen
class Screen0(Screen):
pass
class Screen1(Screen):
pass
class Screen2(Screen):
pass
class Test(App):
def build(self):
return ScreenManager()
if __name__ == "__main__":
Test().run()
test.kv
#:kivy 1.10.0
<ScreenManager>:
SelectionScreen:
id: selection_screen
name: 'SelectionScreen'
Screen0:
name: 'Screen0'
Screen1:
name: 'Screen1'
Screen2:
name: 'Screen2'
<SelectionScreen>:
BoxLayout:
Button:
text: "Click when ready"
size_hint: .6, .5
font_size: 10
on_press: root.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen0>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 0"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen1>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 1"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
<Screen2>:
BoxLayout:
orientation: 'vertical'
Button:
text: "Screen 2"
on_press: root.manager.ids.selection_screen.screenSelector()
on_release:
root.manager.current = str(root.manager.ids.selection_screen.testScreen)
Output

Categories