'Kivy keyboard_on_key_down working doesn't convert text on one of inputs
I'm having a little problem with my code - I have 5 TextInputs where I want to write letters whenever button is pressed I move to another window, it works fine as it is.
The problem lays whenever I am trying to write without capslock on, the 4 first letters will convert by self.text=text.upper() function, however the last one doesn't seem to work - it reads the letter twice - first the one that comes from function and then one letters as a lowercase, but I don't know from where it comes and how prevent my code from taking it.
import kivy
import sys
kivy.require('1.11.1')
from kivy.app import App
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.app import App
from kivy.clock import Clock
from random import choice
import math
from kivy.properties import StringProperty
import string
from functools import partial
letters= string.ascii_lowercase
Builder.load_file("GuessWord.kv")
def set_color(letter, color):
COLORS_DICT = {"W" : "ffffff", "Y" : "ffff00", "G" : "00ff00"}
c = COLORS_DICT.get(color, "W")
return f"[color={c}]{letter}[/color]"
class MyTextInput(TextInput):
focused = 'id1'
def change_focus(self, *args):
app = App.get_running_app()
if app.root is not None:
# Now access the container.
layout = app.root.ids["layout"]
# Access the required widget and set its focus.
print("Changefocus", MyTextInput.focused)
layout.ids[MyTextInput.focused].focus = True
def keyboard_on_key_down(self, window, keycode, text, modifiers):
print(keycode,text)
focusedid = int(MyTextInput.focused[2])
if keycode[1] == "backspace":
if self.text=="":
if int(MyTextInput.focused[2]) > 1:
self.text = ""
focusedid -= 1
MyTextInput.focused = "id" + str(focusedid)
else:
self.text = self.text[:-1]
if keycode[1] == "right":
if int(MyTextInput.focused[2]) < 5:
focusedid += 1
MyTextInput.focused = "id" + str(focusedid)
elif int(MyTextInput.focused[2]) == 5:
MyTextInput.focused = "id" + str(1)
elif keycode[1] == "left":
if int(MyTextInput.focused[2]) > 1:
focusedid -= 1
MyTextInput.focused = "id" + str(focusedid)
elif int(MyTextInput.focused[2]) == 1:
MyTextInput.focused = "id" + str(5)
elif keycode[1] in letters:
if int(MyTextInput.focused[2]) <= 5:
self.text=text.upper()
if int(MyTextInput.focused[2]) <5 :
focusedid += 1
MyTextInput.focused = "id" + str(focusedid)
self.change_focus()
print("After changing", MyTextInput.focused)
return True
class MainScreen(Widget):
pass
class TestingappApp(App):
def build(self):
return MainScreen()
TestingappApp().run()
.kv file
#:import Clock kivy.clock.Clock
#:import threading threading
#:import partial functools.partial
<MainScreen>:
BoxLayout:
size: root.size
orientation: "vertical"
CustomBox:
size_hint: 1,0.5
id: layout
cols:5
<CustomBox@BoxLayout>:
MyTextInput:
id: id1
font_size: 120
halign: "center"
focus: True
focused: "id1"
multiline: False
MyTextInput:
id: id2
font_size: 120
halign: "center"
focused: "id2"
multiline: False
MyTextInput:
id: id3
font_size: 120
halign: "center"
focused: "id3"
multiline: False
MyTextInput:
id: id4
font_size: 120
halign: "center"
focused: "id4"
multiline: False
MyTextInput:
id: id5
font_size: 120
halign: "center"
focused: "id5"
multiline: False
Solution 1:[1]
Problem is that code is more complex:
- first it runs
keyboard_on_key_down()which you use to add text in widget, - next it checks focus and if focus is the same then it runs
input_text()which is proper function to put/add text in widget and it adds second char, - next it may also run
on_text()which is executed whenself.textwas changed, - and finally it runs
keyboard_on_key_up()
So last widget doesn't change focus so it runs insert_text() which adds second char. But you can create empty function insert_text() to stop it. It will stop also numbers, etc.
def insert_text(self, substring, from_undo=False):
pass
but maybe all code should run in insert_text() instead of `keyboard_on_key_down()
See doc for Text Input:
- usage-example. There is
on_text(),on_enter(),on_focus(). - filtering. There is
input_text()
Full code (.kv is the same):
import kivy
import sys
kivy.require('1.11.1')
from kivy.app import App
from kivy.config import Config
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.app import App
from kivy.clock import Clock
from random import choice
import math
from kivy.properties import StringProperty
import string
from functools import partial
letters = string.ascii_lowercase
Builder.load_file("GuessWord.kv")
def set_color(letter, color):
COLORS_DICT = {"W" : "ffffff", "Y" : "ffff00", "G" : "00ff00"}
c = COLORS_DICT.get(color, "W")
return f"[color={c}]{letter}[/color]"
class MyTextInput(TextInput):
focused = 'id1'
def change_focus(self, *args):
app = App.get_running_app()
if app.root is not None:
# Now access the container.
layout = app.root.ids["layout"]
# Access the required widget and set its focus.
print("Changefocus", MyTextInput.focused)
layout.ids[MyTextInput.focused].focus = True
def insert_text(self, substring, from_undo=False):
print('[insert_text] substring:', substring)
print('[insert_text] self.text:', self.text)
#substring = substring.upper()
#return super().insert_text(substring, from_undo=from_undo)
def on_text(self, instance, value):
print('[on_text]', instance, 'have:', value)
def keyboard_on_key_up(self, window, keycode):
print('[keyboard_on_key_up] keycode:', keycode)
print('[keyboard_on_key_up] self.text:', self.text)
print('---')
def keyboard_on_key_down(self, window, keycode, text, modifiers):
print('[keyboard_on_key_down] keycode:', keycode)
print('[keyboard_on_key_down] text:', text)
print('[keyboard_on_key_down] self.text:', self.text)
focusedid = int(MyTextInput.focused[2])
if keycode[1] == "backspace":
if self.text == "":
if focusedid > 1:
self.text = ""
focusedid -= 1
MyTextInput.focused = "id" + str(focusedid)
else:
self.text = self.text[:-1]
if keycode[1] == "right":
if focusedid < 5:
focusedid += 1
MyTextInput.focused = "id" + str(focusedid)
elif focusedid == 5:
MyTextInput.focused = "id" + str(1)
elif keycode[1] == "left":
if focusedid > 1:
focusedid -= 1
MyTextInput.focused = "id" + str(focusedid)
elif int(MyTextInput.focused[2]) == 1:
MyTextInput.focused = "id" + str(5)
elif keycode[1] in letters:
if focusedid <= 5:
self.text = text.upper()
if focusedid < 5 :
focusedid += 1
MyTextInput.focused = "id" + str(focusedid)
self.change_focus()
print("[keyboard_on_key_down] after changing focus:", MyTextInput.focused)
return True
class MainScreen(Widget):
pass
class TestingappApp(App):
def build(self):
return MainScreen()
TestingappApp().run()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | furas |
