How to dynamically update markup text in kivy modalview - python

I am trying to update a label field dynamically from the contents of a TextInput in a ModalView. The idea is that in the TextInput one enters plain text including markup formatting and you will see the results directly in the Label field with markup = True.
Unfortunately I do not know how to access the Label item in the ModalView. Who can help? See the example code below.
Thanks in advance.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.modalview import ModalView
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.properties import ObjectProperty, StringProperty
kv = """
<Test>:
canvas:
Color:
rgba: 0.4, 0.5, 0.6, 1
Rectangle:
size: self.size
pos: self.pos
Button:
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'Edit'
on_press: root.showedit()
"""
Builder.load_string(kv)
class Test(BoxLayout):
minput_text = StringProperty('Welcome')
txtresult = ObjectProperty()
def showedit(self):
mview = ModalView(id='mviewid', size_hint=(0.4, 0.6), auto_dismiss=False, background='./images/noimage.png')
mblt = BoxLayout(orientation='vertical', padding=(24))
minp = TextInput(id='inptxt', text='', hint_text='Start typing text with markup here', size_hint=(1,0.5),multiline=True)
minp.bind(text=self.on_inptext)
mtxt = Label(id='txtresult',text='displays formatted text', color=(0.3,0.3,0.3), size_hint=(1,0.5),markup=True)
mcnf = Button(text='OK', size=(144,48), size_hint=(None,None))
mcnf.bind(on_press=mview.dismiss)
mblt.add_widget(minp)
mblt.add_widget(mtxt)
mblt.add_widget(mcnf)
mview.add_widget(mblt)
mview.bind(on_dismiss=self.print_text)
mview.open()
def on_inptext(self, instance, value):
self.minput_text = value
def print_text(self, *args):
print self.minput_text
class TestApp(App):
def build(self):
return Test()
if __name__ == '__main__':
TestApp().run()

You have to make a binding between the TextIntput text and the Label, for this we can use a lambda function and setattr.
class Test(BoxLayout):
minput_text = StringProperty('Welcome')
txtresult = ObjectProperty()
def showedit(self):
mview = ModalView(id='mviewid', size_hint=(0.4, 0.6), auto_dismiss=False, background='./images/noimage.png')
mblt = BoxLayout(orientation='vertical', padding=(24))
minp = TextInput(id='inptxt', text='', hint_text='Start typing text with markup here', size_hint=(1,0.5),multiline=True)
minp.bind(text=self.on_inptext)
mtxt = Label(id='txtresult',text='displays formatted text', color=(0.3,0.3,0.3), size_hint=(1,0.5),markup=True)
mcnf = Button(text='OK', size=(144,48), size_hint=(None,None))
mcnf.bind(on_press=mview.dismiss)
mblt.add_widget(minp)
mblt.add_widget(mtxt)
mblt.add_widget(mcnf)
mview.add_widget(mblt)
mview.bind(on_dismiss=self.print_text)
# binding between TextInput text and Label text
minp.bind(text=lambda instance, value: setattr(mtxt, 'text',value))
mview.open()
def on_inptext(self, instance, value):
self.minput_text = value
def print_text(self, *args):
print(self.minput_text)

Related

How to change a bg of ScrollView in my code and print the text on it?

My program parses the site at the click of a button and displays the text of the book on the user's screen. But since I'm a beginner, I can't find the ScrollView argument that would repaint it in the color I want. Maybe I'm doing something wrong, I would be glad if someone could tell me how to display the text on the screen ScrollView, which is not black!
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from bs4 import BeautifulSoup
from kivy.uix.scrollview import ScrollView
import requests
class MyButton(Button):
color = (0, 0, 0, 1)
valign = 'bottom'
padding_y = 10
background_color = (.93, .91, .67, 1)
background_normal = ''
class Box(BoxLayout):
orientation = "vertical"
padding = [5,5,5,5]
spacing = 10
def on_kv_post(self, widget):
self.add_widget(MyButton(text='И. С. Тургенев. «Отцы и дети»', on_press=self.btn_press))
def btn_press(self, instance):
self.clear_widgets()
sc = ScrollView()
x = 1
data = ''
while True:
if x == 1:
url = "http://loveread.ec/read_book.php?id=12021&p=1"
elif x < 4:
url = "http://loveread.ec/read_book.php?id=12021&p=" + f'{x}'
else:
break
request = requests.get(url)
soup = BeautifulSoup(request.text, "html.parser")
teme = soup.find_all("p", class_="MsoNormal")
for temes in teme:
data += temes.text
x = x + 1
sc.add_widget(Label(text=f'{data}',color = (1,1,1,1)))
self.add_widget(sc)
class MyApp(App):
def build(self):
return Box()
if __name__ == "__main__":
MyApp().run()
You need your Label to adjust according to its text. The easiest way to do that is by using the kivy language. Here is one way to do it:
Add a new class MyLabel:
class MyLabel(Label):
pass
Use the new class in your python:
sc.add_widget(MyLabel(text=f'{data}',color = (1,1,1,1)))
Add use the kivy language to define the new class:
class MyApp(App):
def build(self):
Builder.load_string('''
<MyLabel>:
size_hint: 1, None
text_size: self.width, None
height: self.texture_size[1]
''')
return Box()

Kivy: how to access IDs created in python code

I have this code below. I've set id by python code, but I couldn't access.
def abrirReceita(self,instance):
instance.text = str(instance.ids)
I'd like to change the text with the number of the ID when I press.
Exemple: if I input the first button, change the text for '1', which is the ID I've passed.
from kivymd.app import MDApp
from kivymd.uix.boxlayout import BoxLayout
from kivymd.uix.floatlayout import FloatLayout
from kivymd.uix.list import TwoLineListItem
from kivymd.uix.textfield import MDTextField
from kivy.lang import Builder
import os
from kivy.core.window import Window
import sqlite3
KV = '''
ScreenManager:
Screen:
name: 'telaSelecionada'
BoxLayout:
orientation: 'vertical'
MDToolbar:
id: tb
title: 'Drinks'
md_bg_color: 0, 0, 0, 1
TelaSelecionada:
id: telaselecionada
<TelaSelecionada>:
ScrollView:
MDList:
id: mostraReceita
padding: '20dp'
'''
Window.softinput_mode = "below_target"
class TelaSelecionada(FloatLayout):
pass
class Aplicativo(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
i = 1
for x in range(5):
self.textLine = TwoLineListItem(text = 'change text', secondary_text = 'change text')
self.root.ids.telaselecionada.ids.mostraReceita.add_widget(self.textLine)
self.root.ids.telaselecionada.ids.mostraReceita.ids[i] = self.textLine
self.textLine.bind(on_release = self.abrirReceita)
i += 1
def abrirReceita(self,instance):
instance.text = str(instance.ids)
Aplicativo().run()
How do I access the IDs from python code?
I'd like to change the text with the number of the ID when I press.
Just pass the required args through method abrirReceita using functools.partial as,
def on_start(self):
...
self.textLine.bind(on_release = partial(self.abrirReceita, i))
i += 1
# Then in `abrirReceita` :
def abrirReceita(self, id_index, instance):
instance.text = str(id_index)
Note:
The ids are not used here at all (actually you don't need that here for this purpose) !
Update:
As, the Widget.id has been deprecated since version 2.0.0 you should use it only in kvlang not in python.
But that doesn't keep you from creating it as a dynamically added attribute. Thus you can do something like this (I modified the on_start method a little):
def on_start(self):
mostraReceita = self.root.ids.telaselecionada.ids.mostraReceita
for i, _ in enumerate(range(5), start=1):
# Or just,
# for i in range(1, 5+1):
self.textLine = TwoLineListItem(
text = 'change text',
secondary_text = 'change text',
)
self.textLine.index = i
# Or even,
# self.textLine.id = i
self.textLine.bind(on_release = self.abrirReceita)
mostraReceita.add_widget(self.textLine)
def abrirReceita(self,instance):
instance.text = str(instance.index) # or, str(instance.id)

displaying a variable in a popup window with kivy

I am trying to make a program that reads the dictionary after the user inputs their name and assigns a random selection based on weighted values in the dictionary. As of now the logic for selecting a random value from the dictionary is working but I have it printing to the console. I would like it to appear in a popup window (which i have but cannot get the output variable to show up there)
four.kv
WindowManager:
MainWindow:
<MainWindow>:
name:'main'
player_python:player_kv
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text:'Player:'
TextInput:
id: player_kv
multiline: False
Button:
text: 'Random'
on_press: root.btn()
<P>:
output:output
FloatLayout:
Label:
id: output
main4.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
import random
#from Dict import *
#### example dictionary
character = {
'John':
{'Water': 2, #50%
'Fire': 1, #25%
'Earth': 1,}, #25%
'Bill':
{'Water': 1, #25%
'Fire': 2, #50%
'Earth': 1,}} #25%
####
class MainWindow(Screen):
player_python = ObjectProperty(None)
output = StringProperty('')
def btn(self):
show_popup()
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
class P(FloatLayout):
pass
def show_popup():
show = P()
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('four.kv')
class FourApp(App):
def build(self):
return kv
if __name__ == '__main__':
FourApp().run()
https://gist.github.com/PatrickToole/00cc72cdd7ff5146976e5d92baad8e02
Thanks in advance
-P
I haven't tested this code, but try passing self.output to your show_popup() method. This would mean changing your btn() method to something like:
def btn(self):
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
show_popup(self.output)
And in the show_popup() method:
def show_popup(output):
show = P()
show.output.text = output
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
As I mentioned, I haven't tested this code, but something like this should work.

Catch value from listitembutton to textinput kivy/python

I created a mobile app. Once a user clicks on 1 element on the list I need the text to go into another text-input
My kv file
#:import main main
#:import ListAdapter kivy.adapters.listadapter.ListAdapter
#:import ListItemButton kivy.uix.listview.ListItemButton
<LocationButton>:
deselected_color:0.4, 1, 1,1
selected_color: 0, 0, 1, 1
size: (100, '48dp')
on_press:root.test()
<ecran1>:
nom_du_produit:le_produit
FloatLayout:
ListView:
id:liste_des_produits
size_hint:.5,.8
pos_hint:{'x':.25,'y':.0}
adapter:
ListAdapter(data=root.L,cls=main.LocationButton)
TextInput:
id:le_produit
text:''
font_size:20
size_hint:.2,.1
pos_hint:{'x':.78,'y':.75}
background_color:1,1,1,1
multiline:False
My python code
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen,ScreenManager,WipeTransition
from kivy.properties import ObjectProperty,StringProperty,ListProperty
from kivy.uix.listview import ListItemButton
class ecran1(Screen):
L=ListProperty(['tomate','abricot'])
nom_du_produit = ObjectProperty()
class LocationButton(ListItemButton):
L = ListProperty(['tomate', 'abricot'])
nom_du_produit = ObjectProperty()
def test(self):
selection_1 = self.liste.adapter.selection[0].text
self.nom_du_produit.text = selection_1
class PongApp(App):
def build(self):
return ecran1()
if __name__ == '__main__':
PongApp().run()
I tried few options but always the answer is Attribute error
Picture to better understand:This Picture
There are at least two different ways to accomplish what you want. Here is a modification of your test method that shows both:
def test(self):
#App.get_running_app().root.nom_du_produit.text = self.text # uses the ObjectProperty in the ecran1 class
App.get_running_app().root.ids.le_produit.text = self.text # uses the le_produit id in the TextInput class

"AttributeError: 'NoneType' object has no attribute 'bind' " after using FlatButton in kv file

I'm trying to implement FlatButton in my kv but I keep getting the same error that is AttributeError: 'NoneType' object has no attribute 'bind. It works fine with Button alone.
from flat_kivy.flatapp import FlatApp
from kivy.uix.touchripple import TouchRippleBehavior
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import (StringProperty, NumericProperty, ObjectProperty,
ListProperty, DictProperty, BooleanProperty)
class Login(Screen):
pass
class MainScreen(Screen):
pass
class ScreenManager(ScreenManager):
pass
theRoot = Builder.load_string('''
ScreenManager:
Login:
<Login>:
FlatButton:
text: 'Click Here'
size_hint: (.4,.25)
''')
class TouchRippleApp(FlatApp):
def build(self):
return theRoot
if __name__ == '__main__':
TouchRippleApp().run()
This is the FlatButton code in Flat_Kivy. I'm stuck at this problem.
class FlatButtonBase(GrabBehavior, LogBehavior, TouchRippleBehavior,
ThemeBehavior):
color = ListProperty([1., 1., 1.])
color_down = ListProperty([.7, .7, .7])
border_size = ListProperty([0, 0, 0, 0])
text = StringProperty('')
alpha = NumericProperty(1.0)
style = StringProperty(None, allownone=True)
color_tuple = ListProperty(['Grey', '500'])
font_color_tuple = ListProperty(['Grey', '1000'])
ripple_color_tuple = ListProperty(['Grey', '1000'])
font_ramp_tuple = ListProperty(None)
font_size = NumericProperty(12)
eat_touch = BooleanProperty(False)
def on_color(self, instance, value):
self.color_down = [x*.7 for x in value]
class FlatButton(FlatButtonBase, ButtonBehavior, AnchorLayout):
pass
class RaisedFlatButton(RaisedStyle, FlatButton):
pass
Perhaps an easier way to do this altogether is create your FlatButton class in the .kv language (inside your string you're loading with Builder.load_string)
Try adding this to your kv string:
<FlatButton#Button>: # create a class "FlatButton" that inherits the kivy Button
background_normal: "" # Get rid of the kivy Button's default background image
background_down: "" # Get rid of the kivy Button's default background image when clicked
# Set the background color to transparent if no action is happening to the button
# If the button is clicked, it will change it to fully white
background_color: (1,1,1,0) if self.state == 'normal' else (1,1,1,1)
and then you can remove all the code relating to your FlatButton class on the python side, with the exception of creating a base class for the kv to work with. E.g. all you need in the python code is
class FlatButton():
pass

Categories

Resources