'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 |
