Automatic 'focus' of TextInput Kivy - python

I have a textinput widget that looks like this:
<ReaderWidget>:
Label:
text: 'Please scan EBT card'
font_size: root.height/8
size: self.texture_size
bold: True
color: 0, 0.70, 0.93, 1
TextInput:
focus: True
password: True
multiline: False
cursor: 0, 0
The widget is dynamically added to the layout based on the user pressing a button in another widget. Currently the user has to point the mouse/finger into the text box before entering text, and I want the cursor to be in the text box ready to receive text without the user having to indicate by mouse press. Is there a way to do this?
It seems like focus : True should do it. But it doesn't seem to.

I know this is old but I found this question when I was trying to do something very similar. My code for adding the TextInput (and setting it's focus) was in the on_press handler for a button. A press would cause the TextInput to be added to the layout and it's focus set, but then it would lose focus when the button was released. Moving my code to on_release fixed the problem.

This worked for me in kivy 1.9.0:
def show_keyboard(event):
text_input.focus = True
Clock.schedule_once(show_keyboard)
If text_input.focus is set directly, it doesn't seem to work. Perhaps this is a bug in kivy?

I had the same issue, but not for a button, so the on_release was not an option.
If you want to do it with the on_touch_down method, you can focus the widget and add the current touch to be ignored for focusing:
def on_touch_down(self, touch):
self.focus = True
FocusBehavior.ignored_touch.append(touch)
Of course you also need to import FocusBehavior:
from kivy.uix.behaviors.focus import FocusBehavior
You can read more here: https://kivy.org/doc/stable/api-kivy.uix.behaviors.focus.html

Related

Kivy (Android): ScrollView.scroll_to() doesn't show widget hidded by keyboard

when a user click on a widget on my application, the keyboard that appears can hide it if the widget is too low.
I tried ScrollView.scroll_to() to ask for a focus on the widget, it works but it doesn't take the keyboard in the equation.
Before I click on "Raison Sociale".
After I click on "Raison Sociale
So the widget is hidded by the keyboard.
I don't know if a function like this already exist.
If widget.hiddedByKeyboard():
widget.show_taking_consideration_of_the_keyboard()
There is also the problem of the widgets at the end of the Screen, if we try to show them by scrolling down, the ScrollView will try to go up again even if that will hide the widget.
Ahh the classic, the keyboard covers the widget problem. I encountered this and here's what I did to solve it:
In my KV file I had something like this:
<MainWindow>:
... [A BUNCH OF WIDGETS] ...
ScrollView:
BoxLayout:
orientation: 'vertical'
size_hint: 1, None
height: self.minimum_height
... [A BUNCH OF WIDGETS] ...
Widget: # The important widget
id: buffer
size_hint: (1, None)
height: root.buffer
I added at the bottom of the ScrollView a blank Widget whose height was defined by a NumericProperty in the top level widget (Window - a BoxLayout).
In the Python file I had:
from kivy.core.window import Window # Need to import this
class MainWindow(BoxLayout):
buffer = NumericProperty()
Then when I requested the keyboard, I made sure to set buffer = Window.keyboard_height. This adjusted the height of blank Widget to the height of the keyboard, essentially creating extra room for the keyboard. This gives the user extra scrolling room to position the keyboard.
You can combine this implementation with the ScrollView.scroll_to() method to create a really nice effect. Essentially pass ScrollView.scroll_to(text_input_widget) when the user clicks on the TextInput. This will automatically scroll the ScrollView down so that the TextInput is at the top and the keyboard is below it.
This probably isn't the cleanest implementation (I could probably do it better now), but the concept of creating a blank Widget whose size is the height of the keyboard would be the same.
I found a better way, this attribute will do all the job.
from kivy.core.window import Window
Window.softinput_mode = "below_target"

Kivy: set widget disabled property in python code

I have something like this in kivy lang file (pseudo code)
<RootWidget>:
Checkbox:
id: chkbox
TextInput:
id: in_text
text: ""
Button:
id: ok_btn
label: "Okay"
on_press: app.ok_pressed()
disabled: chkbox.active or len(in_text.text) > 8 and ...
The point is, the ok_btn needs to be enabled and disabled dynamically based on state of several other widgets.
This all works as expected, but now I have a problem. For complicated reasons, I need to create the button and insert it into the root widget in python rather than define it in a .kv file or string. I can't figure out what to do with the disabled property. If I set it as a property
btn = Button()
btn.disabled = ...
This only sets the initial state. I thought maybe
btn.bind(on_disabled=some_function)
but this is only to do something when the button is disabled, not to define when it should be disabled. Ditto on_state. I also tried
btn.bind(disabled=some_function)
some_function is never called
Thanks in advance for any pointer
It sounds like you have it backwards: it isn't the button's disabled property that you want to bind things to, but rather you want to bind to other things so that when they change the button's disabled property gets updated.
For instance, from your original example the autogenerated code is along the lines of chkbox.bind(active=lambda self: setattr(ok_btn, "disabled", self.active) (not actually this code, but something equivalent). You need to replicate this manually.
Of course you can abstract this in various ways. For instance, you could bind all the conditions you care about to update a property of your App class (so that it's always present to update, regardless of whether your button exists), then use a kv rule like disabled: app.that_property in your button. This is not the only option though.

Kivy button loses visual indication of being pressed when I add in functionality

I'm working on integrating some robots into my work's warehouse. I've created a Kivy GUI to operate these robots. Normally when you press a button in Kivy, the button shape shifts from rectangular to a rounded rectangle and the button color changes. It maintains this response if I add in simple functionality, like it printing words when pressed. However, when I add in code to control the robots, it loses this visual indication. The button works - when pressed it executes the proper function, but there is no change in the button's appearance to indicate it has been pressed.
I don't know how much code I can provide since it is proprietary. I'm using the robot company's API and SDK to create this GUI.
I've tried making buttons both using a .kv file and without. I've tried manually adding in color changes when the button is pressed - no luck. I've also tried making transparency changes and text changes. Basically I can't get any visual change to happen to the button when it is pressed while it calls this function.
from my .kv file (sorry the formatting came out weird):
< Button >:
font_size: 30
color: 1,1,1,1
size_hint: 0.15,0.1
< FloatLayout >:
Button:
text: "Clear Error"
font_size: 20
pos_hint: {"x":0.85, "top":0.1}
background_normal: ''
background_color: .2,.8,.2,1
on_press: app.ClearError()
from my .py file:
def ClearError(self):
robot_name1 = "robot name"
print("CLEAR ERROR")
robot = Robot.load(robot_name1, client=client)
if robot.error_status is not None:
print("Error status!")
robot.error_status = None
robot.save(client=client)

Using user input from TextInput - Kivy

I am trying to do some simple math in a kivy app using TextInput to allow users to input values. I defined the TextInput in the kv section of the code. I am unsure how to create a simple submit button to assign what's in the TextInput (which is defined in kv) to a variable so that I can do basic math with it in the python section.
You'll want to do something like the following:
BoxLayout:
orientation: 'vertical'
TextInput:
id: ti
Button:
text: 'do something!'
on_press: run_some_function_with_text(ti.text)
run_some_function_with_text would probably most usefully be a method of some other widget, but could be anything else you like, or you could just write the function inline if it's simple.

Tab/Enter (and other keystrokes) handling in Kivy's TextInput widgets

I'm writing an app using Kivy framework and I stumbled upon a minor but annoying problem: I don't know how to handle Tab/Enter/Arrow keys in text fields so that pressing either of them would dispatch an event, eg. switch the focus (jump) to another TextInput or launch something like send_form()
Could anyone please shed some light on this issue?
Kivy 1.9 provides the ability to set write_tab: False on text inputs (see docs), causing the tab key to focus on the next focusable widget.
Kivy allows the Enter key to dispatch events by setting multiline: False and on_text_validate: root.foo().
So, to create a text input widget that has the desired Enter and Tab functionality, do as follows:
TextInput:
write_tab: False
multiline: False
on_text_validate: root.foo()
Just found this old question and figured I would contribute. I also needed tab / enter to go to the next field. I did what #tshirtman suggested. This is my custom TextInput class:
from kivy.uix.textinput import TextInput
class TabTextInput(TextInput):
def __init__(self, *args, **kwargs):
self.next = kwargs.pop('next', None)
super(TabTextInput, self).__init__(*args, **kwargs)
def set_next(self, next):
self.next = next
def _keyboard_on_key_down(self, window, keycode, text, modifiers):
key, key_str = keycode
if key in (9, 13) and self.next is not None:
self.next.focus = True
self.next.select_all()
else:
super(TabTextInput, self)._keyboard_on_key_down(window, keycode, text, modifiers)
This allows you to pass next when you instantiate the input, or alternatively call set_next on an existing input.
9 and 13 are the key codes for tab and enter.
Works well for me.
As suggested by Daniel Kinsman in his comment, you could subclass TextInput, add "previous" and "next" ObjectProperties for tab support (easy to set in kv using references to other widgets), and handle the keyboard events differently. There is no out of the box support for this right now, but if you want to work on such modification drop us a feature-request or comme discuss it in #kivy on freenode.
https://github.com/kivy/kivy/blob/master/kivy/uix/textinput.py#L1188
Maybe it would be even better to add such support on widget, and add some focus logic, so tab/enter have effects on any activable widget, and some widgets like slider use right/left/up/down keys too.
So there is still a lot to do in Kivy about that, and if you are interested in helping, you can really make it happen faster, we'll help you :)
[Insufficient points to just comment, so adding this here...]
It's crucial to note that the keyboard NEXT behavior only works easily if the next field is managed by the same keyboard layout. However, an advanced app will have:
username (qwerty)
password (password)
ID (numeric)
etc
So the approaches above really doesn't work out.
In the kv file:
MyTextInput:
next: idTheNextFieldBelowThis
In your MyTextInput class:
def insert_text(self, value, from_undo=False):
#
# Unfortunately the TextInput write_tab behavior only works if the next field is the same exact keyboard
# type.
#
if not value[-1:] == ' ':
return super(MyTextInput, self).insert_text(value, from_undo=from_undo)
r = super(MyTextInput, self).insert_text(value[:-1], from_undo=from_undo)
if self.next is not None:
self.next.focus = True
return r

Categories