Show the text form a TextInput in class A in a Label in class B - label

I'm so deeply stuck in this!!! I tried through hours of frustration to get this little thing done... Every help would be so kind and relieving.
So here's my problem:
I know there's a bit of code, but the hole question turns just about two classes...
In the class Datum, I want a Label.
In the class Alledaten, I want a TextInput.
Now I want that TextInput to bind on_text_validate to update my Labels text.
I know how that works within the same class... (its pretty simple)
but not in two different classes
'''
from kivy.app import App
from kivy.core.window import Window
from kivy.metrics import dp, sp
from kivy.properties import StringProperty, ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from wochenplaner_script import CodefuerWochenplaner_ausgeglichen as CW
Builder.load_file("kivy.kv")
Window.clearcolor = (1, 1, .5, .5)
# 1. File Managing -------------------------------
class Wochenplan(App):
def build(self):
# Designate .kv design file
# Builder.load_file("kivy.kv")
sm = ScreenManager()
sm.add_widget(Maininterface(name="screen_maininterface"))
sm.current = "screen_maininterface"
return sm
class Screenmanager(ScreenManager):
pass
# 2. Code ----------------------------------------
class Zeitplanprotag(GridLayout):
def __init__(self, **kwargs):
super(Zeitplanprotag, self).__init__(**kwargs)
y = Window.system_size[1]
for i in range(1, 16, 1):
buttonleft = Button(text=f'{i} left', size_hint=(.5, None), height=y * 0.1, halign="left", valign="middle")
buttonright = Button(text=f'{i} right', size_hint=(1, None), height=y * 0.1, halign="left", valign="middle")
self.add_widget(buttonleft)
self.add_widget(buttonright)
class Wochentage(BoxLayout):
def __init__(self, **kwargs):
super(Wochentage, self).__init__(**kwargs)
button = Button(size_hint=(.5, 1))
button.text = "Zeit"
button2 = Button(size_hint=(1, 1))
button2.text = "Plan"
self.add_widget(button)
self.add_widget(button2)
class Datum(BoxLayout):
text_input_str = StringProperty("tag")
def ooon_text_validate(self, widget):
self.text_input_str = widget.text
print(self.text_input_str)
# self.ids.label_am_arsch.text = self.text_input_str
self.ids.which_day.text = "harald"
# 2.2 Textinput -------------- <------ in here is my question
class Alledaten(BoxLayout):
# text_input_str = StringProperty("Tag 1")
def __init__(self, *args, **kwargs):
super(Alledaten, self).__init__(**kwargs)
input_ab_wann = TextInput(hint_text="Ab Tag: ",
hint_text_color=(0, 0, 0, 1),
background_color=(1, 1, 1, 1),
halign="center",
multiline=False)
# ids="input_ab_wann_id")
# input_ab_wann.bind(on_text_validate=Datum().ooon_text_validate) <----- **whyyy does this not go inside the function ooon_text_validate?**
def on_text(widget):
Datum().ooon_text_validate(widget) # <------ **but with this the terminal prints the input text, but doesn't change the Label text**
input_ab_wann.bind(on_text_validate=on_text)
self.add_widget(input_ab_wann)
# 3. Appearance ----------------------------------
class Spalteprotag(BoxLayout):
pass
# 4. Screens -------------------------------------
class Maininterface(Screen):
def float_in_int(self, float, **kwargs):
super(Maininterface).__init__(**kwargs)
de_int = float
return int(de_int)
# ----------------------------------
if __name__ == "__main__":
Wochenplan().run()
'''
and my kv file:
'''
<Screenmanager>:
Maininterface:
<Maininterface>:
# 1. Stufe
BoxLayout:
# 1. vBox -> 2. hBox -> 3. vBox -> 4. Grid 2 cols
orientation: "vertical"
size: root.width, root.height
# 1. Stufe
BoxLayout:
size_hint: (1, .15)
orientation: "horizontal"
Alledaten:
orientation: "vertical"
size_hint: (.3, 1)
Label:
text: "Wochenplan"
size_hint: (1, 1)
# texture_size: self.size
text_size: self.size
halign: "center"
valign: "middle"
markup: True
font_size: dp(20)
color: (0, 0, 0, 1)
Label:
text: ""
size_hint: (.3, .5)
Datum: # <------ in here is my Label
# 2. Stufe
BoxLayout:
orientation: "horizontal"
# 1 Spalte in Tabelle
Spalteprotag:
# 2 Spalte in Tabelle
# Spalteprotag:
<Spalteprotag>:
# -> BoxLayout
orientation: "vertical"
# size_hint: (.25, 1)
# 3. Stufe
Wochentage:
size_hint: (1, .1)
ScrollView:
do_scroll_x: False
do_scroll_y: True
Zeitplanprotag:
cols: 2
height: self.minimum_height
size_hint_y: None
# row_default_height: 100
row_force_default: False
# spacint: 10
<Zeitplanprotag>:
# 4. Stufe -> GridLayout
<Wochentage>:
<Datum>:
orientation: "horizontal"
size_hint: (1, .1)
TextInput:
id: zweite_input
hint_text: "this text input is just an example to show my question\n ->> the textinput above should work like that one!"
multiline: False
on_text_validate: root.text_input_str = self.text
Label: # <------ this is the label which causes problems
id: which_day
# text: root.text_input_str
text: root.text_input_str
# background_color: (0, 0, 0, 1)
color: (0, 0, 0, 1)
# size_hint: (1, 1)
<Alledaten>:
# TextInput:
# id: ab_tag_textin
# hint_text:"Ab Tag: "
# hint_text_color:(0, 0, 0, 1)
# background_color:(1, 1, 1, 1)
# halign:"center"
# multiline:False
# on_text_validate: Datum.ooon_text_validate = self.text <---- I tried it with an TextInput in the kv File but I did't know how to reference to another class...
if someone knows the solution via kv file im also very happy, but I want to now what I did wrong in my way to fix it via python file...
'''

Related

Screen doesn't change after pressing a button in Xcode simulator

My Kivy app work fine in python2. Running in Xcode (10.1) simulator gives me the main screen, but pressing button does not bring me to the second one (drawing screen). Interestingly when moving and pressing on the mouse, the app print the coordinates as it should.
I've tried create a very simple project with only 1 button and 2 screens: again, on python works OK but in the simulator not.
Any suggestions?
python
class MainScreen(Screen):
username = ObjectProperty(None)
test_type = ObjectProperty(None)
test_date = ObjectProperty(None)
def reset(self):
self.username.text = ""
self.test_type.text = ""
self.test_date.text = ""
class SecondScreen(Screen):
pass
class AnotherScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class DrawInput(Widget):
def on_touch_down(self, touch):
timing_ms = ApplePenApp.get_running_app().sw_seconds
print('test')
with self.canvas:
Color(0, 0, 0)
touch.ud["line"] = Line(points = (touch.x, touch.y))
def on_touch_move(self, touch):
timing_ms = ApplePenApp.get_running_app().sw_seconds
touch.ud["line"].points += (touch.x, touch.y)
def on_touch_up(self, touch):
timing_ms = ApplePenApp.get_running_app().sw_seconds
presentation = Builder.load_file("applepen_kivy.kv")
class ApplePenApp(App):
def build(self):
return presentation
if __name__=="__main__":
ApplePenApp().run()
Kivy
# File name: main.py
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
id: main
SecondScreen:
AnotherScreen:
<MainScreen>:
name: "main"
#define global variables
username: username
test_type: test_type
test_date: test_date
GridLayout:
cols:1
#organise the window
size: root.width, root.height
GridLayout:
cols: 2
Label:
text: "Username: "
color: 0.5,0.5, 0.5, 1
font_size: 30
TextInput:
id: username
multiline: False
font_size: 30
Label:
text: "Copy/Recall/Recall2: "
color: 0.5,0.5, 0.5, 1
font_size: 30
TextInput:
id: test_type
multiline: False
font_size: 30
Label:
text: "Date: "
color: 0.5,0.5, 0.5, 1
font_size: 30
TextInput:
id: test_date
multiline: False
font_size: 30
Button:
font_size: 30
size_hint: 0.5, 0.5
text: "Submit"
on_press: app.root.current = "drawing"
<SecondScreen>:
name: "drawing"
FloatLayout:
DrawInput:
id: drawing
Button:
font_size: 30
size_hint: 0.2, 0.05
pos_hint: {"x": 0.4, "bottom": 1}
text: "finish"
on_release: app.root.current = "main"

Kivy Popup not able to access root method

I am a newbie here so feel free to correct me if I am not following proper procedures.
I have a Kivy app that opens a popup. In the popup, I can enter 2 numbers then click the Add button which should add the 2 numbers. I get an error saying, "AttributeError: 'CustomPopup' object has no attribute 'addNum'"
Why would this be?
test.py file
import kivy
kivy.require('1.9.1') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
class CustomPopup(Popup):
pass
class MyStuff(BoxLayout):
num1 = StringProperty
num2 = StringProperty
answer = ''
def openPopup(self):
the_popup = CustomPopup()
the_popup.open()
def addNum(self):
self.answer = str(int(self.num1) + int(self.num2))
class MyStuffApp(App):
def build(self):
return MyStuff()
if __name__ == '__main__':
MyStuffApp().run()
mystuff.kv file
#: import main test
<MyStuff>:
orientation: 'vertical'
spacing: 5
padding: 5
Button:
text: 'Change numbers'
on_press: root.openPopup()
font_size: 50
Label:
text: root.answer
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Addition'
num1: number2
num2: number2
BoxLayout:
orientation: 'vertical'
Label:
text: '1st number'
TextInput:
id: number1
Label
text: '2nd number'
TextInput
id: number2
Button:
text: 'Add'
on_press: root.addNum()
First of all, to access addNum, you have to call app.root.addNum from the kv part.
You also have to send the values to be added, which are the text you entered in the text boxes: (number1.text, number2.text).
So the running code could be something like this:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
Builder.load_string("""
<MyStuff>:
orientation: 'vertical'
spacing: 5
padding: 5
Button:
text: 'Change numbers'
on_press: root.openPopup()
font_size: 50
Label:
text: root.answer
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Addition'
num1: number2
num2: number2
BoxLayout:
orientation: 'vertical'
Label:
text: '1st number'
TextInput:
id: number1
Label
text: '2nd number'
TextInput
id: number2
Button:
text: 'Add'
on_press: app.root.addNum(number1.text, number2.text)
""")
class CustomPopup(Popup):
pass
class MyStuff(BoxLayout):
# num1 = StringProperty()
# num2 = StringProperty()
answer = ''
def openPopup(self):
the_popup = CustomPopup()
the_popup.open()
def addNum(self, *args):
# self.answer = str(int(self.num1) + int(self.num2))
self.answer = str(int(args[0]) + int(args[1]))
print(self.answer)
class MyStuffApp(App):
def build(self):
return MyStuff()
if __name__ == '__main__':
MyStuffApp().run()
You can access the methods from MyStuff if you have a reference somewhere to that class.
When you do root.addNum() you try to access a method inside CustomPopup which is root in that case.
So what I would do in this case, is to define MyStuff as an attribute of your App class, (self.ms = MyStuff()). That way you can access it in kv by doing app.ms.addNum()
Also you need to pass the numbers to addNum
In py.:
class MyStuff(BoxLayout):
answer = ''
def openPopup(self):
the_popup = CustomPopup()
the_popup.open()
def addNum(self, num1, num2):
self.answer = str(int(num1) + int(num2))
class MyStuffApp(App):
def build(self):
self.ms = MyStuff()
return self.ms
And in kv.:
Button:
text: 'Add'
on_press: app.ms.addNum(number1.text, number2.text)

wxPython's BoxSizer in a ScrolledWindow doesn't work if the contents of the ScrolledWindow do fit inside the space

The important part of my code is this one:
class Entry(object):
def __init__(self, list_: 'List', ...) -> None:
self.list = list_ # type: List
self.sizer = wx.BoxSizer(wx.HORIZONTAL) # type: wx.BoxSizer
self.name = wx.StaticText(list_.panel, # type: wx.StaticText
label="Example")
self.sizer.Add(self.name, 1, wx.CENTRE)
self.widgets = [
self.name
] # type: List[Union[wx.StaticText, wx.TextCtrl]]
for i in range(data.columns):
self.widgets.append(wx.TextCtrl(list_.panel, value="1"))
self.widgets.append(wx.StaticText(list_.panel, label="1"))
sizer = wx.BoxSizer(wx.VERTICAL) # type: wx.BoxSizer
sizer.Add(self.widgets[-2], 0, wx.EXPAND)
sizer.Add(self.widgets[-1], 0, wx.EXPAND)
self.sizer.Add(sizer, 2, wx.EXPAND)
list_.sizer.Add(self.sizer, 0, wx.EXPAND)
list_.entries.append(self)
# ...
if call_layout:
height = len(list_.entries) * max(
i.GetSize()[1]
for i in self.widgets
) # type: int
list_.sizer.Layout()
list_.panel.SetScrollbars(4, 4, 1, height)
# ...
class List(object):
def __init__(self, ...) -> None:
# ...
self.panel = wx.ScrolledWindow( # type: wx.ScrolledWindow
design.panel, wx.ID_ANY
) # design.panel is a wx.Panel, it's parent is a wx.Frame. The wx.Frame has no sizer, the wx.Panel has a vertical wx.BoxSizer.
self.sizer = wx.BoxSizer(wx.VERTICAL) # type: wx.BoxSizer
design.sizer.Add(self.panel, 1, wx.EXPAND)
self.panel.SetSizer(self.sizer)
self.entries = [] # type: List[Entry]
If I add enough 'Entry' objects, all the widgets are located in the top left corner; but the layout works if there are enough widgets.
Additionally: If there is a good way to calculate the height for 'SetScrollbars' automatically or at least in a better way, tell me! Because it is very ugly this way.
Thanks!
(My system: MacOS, I am using wxPython phoenix, because I need to use python3, wxpython-phoenix or another tag like this one doesn't seem to exist, if there is one, tell me. I think I will ask a whole lot more questions on that subject.)
(Posted on behalf of the OP).
I solved it. It was all my fault, wxPython is working fine. I changed a few values to test the code, but I forgot one.

Pygame: importing fonts causes game to stall [duplicate]

Is there a way I can display text on a pygame window using python?
I need to display a bunch of live information that updates and would rather not make an image for each character I need.
Can I blit text to the screen?
Yes. It is possible to draw text in pygame:
# initialize font; must be called after 'pygame.init()' to avoid 'Font not Initialized' error
myfont = pygame.font.SysFont("monospace", 15)
# render text
label = myfont.render("Some text!", 1, (255,255,0))
screen.blit(label, (100, 100))
You can use your own custom fonts by setting the font path using pygame.font.Font
pygame.font.Font(filename, size): return Font
example:
pygame.font.init()
font_path = "./fonts/newfont.ttf"
font_size = 32
fontObj = pygame.font.Font(font_path, font_size)
Then render the font using fontObj.render and blit to a surface as in veiset's answer above. :)
I have some code in my game that displays live score. It is in a function for quick access.
def texts(score):
font=pygame.font.Font(None,30)
scoretext=font.render("Score:"+str(score), 1,(255,255,255))
screen.blit(scoretext, (500, 457))
and I call it using this in my while loop:
texts(score)
There are 2 possibilities. In either case PyGame has to be initialized by pygame.init.
import pygame
pygame.init()
Use either the pygame.font module and create a pygame.font.SysFont or pygame.font.Font object. render() a pygame.Surface with the text and blit the Surface to the screen:
my_font = pygame.font.SysFont(None, 50)
text_surface = myfont.render("Hello world!", True, (255, 0, 0))
screen.blit(text_surface, (10, 10))
Or use the pygame.freetype module. Create a pygame.freetype.SysFont() or pygame.freetype.Font object. render() a pygame.Surface with the text or directly render_to() the text to the screen:
my_ft_font = pygame.freetype.SysFont('Times New Roman', 50)
my_ft_font.render_to(screen, (10, 10), "Hello world!", (255, 0, 0))
See also Text and font
Minimal pygame.font example: repl.it/#Rabbid76/PyGame-Text
import pygame
pygame.init()
window = pygame.display.set_mode((500, 150))
clock = pygame.time.Clock()
font = pygame.font.SysFont(None, 100)
text = font.render('Hello World', True, (255, 0, 0))
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (128, 128, 128), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
pygame.draw.rect(background, color, rect)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(background, (0, 0))
window.blit(text, text.get_rect(center = window.get_rect().center))
pygame.display.flip()
pygame.quit()
exit()
Minimal pygame.freetype example: repl.it/#Rabbid76/PyGame-FreeTypeText
import pygame
import pygame.freetype
pygame.init()
window = pygame.display.set_mode((500, 150))
clock = pygame.time.Clock()
ft_font = pygame.freetype.SysFont('Times New Roman', 80)
background = pygame.Surface(window.get_size())
ts, w, h, c1, c2 = 50, *window.get_size(), (128, 128, 128), (64, 64, 64)
tiles = [((x*ts, y*ts, ts, ts), c1 if (x+y) % 2 == 0 else c2) for x in range((w+ts-1)//ts) for y in range((h+ts-1)//ts)]
for rect, color in tiles:
pygame.draw.rect(background, color, rect)
run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
window.blit(background, (0, 0))
text_rect = ft_font.get_rect('Hello World')
text_rect.center = window.get_rect().center
ft_font.render_to(window, text_rect.topleft, 'Hello World', (255, 0, 0))
pygame.display.flip()
pygame.quit()
exit()
I wrote a wrapper, that will cache text surfaces, only re-render when dirty. googlecode/ninmonkey/nin.text/demo/
I wrote a TextBox class. It can use many custom fonts relatively easily and specify colors.
I wanted to have text in several places on the screen, some of which would update such as lives, scores (of all players) high score, time passed and so on.
Firstly, I created a fonts folder in the project and loaded in the fonts I wanted to use. As an example, I had 'arcade.ttf' in my fots folder. When making an instance of the TextBox, I could specify that font using the fontlocation (optional) arg.
e.g.
self.game_over_text = TextBox("GAME OVER", 100, 80, 420, RED, 'fonts/arcade.ttf')
I found making the text and updating it each time "clunky" so my solution was an update_text method.
For example, updating the Player score:
self.score1_text.update_text(f'{self.p1.score}')
It could be refactored to accept a list of str, but it suited my needs for coding a version of "S
# -*- coding: utf-8 -*-
'''
#author: srattigan
#date: 22-Mar-2022
#project: TextBox class example
#description: A generic text box class
to simplify text objects in PyGame
Fonts can be downloaded from
https://www.dafont.com/
and other such sites.
'''
# imports
import pygame
# initialise and globals
WHITE = (255, 255, 255)
pygame.font.init() # you have to call this at the start
class TextBox:
'''
A text box class to simplify creating text in pygame
'''
def __init__(self, text, size, x=50, y=50, color=WHITE, fontlocation=None):
'''
Constuctor
text: str, the text to be displayed
size: int, the font size
x: int, x-position on the screen
y: int, y-position on the screen
color: tuple of int representing color, default is (255,255,255)
fontlocation: str, location of font file. If None, default system font is used.
'''
pygame.font.init()
self.text = text
self.size = size
self.color = color
self.x = x
self.y = y
if fontlocation == None:
self.font = pygame.font.SysFont('Arial', self.size)
else:
self.font = pygame.font.Font(fontlocation, self.size)
def draw(self, screen):
'''
Draws the text box to the screen passed.
screen: a pygame Surface object
'''
text_surface = self.font.render(f'{self.text}', False, self.color)
screen.blit(text_surface, [self.x, self.y])
def update_text(self, new_text):
'''
Modifier- Updates the text variable in the textbox instance
new_text: str, the updated str for the instance.
'''
if not isinstance(new_text, str):
raise TypeError("Invalid type for text object")
self.text = new_text
def set_position(self, x, y):
'''
Modifier- change or set the position of the txt box
x: int, x-position on the screen
y: int, y-position on the screen
'''
self.x = x
self.y = y
def __repr__(self):
rep = f'TextBox instance, \n\ttext: {self.text} \n\tFontFamly:{self.font} \n\tColor: {self.color} \n\tSize: {self.size} \n\tPos: {self.x, self.y}'
return rep
if __name__ == "__main__":
test = TextBox("Hello World", 30, 30, 30)
print(test)
To use this in my Game class
from textbox import TextBox
and in the initialisation part of the game, something like this:
self.time_text = TextBox("Time Left: 100", 20, 20, 40)
self.cred_text = TextBox("created by Sean R.", 15, 600, 870)
self.score1_text = TextBox("0", 100, 40, 650)
self.score2_text = TextBox("0", 100, 660, 650)
self.lives1_text = TextBox("[P1] Lives: 3", 20, 40, 750)
self.lives2_text = TextBox("[P2] Lives: 3", 20, 660, 750)
self.game_over_text = TextBox("GAME OVER", 100, 80, 420, RED)
self.textbox_list = []
self.textbox_list.append(self.time_text)
self.textbox_list.append(self.cred_text)
self.textbox_list.append(self.score1_text)
self.textbox_list.append(self.score2_text)
self.textbox_list.append(self.lives1_text)
self.textbox_list.append(self.lives2_text)
so that when I want to draw all on the screen:
for txt in self.textbox_list:
txt.draw(screen)
In the update section of the game, I only update directly the boxes that have updated text using the update_text method- if there is nothing to be updated, the text stays the same.
I wrote a TextElement class to handle text placement. It's still has room for improvement. One thing to improve is to add fallback fonts using SysFont in case the font asset isn't available.
import os
from typing import Tuple, Union
from pygame.font import Font
from utils.color import Color
class TextElement:
TEXT_SIZE = 50
def __init__(self, surface, size=TEXT_SIZE, color=Color('white'), font_name='Kanit-Medium') -> None:
self.surface = surface
self._font_name = font_name
self._size = size
self.color = color
self.font = self.__initialize_font()
#property
def font_name(self):
return self._font_name
#font_name.setter
def font_name(self, font_name):
self._font_name = font_name
self.font = self.__initialize_font()
#font_name.deleter
def font_name(self):
del self._font_name
#property
def size(self):
return self._size
#size.setter
def size(self, size):
self._size = size
self.font = self.__initialize_font()
#size.deleter
def size(self):
del self._size
def write(self, text: str, coordinates: Union[str, Tuple[int, int]] = 'center'):
rendered_text = self.font.render(text, True, self.color)
if isinstance(coordinates, str):
coordinates = self.__calculate_alignment(rendered_text, coordinates)
self.surface.blit(rendered_text, coordinates)
return self
def __calculate_alignment(self, rendered_text, alignment):
# https://www.pygame.org/docs/ref/surface.html#pygame.Surface.get_rect
# Aligns rendered_text to the surface at the given alignment position
# e.g: rendered_text.get_rect(center=self.surface.get_rect().center)
alignment_coordinates = getattr(self.surface.get_rect(), alignment)
return getattr(rendered_text, 'get_rect')(**{alignment: alignment_coordinates}).topleft
def __initialize_font(self):
return Font(os.path.join(
'assets', 'fonts', f'{self._font_name}.ttf'), self._size)
Here is how you can use it:
TextElement(self.screen, 80).write('Hello World!', 'midtop')
TextElement(self.screen).write('Hello World 2!', (250, 100))
# OR
text = TextElement(self.screen, 80)
text.size = 100
text.write('Bigger text!', (25, 50))
text.write('Bigger text!', 'midbottom')
I hope this can help someone! Cheers!

How can I make a Kivy (KVlang) cascaded spinner set respond to my first on_release?

My cascaded spinners do what i want on the SECOND release of the master spinner.
How can i make this work on the FIRST release?
Thanks in advance. Here is my KVlang and Python code.
KVlang:
# 0009_spinnerCascade.kv
<MyLayout#BoxLayout>:
orientation: 'vertical'
Spinner:
id: s1
text: 'colors'
values: 'colors numbers days'.split()
size_hint_y: None
height: '48dp'
my_string_property: 'hello from s1'
on_release: s2.my_key = self.text
Label:
text: 'Mid label'
Spinner:
id: s2
text: 'choose one'
my_dict: {'colors': 'red green blue'.split(), 'numbers': '1 2 3'.split(), 'days':'mon tue wed'.split() }
my_key: 'numbers'
values: self.my_dict[self.my_key]
size_hint_y: None
height: '48dp'
MyLayout
Python
''' 0009_spinnerCascade.py
'''
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
Config.set('graphics', 'width', '430')
Config.set('graphics', 'height', '430')
class MyApp(App):
def build(self):
self.root = Builder.load_file('0009_spinnerCascade.kv')
return self.root
if __name__ == '__main__':
MyApp().run()
release event is triggered when your spinner opens and shows options, before you select any. In that moment value of s2.my_key is set to s1.text. After you select option, release event is not triggered and s2.my_key remains unchanged. Then after you display list of s1 options with second click, second release event is triggered and value od s2.my_key is finally setted to right value. Observe this behaviour with:
<MyLayout#BoxLayout>:
# ...
Spinner:
id: s1
# ...
on_release: s2.my_key = self.text ; print("spinner opened")
# ...
You actually need to observe text property to detect changes:
<MyLayout#BoxLayout>:
# ...
Spinner:
id: s1
# ...
on_text: s2.my_key = self.text ; print("option selected")
# ...
I implemented this behaviour as follows:
def callback(instance,value):
print(instance,value)
class spinnerName(Spinner):
values = ('1','2','3')
spinInstance = Spinner()
spinInstance.bind(text=callback)
print(instance,value) will be called every time you click an item in the Spinner.

Resources