How can I make a TextInput in a python GUI app built with kivy that's read-only, but where the user can still select all of the text with crtl+a?
Consider the following simplified example program with a TextInput containing over 9000 characters
import random
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
class MyApp(App):
def build(self):
layout = BoxLayout()
# generate some random ASCII content
textinput_contents = ''.join( [chr( random.randint(32,127) ) for i in range(0,9001)] )
# add the textinput
self.textinput1 = TextInput(
text=textinput_contents,
readonly=True
)
layout.add_widget(self.textinput1)
return layout
if __name__ == "__main__":
MyApp().run()
I don't want the user to be able to edit the contents of the TextInput, but I do want them to be able to click around, select text, copy from it, etc. Unfortunaetly, in the above example, typing ctrl+a (for the Select All shortcut) does nothing.
However, if I omit the readonly attribute, then ctrl+a works again!
import random
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
class MyApp(App):
def build(self):
layout = BoxLayout()
# generate some random ASCII content
textinput_contents = ''.join( [chr( random.randint(32,127) ) for i in range(0,9001)] )
# add the textinput
self.textinput1 = TextInput(
text=textinput_contents
)
layout.add_widget(self.textinput1)
return layout
if __name__ == "__main__":
MyApp().run()
How can I make the kivy TextInput read-only without disabling Select-All (ctrl+a)?
Related
I'm trying to create a user-interface for a personal assistant.
I want the user to input a text and when he presses enter,i want to do something(' say print a text') and also automatically clear the input field.
This is my code:
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
class TetraApp(App):
def build(self):
Window.size=(875,600)
Window.clearcolor = (0, 1, 1, 1)
b = BoxLayout(orientation ='vertical')
self.t = TextInput(hint_text='Say Something...', size_hint=(1,0.1), multiline=False)
#the multiline disables on enter. i want it to do a process on enter.
b.add_widget(self.t)
# code here to go to enterClicked() when enter is pressed and to clear input field
Window.borderless=True
return b
def enterClicked(self):
if 'hello' in self.t.text:
print("hello user")
if __name__=='__main__':
app=TetraApp()
app.run()
I couldnt find any tutorials for this.
You can try to bind an action to your TextInput like this:
self.t = TextInput(hint_text='Say Something...', size_hint=(1,0.1),multiline=False)
self.t.bind(on_text_validate=self.enterClicked)
b.add_widget(self.t)
def enterClicked(self,t):
if 'hello' in self.t.text:
print("hello user")
self.t.text=''
The on_text_validate action is triggered only in multiline=False mode when the user hits ‘enter’.
To clear the input field, try to make a method that clears the text (similar to your enterClicked) and bind this method as well to the TextInput with on_text_validate. Let me know if it worked.
I'm trying to use kivy for my project but I can't deal with it well..
I made a button, but I want that when I press him it will create another (new) button. Thanks a lot!
from kivy.app import App
from kivy.lang import builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.widget import Widget
from kivy.uix.button import Button
def createButton():
b = Button(pos=(0, 90), size_hint=(.2, .2), on_press=lambda a:ad())
return b
def ad():
"crate new button here!"
class NoobApp(App):
def build(self):
return createButton()
if __name__ == '__main__':
NoobApp().run()
In your ad() method add a line to create a Button and add it to the root of the app:
def ad():
print("crate new button here!")
App.get_running_app().root.add_widget(Button(text='hi'))
Note that this is adding a Button to a Button, (the root of the app is the original Button). Not a recommended approach. You should probably return some kind of Layout from your build() method instead.
I have unfortuanlly have encourtered an error in kivy and Python 3. I have not found a soultion via Google. I wanted to get text input at the very least but it does not show up. Just the text itself. Thank you for your time!
import kivy
kivy.require('1.10.1') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
class ColdKivyApp(App):
def build(self):
f = FloatLayout()
label = Label(text="Cold") #I acutally orginally called it Zone unitil I changed it into Cold cause it's really cold now
f.add_widget(label)
txt = TextInput(text='', focus=True, multiline=True, cursor_blink=True, background_color=(1,1,1,1))
f.add_widget(txt)
return f
if __name__ == '__main__':
ColdKivyApp().run()
It seems that there is a bug in TextInput when setting the focus in the constructor, a workaround is to set the focus an instant after the window is shown through Clock:
import kivy
kivy.require('1.10.1') # replace with your current kivy version !
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.clock import Clock
class ColdKivyApp(App):
def build(self):
f = FloatLayout()
label = Label(text="Cold")
f.add_widget(label)
txt = TextInput(multiline=True, cursor_blink=True, background_color=(1,1,1,1))
f.add_widget(txt)
Clock.schedule_once(lambda *args: setattr(txt, "focus", True))
return f
if __name__ == '__main__':
ColdKivyApp().run()
Using this code:
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
class Main(App):
def build(self):
root = FloatLayout(size=(100, 100))
root.add_widget(TextInput(pos=(0, 0)))
root.add_widget(TextInput(pos=(50, 50)))
return root
if __name__ == '__main__':
Main().run()
I get two TextInputs, one on top of the other. When I click on the top TextInput (by clicking somewhere in the middle of the screen), the focus goes to the lower TextInput for some reason. In fact, the only way I can get focus on the top TextInput is by clicking entirely outside of the lower TextInput (by clicking right at the top of the screen). Why does this happen, and how can I circumvent this?
Your problem can be approached in two ways.Float layout honors the pos_hint and the size_hint properties of its children.So you need to set size_hint for textinput.
ie-
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
class Main(App):
def build(self):
root = FloatLayout(size=(100, 100))
root.add_widget(TextInput(pos=(0, 0),size_hint=(0.5,0.5)))
root.add_widget(TextInput(pos=(100, 100),size_hint=(0.5,0.5)))
return root
if __name__ == '__main__':
Main().run()
or use boxlayout instead of floatlayout
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
class Main(App):
def build(self):
root = BoxLayout(size=(100, 100))
root.add_widget(TextInput(pos=(0, 0)))
root.add_widget(TextInput(pos=(50, 50)))
return root
if __name__ == '__main__':
Main().run()
I don't have any idea to find a solution of my problem.
I have make an application with Carousel Widget. In this Carousel I have 4 slides.
welcomeSlide -> DVDSlide -> DVDPretSlide --> CategorySlide
I have make a class for each slides.
I use a ListAdpter to display the data extracted from an Sqlite3 Database.
My pblem is about the refresh of the list, when I modify a DVD (add name to pret) in the DVDSlide, when I slide to the DVDPret, the DVD do not appears because the List is not refresh.
Like the doccumentation for the carousel I don't find the event when slide change. It will be the best if an event exist to get the current slide index.
Have you got any Idea ?
Thanks,
You can observe index property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
Label:
text: str(id(root))
<Carousel>
on_index: print("slide #{}".format(args[1]))
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
Or you can observe current_slide property:
from kivy.uix.carousel import Carousel
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
Builder.load_string('''
<Page>:
label_id: label_id
Label:
id: label_id
text: str(id(root))
<Carousel>
on_current_slide: print(args[1].label_id.text)
''')
class Page(BoxLayout):
pass
class TestApp(App):
def build(self):
root = Carousel()
for x in range(10):
root.add_widget(Page())
return root
if __name__ == '__main__':
TestApp().run()
If you want a pure python solution rather than a Kivy Language solution you can create your own carousel that inherits from the Kivy carousel as follows.
import kivy
from kivy.uix.carousel import Carousel
class MyCarousel(Carousel):
# This class is a carousel that runs script
# when a slide gets focus (except first load).
def on_index(self, *args):
print('the slide is', self.index)
# YOUR CODE GOES HERE
Carousel.on_index(self, *args)