Kivy Character Counter from TextInput - python

again! I'm trying to add a character counter to my TextInput widget, but I don't know what parameters to pass for the four arguments, or much on how they're supposed to function. I checked the documentation, but it was putting me further into the woods. Anyway, here are the relevant snippets.
def charsLeft(window, keycode, text, modifiers):
# Do some magic, pass some parameters, and then...
ansLen.text = str(len(hidden.text) - len(answer.text))
And here's the code for my layout:
ansLen = Label(bold=True, halign="center", size_hint=(.2, .5), text_size=self.size, valign="middle")
answer = TextInput(id="sbt", multiline=False, size_hint=(.8, .5), text="")
answer.bind(keyboard_on_key_down=charsLeft)
I figure since it's on virtually every website, it ought to be fairly straightforward. I just don't know what I don't know here.

if you want to set a text counter you do not need to use keyboard_on_key_down, you just need to catch the text change for them we use bind, then we can use a lambda function to update the values since the bind returns the instance and the property changed, to set the value we use setattr:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
class MyApp(App):
def build(self):
layout = BoxLayout(orientation='vertical')
answer = TextInput(multiline=False, text="", size_hint=(1, 0.5))
ansLen = Label(bold=True, halign="center", text="", size_hint=(1, 0.5))
answer.bind(text=lambda instance, text: setattr(ansLen, "text", str(len(text))))
layout.add_widget(answer)
layout.add_widget(ansLen)
return layout
if __name__ == '__main__':
MyApp().run()

Related

Not able to print the text taken from kivy.uix.textinput.TextInput in KIVY Python

What I want to do is take input from kivy.uix.textinput.TextInput() and show it on the screen.
I am new to gui Programming and I think it is an easy task.
import kivy
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
class MyWindowApp(App):
def __init__(self):
super(MyWindowApp, self).__init__()
self.lbl = Label(text='Read Me!')
self.inp = TextInput(multiline=False,
size_hint =(1, 0.05),
pos_hint = {"x":0, "y":0.05})
def build(self):
self.inp.bind(on_text_validate=self.on_enter)
#self.bt1.bind(on_press=self.clk)
layout = FloatLayout()
layout.orientation = 'vertical'
layout.add_widget(self.lbl)
layout.add_widget(self.inp)
return layout
def on_enter(self,value):
print(value)
def clk(self, obj):
print ('input')
x = input()
self.lbl.text = x
window = MyWindowApp()
window.run()
when i run the code, I get the regular output output.
when I type say "hello world" in the textbox, this is the output:
<kivy.uix.textinput.TextInput object at 0x03F5AE30>
I do not get what I typed.
please suggest what should I do
Modify the following ...
def on_enter(self, value):
print(value.text)

How to position buttons inside a scrollview using kivy

I have some buttons inside a gridlayout in a scrollView that move vertically. I have been trying to postion those buttons at different positions but they are not changing. Please how do I position those buttons at different x and y coordinate. I used floatlayout but it is not working for ScrollView(), why is that?
import kivy
kivy.require('1.8.0')
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
class ScrollViewApp(App):
def build(self):
grid = GridLayout(cols=2, spacing=90, size_hint=(None,None))
grid.bind(minimum_height=grid.setter('height'))
btn1=Button(text='1', size=(90,90), size_hint=(None,None), pos_hint={'center_x':.5, 'center_y': 6})
btn2=Button(text='1', size=(90,90), size_hint=(None,None), pos_hint={'center_x':.5, 'center_y': 2})
btn3=Button(text='1', size=(90,90), size_hint=(None,None), pos_hint={'center_x':.5, 'center_y':.9})
grid.add_widget(btn1)
grid.add_widget(btn2)
grid.add_widget(btn3)
# pos_hint={center_x and center_y} not working
scroll = ScrollView( size_hint=(1, 1), do_scroll_x=False, do_scroll_y=True, scroll_type=['content'])
scroll.effect_cls= 'ScrollEffect'
scroll.add_widget(grid)
return scroll
if __name__ == '__main__':
ScrollViewApp().run()
to do this you can either give the each input of the x and y coordinate yourself:
for i in range(15):
a = float(input(f"Enter X postion value for #00{i}: "))
b = float(input(f"Enter Y postion value for #00{i}: "))
screen.add_widget(Button(text='#00' + str(i), size=(90,90), size_hint=(None,None),pos_hint={'center_x':a, 'center_y':b} ))
or
You can import random and set the different values or use "for" loop to insert different sequential values. I am showing you the examples 'random' below here:
for i in range(15):
a = random.randrange(0,10)
b = random.randrange(1,20)
screen.add_widget(Button(text='#00' + str(i), size=(90,90), size_hint=(None,None),pos_hint={'center_x':a, 'center_y':b} ))
I hope this will help you. And I am not sure about the usage of grid layouts here. You try to remove gridlayouts and just placing these buttons on different coordinate as you have gave the value for spacing of the button in the grid layout which may affect the output display. So, I hope it will work for you. Happy Coding...
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen, ScreenManager
import random
class ScrollViewApp(App):
def build(self):
screen = Screen()
for i in range(3):
a = float(input(f"Enter X postion value for #00{i}: "))
b = float(input(f"Enter Y postion value for #00{i}: "))
screen.add_widget(Button(text='#00' + str(i), size=(90,90), size_hint=(None,None),pos_hint={'center_x':a, 'center_y':b} ))
return screen
if __name__ == '__main__':
ScrollViewApp().run()
This one works fine. I hope this will help you....
float layout should certainly work in scrollview, here's an example:
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
import random
class ScrollViewApp(App):
def build(self):
float = FloatLayout(size=(600,1000),size_hint=(None,None))
for i in range(20):
btn1=Button(text=str(i), size=(90,90), size_hint=(None,None), pos_hint={'center_x':random.random(), \
'center_y': random.random()})
float.add_widget(btn1)
scroll = ScrollView( size_hint=(.8, .3), do_scroll_x=False, do_scroll_y=True, scroll_y=0.5,scroll_type=['content','bars'],\
bar_color = [1,0,0,.9],bar_inactive_color=[1,0,0.3,.5],bar_width=25)
scroll.add_widget(float)
return scroll
if __name__ == '__main__':
ScrollViewApp().run()
whereas with the attempted gridlayout, the position of each button will be at regular intervals, at least by default. To get arbitrary offsets at each cell of a gridlayout might be possible, but it would be three times as much work at least as just using float layout.
Note that the size_hint for the float layout is None,None, and the absolute size (600,1000) is intentionally larger than the scrollview (fractional 0.8,0.3 of default Window.size()). Scroll behaviour won't be seen otherwise.

How to position kivy widgets in floatlayout using pos_hint?

I'm stuck trying to position widgets in kivy in a FloatLayout using pos_hint.
If the label exists from the beginning, e.g. if I can define the pos_hint in the .kv file, everything works as expected. However, I'm trying to create buttons later on. Using this .kv file (named layouttest.kv):
<NewButton#Button>:
size_hint: (0.1, 0.1)
<BasicFloatLayout#FloatLayout>:
Button:
size_hint: (0.4, 0.2)
pos_hint: {'x': 0.0, 'top': 1.0}
text: 'create Button'
on_release: self.parent.create_Button()
and this python code, I am trying to position newly created blank buttons at a random y-position ranging from 0%-100% of the size of my BasicFloatLayout, and at a random x-position ranging from 0-200px.
If I press the button once, everything behaves as expected. On a second press, the first created button will change its y-position such that it is identical with the newly created button. On a third press, both old buttons will align with the newly created button and so on. The x-positioning will however remain as expected. Can someone please explain what I'm doing wrong here?
(Bonus points if you can help me moving the buttons using the update function and pos_hint)
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.properties import NumericProperty
from kivy.clock import Clock
import random
class BasicFloatLayout(FloatLayout):
timer = NumericProperty(0)
def update(self, *args):
self.timer += 1
for child in self.children:
try: child.update()
except AttributeError:
pass
def create_Button(self):
button = NewButton( (random.random(), random.random()) )
self.add_widget(button)
class NewButton(Button):
def __init__(self, pos, **kwargs):
super(NewButton, self).__init__(**kwargs)
self.pos[0] = 200*pos[0]
self.pos_hint['y'] = pos[1]
class layouttestApp(App):
def build(self):
GUI = BasicFloatLayout()
Clock.schedule_interval(GUI.update, 1/30.)
return GUI
if __name__ == "__main__":
layouttestApp().run()
First, make pos_hint: {'x': 0.0, 'y': 0.5}(because it's hard to get 2 different things work, if you are using x, use y instead of Top, if you are using Top, then use Bottom insead of x)
Second, instead of giving on_release: self.parent.create_Button() in the kv file, do this: on_release: root.create_Button()
Third, you have only assigned for the y value , you should also assign for the x value, the line is self.pos_hint['y'] = pos[1] inside the NewButton class.
But you can make it more simple by doing this:
#from your first class......
def create_Button(self):
button = NewButton(self.pos_hint{'x' : random.random(), 'y' : random.random()}
self.add_widget(button)
class NewButton(Button):
def __init__(self, *kwargs):
pass
Hope this makes some kind of sense, and you can modify it more.
(Note: I haven't wrote the begining part of your main class, I am lazy ;-p)

Kivy Dropdown not opening in ScreenManager but open in screen

I'm having issues to get a kivy.DropDown widget to work with a screen manager.
I am using the dropdown code that the kivy documentation provides, and add it to a screen widget, which I then add to a screen manager to display. The following code should reproduce the problem by itself.
import kivy
kivy.require('1.10.1')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
anchor = AnchorLayout()
anchor.anchor_x = "center"
anchor.anchor_y = "center"
anchor.size = self.size
anchor.pos = self.pos
dropdown = DropDown()
for index in range(10):
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: dropdown.select(btn.text))
# then add the button inside the dropdown
dropdown.add_widget(btn)
# create a big main button
mainbutton = Button(text='Hello', size_hint=(None, None))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
mainbutton.bind(on_release=dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
anchor.add_widget(mainbutton)
self.add_widget(anchor)
sm = ScreenManager() # transition = NoTransition())
sm.add_widget(MyScreen(name='screen'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()
Why is it that if put in a screen widget inside a ScreenManager, the dropdown widget does not work? Clarifications are welcome.
PS:
For anybody finding this issue, you can use the spinner widget to have the same functionality already implemented.
I believe your problem is due to garbage collection. The dropdown reference in your __init__() method is not saved (The bind uses a weakref which will not prevent garbage collection). So I think all you need to do is replace your dropdown local variable with a self.dropdown instance variable as:
import kivy
kivy.require('1.10.1')
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
anchor = AnchorLayout()
anchor.anchor_x = "center"
anchor.anchor_y = "center"
anchor.size = self.size
anchor.pos = self.pos
self.dropdown = DropDown()
for index in range(10):
# When adding widgets, we need to specify the height manually
# (disabling the size_hint_y) so the dropdown can calculate
# the area it needs.
btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
# for each button, attach a callback that will call the select() method
# on the dropdown. We'll pass the text of the button as the data of the
# selection.
btn.bind(on_release=lambda btn: self.dropdown.select(btn.text))
# then add the button inside the dropdown
self.dropdown.add_widget(btn)
# create a big main button
mainbutton = Button(text='Hello', size_hint=(None, None))
# show the dropdown menu when the main button is released
# note: all the bind() calls pass the instance of the caller (here, the
# mainbutton instance) as the first argument of the callback (here,
# dropdown.open.).
mainbutton.bind(on_release=self.dropdown.open)
# one last thing, listen for the selection in the dropdown list and
# assign the data to the button text.
self.dropdown.bind(on_select=lambda instance, x: setattr(mainbutton, 'text', x))
anchor.add_widget(mainbutton)
self.add_widget(anchor)
sm = ScreenManager() # transition = NoTransition())
sm.add_widget(MyScreen(name='screen'))
class MyApp(App):
def build(self):
return sm
if __name__ == '__main__':
MyApp().run()

Anchor a label to the corner?

In Kivy:
from kivy.app import App
from kivy.uix.label import Label
class TestApp(App):
def build(self):
label = Label(text="TEST")
return label
TestApp().run()
My label is centred in the window:
How can I instead anchor my label to the bottom right corner of the window?
You'd think
label.halign = 'right'
label.valign = 'bottom'
would do the trick, but as the Label documentation points out,
The valign property will have no effect and halign will only have an effect if your text has newlines; a single line of text will appear to be centered even though halign is set to left (by default).
It looks like adding the label to an AnchorLayout, then shrinking the size of the label relative to its parent widget, together achieves what I want.
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.anchorlayout import AnchorLayout
class TestApp(App):
def build(self):
anchor_layout = AnchorLayout(anchor_x='right', anchor_y='bottom')
label = Label(text="TEST")
label.size_hint = (0.1, 0.1)
anchor_layout.add_widget(label)
return anchor_layout
TestApp().run()
Produces:
Set the Label's text_size to its size, e.g. in kv text_size: self.size. The text_size controls the bounding box within which text is wrapped.

Categories