English Grad
English Grad

Reputation: 1395

Kivy sending text between widgets

I am trying to reset a text input box with new text when I click the mouse in another widget and I am not quite sure how to make this happen. I have tried altering the code in many ways but clearly do not not what I am doing. Here is the code I am using: Thanks to inclement and qua-non for getting me this far

Builder.load_string('''
    <MouseWidget>:
    image: image
    label: label
    orientation: 'vertical'
    Image:
        id: image
        source: root.source

    Label:
        id: label
        size_hint_y: None
        height: 50
        text: 'Hello World'
''')

class Test(TextInput):


    def on_double_tap(self):
        # make sure it performs it's original function
        super(Test, self).on_double_tap()

        def on_word_selection(*l):
            selected_word = self.selection_text
            print selected_word

        # let the word be selected wait for
        # next frame and get the selected word
        Clock.schedule_once(on_word_selection)

class MouseWidget(BoxLayout): 
    image = ObjectProperty()
    label = ObjectProperty()
    source = StringProperty()

It is here in this def that I want to update the textinput box that is created in AccordianAPP and sent through TEST with new text every time the mouse is clicked on the image

    def on_touch_down(self, touch):

        if self.image.collide_point(*touch.pos):
            self.label.text = str(touch.pos)

    def on_touch_up(self, touch):
        self.label.text = 'Hello World'

class AccordianApp(App):
    def build(self):
    root = Accordion(orientation='horizontal')

    item= AccordionItem(title='Page One')
    src = "image.png"
    image = MouseWidget(source=src, size_hint = (1.0, 1.0))

This is the textinput that I want to reset the text="" to something else when I click on the image

    textinput = Test(text='Testing', size_hint = (0.5, 1.0))

    # add image to AccordionItem
    item.add_widget(image)
    item.add_widget(textinput)
    root.add_widget(item)

    return root

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

Thanks for the help

Upvotes: 0

Views: 1439

Answers (1)

inclement
inclement

Reputation: 29478

What you really need here is a reference to the textinput that the mousewidget can access. As long as the mousewidget can access some variable that's assigned to the textinput, it can do anything it likes to that textinput.

Here's a simple modification that simply adds an attribute 'self.textinput' to the mousewidget, that is then set to point at the textinput. Then in the on_touch_up method it's easy to add text to the textinput...in this case appending the new coordinates each time.

from kivy.lang import Builder
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.accordion import *
from kivy.properties import *
from kivy.app import App

Builder.load_string('''
<MouseWidget>:
    image: image
    label: label
    orientation: 'vertical'
    Image:
        id: image
        source: root.source

    Label:
        id: label
        size_hint_y: None
        height: 50
        text: 'Hello World'
''')

class Test(TextInput):


    def on_double_tap(self):
        # make sure it performs it's original function
        super(Test, self).on_double_tap()

        def on_word_selection(*l):
            selected_word = self.selection_text
            print selected_word

        # let the word be selected wait for
        # next frame and get the selected word
        Clock.schedule_once(on_word_selection)

class MouseWidget(BoxLayout): 
    image = ObjectProperty()
    label = ObjectProperty()
    source = StringProperty()
    textinput = ObjectProperty()

    def on_touch_down(self, touch):

        if self.image.collide_point(*touch.pos):
            self.label.text = str(touch.pos)

    def on_touch_up(self, touch):
        self.label.text = 'Hello World'
        if self.textinput is not None:
            self.textinput.text += ' ... and {}'.format(touch.pos)

class AccordianApp(App):
    def build(self):
        root = Accordion(orientation='horizontal')

        item= AccordionItem(title='Page One')
        src = "image.png"
        image = MouseWidget(source=src, size_hint = (1.0, 1.0))

        textinput = Test(text='Testing', size_hint = (0.5, 1.0))
        image.textinput = textinput

        # add image to AccordionItem
        item.add_widget(image)
        item.add_widget(textinput)
        root.add_widget(item)

        return root

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

This isn't the only way to do it - there are lots of ways you could make that reference available, and different ones might be useful in different situations. For instance, you could make another widget containing both your mousewidget and the textinput, and write all the bindings in kv language.

Another trick that can be useful for unrelated widgets (where it isn't easy to pass a reference between them) is to store the reference in your App class. You can do something like

class AccordianApp(App):
    some_thing = ObjectProperty()
    ...

This is useful because you can always access the app with App.get_running_app(), so even if you have disconnected widgets and can't see how they might communicate, you could store the textinput at app level so anything can easily get at it.

I hope that's clear...I only mean to say, there are several possibilities that might suit different situations. For your particular problem, you can just store a reference to the textinput in the mousewidget, or some similar simple solution.

Upvotes: 1

Related Questions