'Storing selection of TextInput when not is focus (Kivy)

I have a TextInput and a button, and my aim is to be able to select some text from the TextInput and then push a button which calls a function that prints: selection_text, selection_to, and selection_from.

However, because the TextInput is not in focus when the button is pushed, the selection is lost and the function returns nothing AND/OR incorrect values.

I have seen this line of code in similar questions but I have not been able to figure out what it is meant to do, via messing with the code or looking at the TextInput docs, since I have only seen it called from within an 'on_focus' function

Clock.schedule_once(lambda dt: new_post_input.selection_text)

I have not been able to recreate the issue in an example program yet since it works when I have taken the widgets into their own program

main.py

from kivy.app import App
from kivy.properties import BooleanProperty, StringProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.modules import inspector
from kivy.core.window import Window


class NewPost(FloatLayout):
    buttons_disabled = BooleanProperty(False)
    cancle_button_disabled = BooleanProperty(True)
    preview_text = StringProperty()
    def make_bold(self, new_post_input, selected):
        print('Selected = ' + selected)
        print('Button has been pushed')

    def preview_post(self, Button, cancleButton, TextInput, Label):
        #self.preview_text = ('Hello\n' + TextInput.text)
        self.buttons_disabled = True
        self.cancle_button_disabled = False
        Label.opacity = 1
        Label.pos_hint = {'center_x': 0.5, 'center_y': 0.5}
        TextInput.opacity = 0
        cancleButton.opacity = 1
        cancleButton.pos_hint = {'center_x': 0.5, 'center_y': 0.5}
        Button.opacity = 0
        Button.pos_hint = {'center_x': 0.5, 'center_y': -1}
        #print(TextInput.text)

    def back_from_preview(self, Button, previewButton, TextInput, Label):
        self.buttons_disable = False
        self.cancle_button_disabled = True
        Label.opacity = 0
        Label.pos_hint = {'center_x': 0.5, 'center_y': -1}
        TextInput.opacity = 1
        Button.opacity = 0
        Button.pos_hint = {'center_x': 0.5, 'center_y': -1}
        previewButton.opacity = 1
        previewButton.pos_hint = {'center_x': 0.5, 'center_y': 0.5}

class SelectionApp(App):
    def build(self):
        inspector.create_inspector(Window, SelectionApp)


SelectionApp().run()

selection.kv

PageLayout:
    Label:
        text: 'Swipe to the next page'
        font_size: dp(50)
    Label:
        text: 'And again'
        canvas.before:
            Color:
                rgba: (0,.8,.8,1)
            RoundedRectangle:
                size: self.size
                radius: [dp(6),]
                pos: self.x, self.y    
    NewPost:
        id: new_post
        canvas.after:
            Color:
                rgba: 0,1,0,1
            Line:
                width: dp(1.6)
                rounded_rectangle:(self.x, self.y, self.width, self.height, dp(5))
        BoxLayout:
            id: main_new_post
            orientation: 'vertical'
            padding: '10dp', '16dp'
            pos_hint: {'center_x': 0.5, 'center_y': 0.5}
            canvas.before:
                Color:
                    rgba: 0, 0, 0, 1
                Rectangle:
                    pos: self.pos
                    size: self.size
            AnchorLayout:
                size_hint: 1, .05
                anchor_x: 'right'
                anchor_y: 'center'
                Label:
                    text: 'New Post'
                    size_hint: None, None
                    size: '100dp', '30dp'
                    color: .8, 0, 0, 1
                    font_size: '16dp'
                    #pos_hint: {'center_x': 0.8, 'center_y': 0.5}
            Label:
                size_hint: 1, .035
                text: ''
                font_size: '1dp'
            BoxLayout:
                orientation: 'vertical'
                padding: '10dp', 0
                size_hint: 1, .38
                FloatLayout:
                    TextInput:
                        id: new_post_input
                        #disabled: new_post.buttons_disabled
                        opacity: 1
                        background_color: 0, 0, 0, 1
                        foreground_color: 1, 1, 1, 1
                        background_disable_normal: True
                        multiline: True
                        font_size: '15dp'
                        padding: '10dp', '10dp'
                        selection_color: (.8, 0, 0, .5)
                        pos_hint: {'center_x': 0.5, 'center_y': 0.5}
                        allow_copy: True
                        #on_focus: new_post.on_focus(self)
                        canvas.after:
                            Color:
                                rgba: 1,1,1,1
                            Line:
                                width: dp(1.6)
                                rounded_rectangle:(self.x, self.y, self.width, self.height, dp(5))
                    BoxLayout:
                        orientation: 'vertical'
                        id: preview_new_post_label
                        opacity: 0
                        pos_hint: {'center_x': 0.5, 'center_y': -1}
                        canvas.before:
                            Color:
                                rgba: (.8,.8,.8,1)
                            RoundedRectangle:
                                size: self.size
                                radius: [dp(6),]
                                pos: self.x, self.y
                        canvas:
                            Color:
                                rgba:0.8,0,0,1
                            Line:
                                width: dp(1.6)
                                rounded_rectangle:(self.x,self.y,self.width,self.height, dp(5))
                        ScrollView:
                            always_overscroll: False
                            bar_color: (0,0,0,0)
                            Label:
                                text: ('Someone:\n' + new_post_input.text)
                                padding: "10dp", "12dp"
                                size_hint: None, None
                                height: self.texture_size[1]
                                width: self.parent.width
                                font_size: "12dp"
                                text_size: self.width, None
                                color: 0,0,0,1
                                multiline: True
                                markup: True
            BoxLayout:
                orientation: 'horizontal'
                size_hint: 1, .08
                padding: '10dp', 0
                AnchorLayout:
                    anchor_x: 'left'
                    anchor_y: 'center'
                    Label:
                        text: 'Text Modification'
                        font_size: '12dp'
                        size_hint: None, None
            BoxLayout:
                orientation: 'vertical'
                padding: '10dp', 0
                size_hint: 1, .12
                BoxLayout:
                    orientation: 'horizontal'
                    #padding: '10dp', 0
                    canvas.after:
                        Color:
                            rgba: 1, 1, 1, 1
                        Line:
                            width: 1.6
                            rounded_rectangle:(self.x, self.y, self.width, self.height, 5)
                    ScrollView:
                        GridLayout:
                            id: container_x
                            size_hint_x: None
                            rows: 1
                            col_default_width: dp(95)
                            width: self.minimum_width
                            spacing: dp(7)
                            Button:
                                text: "Bold"
                                font_size: '14dp'
                                color: 1, 1, 1, 1
                                background_color: .2, .2, .2, 0
                                on_press: new_post.make_bold(new_post_input, new_post_input.selection_text)
                                canvas.before:
                                    Color:
                                        rgba: (.2,.2,.2,0) if self.state=='normal' else (.3,.3,.3,1)
                                    RoundedRectangle:
                                        pos: self.pos
                                        size: self.size
                                        radius: [dp(6),]
                                canvas:
                                    Color:
                                        rgba: (1,1,1,1) if self.state=='normal' else (1,1,1,1)
                                    Line:
                                        width: dp(1.2)
                                        rounded_rectangle:(self.x,self.y,self.width,self.height, dp(6))
            BoxLayout:
                orientation: 'horizontal'
                size_hint: 1, .08
                #padding: '10dp', 0
                AnchorLayout:
                    anchor_x: 'left'
                    anchor_y: 'center'
                    Label:
                        text: 'Post Category'
                        font_size: '12dp'
                        size_hint: None, None
            BoxLayout:
                orientation: 'vertical'
                padding: '10dp', 0
                size_hint: 1, .12
                BoxLayout:
                    orientation: 'horizontal'
                    #padding: '10dp', 0
                    canvas.after:
                        Color:
                            rgba: 1, 1, 1, 1
                        Line:
                            width: 1.6
                            rounded_rectangle:(self.x, self.y, self.width, self.height, 5)
                    ScrollView:
                        GridLayout:
                            id: container_x
                            size_hint_x: None
                            rows: 1
                            col_default_width: dp(95)
                            width: self.minimum_width
                            spacing: dp(7)
                            ToggleButton:
                                text: "Opinion"
                                font_size: '14dp'
                                color: 1, 1, 1, 1
                                background_color: .2, .2, .2, 0
                                on_press: new_post.update_catagory(self, 'opinions')
                                canvas.before:
                                    Color:
                                        rgba: (.2,.2,.2,0) if self.state=='normal' else (.3,.3,.3,1)
                                    RoundedRectangle:
                                        pos: self.pos
                                        size: self.size
                                        radius: [dp(6),]
                                canvas:
                                    Color:
                                        rgba: (1,1,1,1) if self.state=='normal' else (1,1,1,1)
                                    Line:
                                        width: dp(1.2)
                                        rounded_rectangle:(self.x,self.y,self.width,self.height, dp(6))

Demo program working: YouTube link

Thank you for any suggestions/solutions :)

Update

It turns out that the selection seems to stop working when the TextInput is within a PageLayout with more than 2 pages in it, (Which it is in my program).

I have created a rough demo program to show the problem and have put it in .py and .kv



Solution 1:[1]

You can achieve that by creating a custom TextInput instance and overriding one of its method.

class MyTextInput(TextInput):
    selected_text = StringProperty("")
    # Use this prop. instead of 'selection_text'.

    def cancel_selection(self):
        self.selected_text = self.selection_text
        super().cancel_selection()

Now use this instance and the new property wherever you need.

In .kv,

                FloatLayout:
                    MyTextInput:
                        id: new_post_input
                        .
                        .
                        .
                            Button:
                                text: "Bold"
                                font_size: '14dp'
                                color: 1, 1, 1, 1
                                background_color: .2, .2, .2, 0
                                on_press: new_post.make_bold(new_post_input, new_post_input.selected_text)

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