Kivyで任意のwidgetをクリックしたらそのままテキストボックスに入力ができるようにするの巻

Kivyで任意のwidgetをクリックしたらそのままテキストボックスに入力ができるようにするの巻

はじめに

Kivyでテキストボックスを作ったときに、任意のwidgetをクリック(タップ)したら、紐づけたテキストボックスがアクティブになってそのままテキスト入力ができるようにしたいぞ、と

こんな感じに。

Labelをダブルタップするとtextinput1がアクティブになって入力ができるようになる。

Buttonをクリックするとtextinput2がアクティブになって入力ができるようになる。

と、いうことをやる方法の備忘録です。

やり方

以下の2つを組み込めば良かったのでした。

  1. Labelをダブルタップしたら(Buttonをクリックしたら)対応するテキストボックスのfocusをTrueにする
  2. Clockを使って、1.を少し遅れて実行することで、タップ(クリック)イベントが完了してからTextInputにfocusが行くようにする

コード

冒頭の動画のやつのコードです。

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang import Builder

from kivy.clock import Clock

Builder.load_string('''
<Otameshi>
    orientation: 'vertical'
    BoxLayout:
        TextInput:
            id: textinput1desu
            hint_text: 'textinput1 for Label'
        TextInput:
            id: textinput2desu
            hint_text: 'textinput2 for Button'
    Label:
        id: labeldesu
        text: 'Label dayo'
        font_size: 80
        #args[1]; mouse pos correspond to args 'touch' for on_touch_down 
        on_touch_down: root.focus_from_label(args[1])
            
    Button:
        id: buttondesu
        text: 'Button dayo'
        font_size: 80
        on_press: root.focus_from_button()

<TextInput>
    padding: 30,150
    font_size: 80
''')


#give class the name of Otameshi 
class Otameshi(BoxLayout):

    #for label
    def focus_from_label(self, touch):

        #execute if touch is double tap on the widget(Label)
        if self.ids.labeldesu.collide_point(*touch.pos) and touch.is_double_tap:

            #assign textinput object to a variable
            target_textinput = self.ids.textinput1desu

            #wait for 0.5 sec to execute function to keep focus maintained
            Clock.schedule_once(lambda dt: self.focus_callback(target_textinput, dt=dt), 0.5)
 
    #for button
    def focus_from_button(self):

        #assign textinput object to a variable
        target_textinput = self.ids.textinput2desu

        #wait for 0.5 sec to execute function to keep focus maintained
        Clock.schedule_once(lambda dt: self.focus_callback(target_textinput, dt=dt), 0.5)
 
    #for Clock function above
    def focus_callback(self, target_textinput, dt, *kwargs):

        #turn focus to True
        target_textinput.focus=True

#give class the name of App 
class TextInputtestApp(App):

    def __init__(self, **kwargs):
        super(TextInputtestApp, self).__init__(**kwargs)

    def build(self):
        return Otameshi()

if __name__ == '__main__':
    TextInputtestApp().run()

コードの説明をざっくり

・Labelをダブルタップしたとき(on_touch_down)の関数; focus_from_label を定義。タップしたときのargs[1]をtouchとして入力に持ってくる。

 def focus_from_label(self, touch):

・Labelウィジェット(id: labeldesu)のところでon_touch_downイベントが起こっていて、かつそれがダブルタップだった時に処理を実行する

if self.ids.labeldesu.collide_point(*touch.pos) and touch.is_double_tap:

・変数target_textinputに左側のTextInputオブジェクト(id: textinput1desu)を入れておく

target_textinput = self.ids.textinput2desu

・Clock.schedule_onceにより、Labelをダブルタップしたときの関数(focus_callback)の実行を少し遅らせて(今回0.5秒)、タップイベントが終わった後にfocusがTextInputに行くようにしておく (0.5秒より短くしてもいいかも)

Clock.schedule_once(lambda dt: self.focus_callback(target_textinput, dt=dt), 0.5) 

・Buttonのときの関数設定部分はLabelのときの関数の流用なので割愛

・Clockのところのfocus_callback関数の定義。target_textinputのfocusをTrueにする

def focus_callback(self, target_textinput, dt, *kwargs):
    target_textinput.focus=True

で、OKと。これで冒頭の動画のような挙動にできるはず。

めでたしめでたし。

実施環境

Python 3.9.4

Kivy 2.0.0

macOS Catalina ver.10.15.7

参考にしたページ

・Stack Overflow 

 Python KIVY: how to select a TextInput without mouse click?

・Clockの説明 Kivy Official

 https://pyky.github.io/kivy-doc-ja/api-kivy.clock.html

・on_touch_downの引数について

 https://start-python.hateblo.jp/entry/2020/01/12/090000



https://business.xserver.ne.jp/

https://www.xdomain.ne.jp/

★LOLIPOP★

.tokyo

MuuMuu Domain!