Suppose a Label widget has a text 'abcd[', it prints out the correct thing on the output screen as expected. But when I set the markup for that Label widget to True, it prints out 'abcd[[/color]'. How do I overcome this? I found out one possible fix by adding '\n' after the opening bracket in the text. But since I have many widgets in a row close to each other, the newline is pretty visible and it looks kinda ugly.
For this example, I'm using Button instead of Label.
This is the output for
Button:
markup: True
text: 'abcd\n['
And this is the output for
Button:
markup: True
text: 'abcd\n[\n'
As I said, adding a newline makes it look ugly and the difference in text level between the nearby widgets look very visible.
This can be solved by using escape_markup or replacing '[' with '&bl;'.
Method 1: Using the escape_markup.
from kivy.app import App
from kivy.lang import Builder
kv = ('''
#:import escape kivy.utils.escape_markup
Label:
markup: True
text: 'abcd{}'.format(escape('['))
''')
class mainApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
mainApp().run()
Method 2: Character replacement.
from kivy.app import App
from kivy.lang import Builder
kv = ('''
#:import escape kivy.utils.escape_markup
Label:
markup: True
text: 'abcd&bl;'
''')
class mainApp(App):
def build(self):
return Builder.load_string(kv)
if __name__ == '__main__':
mainApp().run()
Now, if you want to change color of '[' you have to do it like this:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.properties import StringProperty
kv = (
'''
#:import escape kivy.utils.escape_markup
<L>:
markup: True
text: self.hidden_text
<B>:
Button:
text: 'press'
on_press: root.lel()
L:
id: lol
hidden_text: 'abcd{}'.format(escape('['))
markup: True
B
'''
)
class L(Label):
hidden_text = StringProperty('')
class B(BoxLayout):
def lel(self):
self.ids.lol.text = '{}[color=#E5D209]{}[/color]'.format(self.ids.lol.hidden_text[:4], self.ids.lol.hidden_text[4:])
class color(App):
def build(self):
return Builder.load_string(kv)
if __name__ == "__main__":
color().run()
Notice what I did in lel() in B class. To change to color of '[', I typed hidden_text[4:] instead of hidden_text[4]. This is because when you do escape('['), all it does is it replaces '[' by '&bl;'. So, when you use hidden_text[4], you'll get this output:
But if you use hidden_text[4:], it covers the characters after & until it reaches the semi-colon.
To know why I used StringProperty on the Label's text, read here.
Related
I am trying to add buttons dynamically when some text is typed on a text input. In order to achieve search select combo box in KIvy.
Even though i am able to add widgets when some text is typed , not able to remove those added widgets when the text typed is removed.
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix import dropdown
from kivy.uix.textinput import TextInput
# from kivymd.app import MDApp
kivy.require('1.9.0')
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.base import runTouchApp
from kivy.uix.screenmanager import ScreenManager,Screen
class ScreenOne(Screen):
def change_text(self,root,val):
pass
def create_dropdown(self,root,value):
print("value is :" + value)
if value == "":
result = ""
print(root.ids)
else:
lang = ["aa","aaa", "bsa","cds","dds", "ddyus"]
result = list(filter(lambda x: x.startswith(value), lang))
for i in range (0,len(result)):
self.textinput = Button()
self.textinput.id = 'textinput'+ str(i)
self.textinput.text = result[i]
self.textinput.size_hint= (.3, .06)
self.textinput.font_size= '14sp'
self.textinput.pos_hint= {'center_x': 0.5, 'center_y': 0.8-(i+1)/10, }
root.ids.screen1.add_widget(self.textinput)
sm = Builder.load_string("""
ScreenManager:
ScreenOne:
id: screen1
name: "screen_one"
TextInput:
id: input1
hint_text:'Select input Language'
size_hint: (.3,.06)
font_size: '14sp'
pos_hint:{'center_x':0.5,'center_y':0.8,}
on_text: root.ids.screen1.create_dropdown(root,input1.text)
""")
class demo(App):
def build(self):
return sm
app=demo()
# app.run()
runTouchApp(sm)
in UI when a is typed cahn see the below image
but when i clear the input text , i am still able to see the widgets added previously
I neet some logic to remove the added widgets when the text typed in input box is cleared.
Try adding this:
result = list(filter(lambda x: x.startswith(value), #from your cod
lang)) #from your code
if result == [] :
for widget in root.ids.screen1.children:
root.ids.screen1.remove_widget(widget)
I was just trying to make a small hello world program as given below. Why nothing gets displayed.
# File: main.py
from kivy.app import App
from kivy.lang import Builder
from kivy.base import runTouchApp
KV = '''
# File: clock.kv
<aClock#BoxLayout>:
orientation: 'vertical'
Label:
color: 1,0,1,1
text: '00:00:00'
<myClock> :
aClock:
'''
class myClock(App):
pass
if __name__ == '__main__':
Builder.load_string(KV)
myClock().run()
from kivy.app import App
from kivy.lang import Builder
KV = '''
<AClock#BoxLayout>:
orientation: 'vertical'
Label:
color: 1,0,1,1
text: '00:00:00'
AClock: # This is going to be the return value of Builder.load_string()
'''
class MyClock(App):
def build(self):
return Builder.load_string(KV)
if __name__ == '__main__':
MyClock().run()
App is not a widget, so you can't do this:
<myClock> :
aClock:
And in Kivy, PEP8 is constraint rather than style. All widgtes' class name must starts with upper case. So aClock must be AClock.
And you should implement build() and make it return a widget. (There is a case that build() doesn't have to return a widget, though.)
separating into two files
# myclock.kv
<AClock#BoxLayout>:
orientation: 'vertical'
Label:
color: 1,0,1,1
text: '00:00:00'
AClock:
# main.py
from kivy.app import App
class MyClock(App):
pass
if __name__ == '__main__':
MyClock().run()
I am trying to implement a scrolling label in a Kivy program, and found this example (slightly modified) that works:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
from kivy.lang import Builder
long_text = "".join(["this is a long line "+str(n)+"\n" for n in range(1,101)])
Builder.load_string('''
<ScrollableLabel>:
Label:
size_hint_y: None
height: self.texture_size[1]
text_size: self.width, None
text: root.text
''')
class ScrollableLabel(ScrollView):
text = StringProperty('')
class ScrollApp(App):
def build(self):
return ScrollableLabel(text=long_text)
if __name__ == "__main__":
ScrollApp().run()
Partly for my own education, I am trying to convert this sample to not use Builder (and not resort to a .kv file). I have modified the above example to:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
long_text = "".join(["this is a long line "+str(n)+"\n" for n in range(1,101)])
class ScrollableLabel(ScrollView):
text = StringProperty('')
def __init__(self, **kwargs):
super(ScrollableLabel, self).__init__(**kwargs)
self.label = Label(size_hint_y=None, text=self.text)
self.label.height = self.label.texture_size[1]
self.label.text_size = (self.label.width, None)
self.add_widget(self.label)
class ScrollApp(App):
def build(self):
return ScrollableLabel(text=long_text)
if __name__ == "__main__":
ScrollApp().run()
To my obviously untutored eye, these programs look like they should be equivalent. However, my (second) version doesn't work correctly (on several fronts).
So my question is two-fold: why doesn't the second version work the same as the first, and (if the answer isn't obvious from the first), how can I make it do so?
Thanks! -David
Try this:
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty
from kivy.clock import Clock
long_text = "".join(["this is a long line "+str(n)+"\n" for n in range(1,101)])
class ScrollableLabel(ScrollView):
text = StringProperty('')
def __init__(self, **kwargs):
super(ScrollableLabel, self).__init__(**kwargs)
self.label = Label(size_hint_y=None, text=self.text)
self.add_widget(self.label)
Clock.schedule_once(self.update, 1)
def update(self, *args):
self.label.text_size = (self.label.width, None)
self.label.height = self.label.texture_size[1]
class ScrollApp(App):
def build(self):
return ScrollableLabel(text=long_text)
if __name__ == "__main__":
ScrollApp().run()
the output now is the same as your first
I just want to have 2 buttons in my KIVY APP.
One with text "Hello" and other having a random number from 0-9.
My code
#!/usr/bin/kivy
import kivy
kivy.require('1.7.2')
from random import random
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from random import random
Builder.load_string("""
<Highest>:
r1c1: "hello"
r1c2: random.randrange(10)
GridLayout:
cols: 1
Button:
text: root.r1c1
Button:
text: root.r1c2
""")
class Highest(Screen):
pass
# Create the screen manager
sm = ScreenManager()
sm.add_widget(Highest(name='Highest'))
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
My code works if I just have one button with text - Hello. Random seems not working.
Perhaps it's because randrange isn't returning a string, but an int. You could try:
r1c2: str(random.randrange(10))
OR
Try adding it as a function to your root widget:
class Highest(Screen):
def get_rand(self):
return str(random.randrange(10))
And your kv would look like this:
r1c2: root.get_rand()
How to create simple Kivy app?
If user type text into field "Name" using keyboard like on android
phone, this name is display
I need this to learn
Here's as simple an example as i can figure out.
Here's the KVLANG code.
<LblTxt#BoxLayout>:
orientation: 'horizontal'
lblTxtIn: 'default'
theTxt: iAmTxt
Label:
text: root.lblTxtIn
TextInput:
id: iAmTxt
text: 'txt'
<MyLayout#BoxLayout>:
orientation: 'vertical'
LblTxt:
id: lt0
lblTxtIn: 'LblTxtInput0'
LblTxt:
id: lt1
lblTxtIn: 'LblTxtInput1'
LblTxt:
id: lt2
lblTxtIn: 'LblTxtInput2'
Button:
text: 'print LblTxtInput [0, 1, 2]'
on_release: print lt0.theTxt.text, lt1.theTxt.text, lt2.theTxt.text
MyLayout
Here's the Python code.
import kivy
kivy.require('1.8.0') # replace with your current kivy version !
from kivy.app import App
from kivy.lang import Builder
from kivy.config import Config
from kivy.core.window import Window
Window.size = (400,130)
from kivy.uix.boxlayout import BoxLayout
class LblTxt(BoxLayout):
from kivy.properties import ObjectProperty
theTxt = ObjectProperty(None)
class MyApp(App):
def build(self):
self.root = Builder.load_file('simpleForm.kv')
return self.root
if __name__ == '__main__':
MyApp().run()
Here's a run screenshot. It will print a b c to the command line when the 'print LblTxtInput [0, 1, 2]' button is released.
I hope this helps you out.