Kivy Multiselect Spinner: 2nd time adding an item, spinner behaves oddly - python-3.x

Kivy 1.10.0 and using a kv file for my Kivy language.
Python 3.6
I have an app that works with mysql3. One page of the app allows me to add an 'flash card' to the database. One of the form elements when adding the flash card uses a Multiselect Spinner to add one or more tags, this data is then saved to the database. The first time I access this page, I can use the spinner and add everything as expected. Then if I go back to try to add a second flash card, even though the form is cleared and everything looks exactly as it does the first time I add a flash card, the spinner acts strangly. Data seems to be getting stored somewhere, as can be seen in the third gif, and somehow loaded back into the spinner data. (The problem is the same for the 'decks' spinner.)
This gif shows it working properly the first time I add a new card:
This gif shows the second time I add a new card (this happens regardless of what I do between adding the two cards, except quitting the app entirely):
This gif shows that data seems to be retained:
Because the code is long, I will add only what I believe relevant. If something is missing, please let me know and I'll add it right away.
class NewFlashCardScreen(Screen):
data = DictProperty({})
data_fc_tag_ids = DictProperty({})
data_fc_deck_ids = DictProperty({})
__events__ = ('on_submit',)
fc_tag_spinner_list = ListProperty(None)
fc_deck_spinner_list = ListProperty(None)
def on_parent(self, widget, parent):
gd = App.get_running_app()
self.fc_tag_spinner_list = []
fc_tag_list = Queries.get_fc_tag_list()
if len(fc_tag_list) > 0:
for fc_tag in fc_tag_list:
self.fc_tag_spinner_list.append(fc_tag[1])
self.data_fc_tag_ids[fc_tag[1]] = fc_tag[0]
else:
self.fc_tag_spinner_list.append("")
self.fc_deck_spinner_list = []
fc_deck_list = Queries.get_fc_deck_list()
if len(fc_deck_list) > 0:
for fc_deck in fc_deck_list:
self.fc_deck_spinner_list.append(fc_deck[1])
self.data_fc_deck_ids[fc_deck[1]] = fc_deck[0]
else:
self.fc_deck_spinner_list.append("")
def get_spinner_lists(self):
pass
def on_submit(self, data):
gd = App.get_running_app()
self.data['orig'] = gd.glob_dict['orig']
title = data['fc_title'] if data['fc_title'] else " "
front = data['fc_front'] if data['fc_front'] else " "
back = data['fc_back'] if data['fc_back'] else " "
difficulty = data['fc_difficulty'] if data['fc_difficulty'] else 0
self.fc_id = MiscFuns.get_id(16)
try:
c.execute("""
INSERT INTO `tbl_learning_flash_cards` (`fc_id`,`fc_title`,`fc_front`,`fc_back`,`fc_difficulty`)
VALUES (?,?,?,?,?)
""", (self.fc_id, title, front, back, difficulty))
conn.commit()
except sqlite3.Error as e:
print("An error occurred:", e.args[0])
class MultiSelectSpinner(Button):
dropdown = ObjectProperty(None)
values = ListProperty([])
selected_values = ListProperty([])
def __init__(self, **kwargs):
self.values.clear()
self.selected_values.clear()
self.bind(dropdown=self.update_dropdown)
self.bind(values=self.update_dropdown)
super(MultiSelectSpinner, self).__init__(**kwargs)
self.bind(on_release=self.toggle_dropdown)
def toggle_dropdown(self, *args):
if self.dropdown.parent:
self.dropdown.dismiss()
else:
self.dropdown.open(self)
def update_dropdown(self, *args):
if not self.dropdown:
self.dropdown = DropDown()
values = self.values
if values:
if self.dropdown.children:
self.dropdown.clear_widgets()
for value in values:
b = Factory.MultiSelectOption(text=value)
b.bind(state=self.select_value)
self.dropdown.add_widget(b)
def select_value(self, instance, value):
if value == 'down':
if instance.text not in self.selected_values:
self.selected_values.append(instance.text)
else:
if instance.text in self.selected_values:
self.selected_values.remove(instance.text)
def on_selected_values(self, instance, value):
if value:
self.text = ';'.join(value)
else:
self.text = ''
And the kv file:
<NewFlashCardScreen>:
BoxLayout:
orientation: "vertical"
BoxLayout:
size_hint_y: 0.1
Label:
size_hint_x: 0.2
text: "Card Title"
text_size: self.text_size
valign: 'middle'
TextInput:
id: new_fc_title
multiline: False
padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0]
text: root.data['fc_title'] if 'fc_title' in root.data else ""
on_text: root.data['fc_title'] = self.text
Label:
size_hint_x: 0.2
text: "Difficulty"
text_size: self.text_size
valign: 'middle'
BoxLayout:
size_hint_y: 0.1
Label:
size_hint_x: 0.2
text: "Card Tag(s)"
text_size: self.text_size
valign: 'middle'
BoxLayout:
MultiSelectSpinner:
id: new_fc_tag
text: root.data['fc_tags'] if 'fc_tags' in root.data else "Select tag(s)"
values: root.fc_tag_spinner_list
on_text: root.data['fc_tags'] = self.text
Button:
size_hint_x: 0.3
text: "New Tag"
on_release: lib.Navigation.page_nav(dest='new_flash_card_tag', orig='new_flash_card', edit=False)
BoxLayout:
size_hint_x: 0.2
TextInput:
padding_y: [self.height / 2.0 - (self.line_height / 2.0) * len(self._lines), 0]
id: new_fc_difficulty
text: root.data['fc_difficulty'] if 'fc_difficulty' in root.data else "0"
on_text: root.data['fc_difficulty'] = self.text
BoxLayout:
size_hint_y: 0.1
Label:
size_hint_x: 0.2
text: "Card Deck(s)"
text_size: self.text_size
valign: 'middle'
BoxLayout:
MultiSelectSpinner:
id: new_fc_deck
text: root.data['fc_decks'] if 'fc_decks' in root.data else "Select deck(s)"
values: root.fc_deck_spinner_list
on_text: root.data['fc_decks'] = self.text
Button:
size_hint_x: 0.3
text: "New Deck"
on_release: lib.Navigation.page_nav(dest='new_flash_card_deck', orig='new_flash_card', edit=False)
BoxLayout:
size_hint_x: 0.2
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
text: "Card Front"
BoxLayout:
TextInput:
id: new_fc_front
multiline: True
text: root.data['fc_front'] if 'fc_front' in root.data else ""
on_text: root.data['fc_front'] = self.text
RstDocument:
text: new_fc_front.text
show_errors: True
BoxLayout:
orientation: "vertical"
Label:
size_hint_y: 0.1
text: "Card Back"
BoxLayout:
TextInput:
id: new_fc_back
multiline: True
text: root.data['fc_back'] if 'fc_back' in root.data else ""
on_text: root.data['fc_back'] = self.text
RstDocument:
text: new_fc_back.text
show_errors: True
BoxLayout:
size_hint_y: 0.2
Button:
text: "Cancel"
on_release: lib.Navigation.page_nav(dest='prev_page', orig='new_flash_card', edit=False)
Button:
text: "Submit"
on_release: root.dispatch('on_submit', root.data)
I've tried clearing the dictionary files, self.data, self.data_fc_tag_ids, and self.data_fc_deck_ids, but that doesn't help.
I have no idea what data is being retained and how to get rid of it. Thank you.

John Don't woory! I get the solution.. Here is the path: In kv file first we can mention Dropdown widget, under Drop down we will mention check boxes and this is the answer.. Here is the kv file code:
DropDown:
padding: 0, 0, 0, root.width * 0.4
id: dropdown
on_select: btn.text = '{}'.format(args[1])
GridLayout:
size_hint_y: None
height: 44
cols: 2
row_default_height: '10dp'
Label:
id: person
text: 'Person'
text_size: self.size
valign: 'middle'
CheckBox:
text: 'check me'
on_active:
root.on_checkbox_active(person.text, self.active)
GridLayout:
size_hint_y: None
height: 44
cols: 2
row_default_height: '10dp'
Label:
id: vehicle
text: 'Vehicle'
text_size: self.size
valign: 'middle'
CheckBox:
id: vecle
text: 'check me'
on_active:
root.on_checkbox_active(vehicle.text, self.active)
GridLayout:
size_hint_y: None
height: 44
cols: 2
row_default_height: '10dp'
Label:
id: aircraft
text: 'Air_craft'
text_size: self.size
valign: 'middle'
CheckBox:
text: 'check me'
on_active:
root.on_checkbox_active(aircraft.text, self.active)
The .py file:
class My_class(BoxLayout):
def on_checkbox_active(checkbox_ref, name, checkbox_value):
if checkbox_value:
print('', name, 'is active')
else:
print('', name, 'is inactive')
pass

Related

Adding Kivy recycleview to screenmanager breaks example

I'm trying to combine this recycleview example with this screenmanager example so that the recycleview example can be one of the screens in my app. The app runs but all the control buttons display at the bottom of the UI (They're supposed to be at the top) and are either disabled or obscured, disallowing input. Consequently, the recycleview cannot be populated and/or viewed.
Here's my attempt:
import asyncio
from random import sample, randint
from string import ascii_lowercase
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
kv = '''
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:import BoxLayout kivy.uix.boxlayout.BoxLayout
#:import RecycleDataViewBehavior kivy.uix.recycleview.views.RecycleDataViewBehavior
ScreenManagement:
transition: FadeTransition()
ContactsScreen:
name: 'contacts'
MessengerScreen:
name: 'messenger'
<Row#RecycleKVIDsDataViewBehavior+BoxLayout>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 1
Rectangle:
size: self.size
pos: self.pos
value: ''
Label:
id: name
Label:
text: root.value
<ContactsScreen>:
canvas:
Color:
rgba: 0.3, 0.3, 0.3, 1
Rectangle:
size: self.size
pos: self.pos
rv: rv
orientation: 'vertical'
GridLayout:
cols: 3
rows: 2
size_hint_y: None
height: dp(108)
padding: dp(8)
spacing: dp(16)
Button:
text: 'Populate list'
on_press: root.populate()
Button:
text: 'Sort list'
on_press: root.sort()
Button:
text: 'Clear list'
on_press: root.clear()
BoxLayout:
spacing: dp(8)
Button:
text: 'Insert new item'
on_press: root.insert(new_item_input.text)
TextInput:
id: new_item_input
size_hint_x: 0.6
hint_text: 'value'
padding: dp(10), dp(10), 0, 0
BoxLayout:
spacing: dp(8)
Button:
text: 'Update first item'
on_press: root.update(update_item_input.text)
TextInput:
id: update_item_input
size_hint_x: 0.6
hint_text: 'new value'
padding: dp(10), dp(10), 0, 0
Button:
text: 'Remove first item'
on_press: root.remove()
RecycleView:
id: rv
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
bar_width: dp(10)
viewclass: 'Row'
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
spacing: dp(2)
<MessengerScreen>:
Button:
on_release: app.root.current = 'contacts'
text: 'back to the home screen'
font_size: 50
'''
class ContactsScreen(Screen):
def populate(self):
self.rv.data = [
{'name.text': ''.join(sample(ascii_lowercase, 6)),
'value': str(randint(0, 2000))}
for x in range(50)]
def sort(self):
self.rv.data = sorted(self.rv.data, key=lambda x: x['name.text'])
def clear(self):
self.rv.data = []
def insert(self, value):
self.rv.data.insert(0, {
'name.text': value or 'default value', 'value': 'unknown'})
def update(self, value):
if self.rv.data:
self.rv.data[0]['name.text'] = value or 'default new value'
self.rv.refresh_from_data()
def remove(self):
if self.rv.data:
self.rv.data.pop(0)
class MessengerScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_string(kv)
class MainApp(App):
def build(self):
return presentation
def main_runner(self):
async def run_wrapper():
# we don't actually need to set asyncio as the lib because it is
# the default, but it doesn't hurt to be explicit
await self.async_run(async_lib='asyncio')
print('App done')
#self.other_task.cancel()
return asyncio.gather(run_wrapper())
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(MainApp().main_runner())
loop.close()
The trouble seems to come from the <Row#RecycleKVIDsDataViewBehavior+BoxLayout> directive but I can't seem to fix it no matter where I place it.
You can position the Buttons using pos_hint, like this:
GridLayout:
id: grid
pos_hint: {'center_x': 0.5, 'top': 1}
Then, you need to size the RecycleView so that it is not over the Buttons, like this:
RecycleView:
id: rv
size_hint_y: None
height: root.height - grid.height

Kivy use two files .kv

i'm trying to switch kv files by a function on my .py code. In my first kivy code there are few screens and in my second kivy code there is a swipebutton#carausel.Is there any way for connect the two files. I post an example: <Screen1> id:_screen1 on another file there is: <SwipeButton#Carousel>. I hope someone can help me
This is the output received when I unload the first file and load the second, it doesn't break the code:
`
class MainApp(MDApp)
def build(self):
self.title = "Meet!"
if "Colore" in impostazioni:
self.theme_cls.theme_style = impostazioni.get("Colore")["coloresfondo"]
else:
print("Nulla")
self.theme_cls.theme_style = "Light"
if "Nome" in impostazioni:
Nome = impostazioni.get("Nome")["nome"]
print(Nome)
else:
print("Non trovato")
if "Sesso" in impostazioni:
Sesso1 = impostazioni.get("Sesso")["sesso"]
print(Sesso1)
else:
print("Non trovato")
self.theme_cls.primary_palette = "Red"
self.theme_cls.primary_hue = "A700"
self.dativari = [{'id': i, 'data_index': i, 'index': 1, 'height': 48, 'text': str(calendariofile.get(str(i)))} for i in calendariofile]
self.screen = Builder.load_file("num3.kv")
self.root = Builder.load_file("prova.kv")
return self.screen`
#:import C kivy.utils.get_color_from_hex <SwipeButton#Carousel>: text: '' size_hint_y: None height: 48 ignore_perpendicular_swipes: True data_index: 0 min_move: 20 / self.width on__offset: app.aggiorna(root.data_index)#print(root.data_index) #app.update_index(root.data_index, self.index) canvas.before: Color: rgba: C('FFFFFF33') Rectangle: pos: self.pos size: self.size Line: rectangle: self.pos + self.size Button: text: 'delete ({}:{})'.format(root.text, root.data_index) on_press: app.elimina(root.data_index) Label: text: root.text Button: text: 'archive' on_press: app.passachat(root.data_index) RecycleView: data: app.dativari viewclass: 'SwipeButton' do_scroll_x: False scroll_timeout: 100 RecycleBoxLayout: orientation: 'vertical' size_hint_y: None height: self.minimum_height default_size_hint: 1, None
If the two kv files do not redefine the same classes, then you can just load them both.
If the two kv files do redefine the same classes, then you can use Builder.unload_file() to unload one before loading the other. Note that loading/unloading kv files will not affect Widgets already created, it will only affect Widgets created after the change.

Content at bottom of screen... after adding ToolBar with Kivy

I'm just trying to add a simple 'ToolBar' but after the tool bar kept aligning to the bottom I found that AnchorLayout: let's me anchor the toolbar to the top. But all my content is now only showing in the bottom half of the screen... I'm not sure why.. Adjusting the 'center_y': does nothing... Does anyone see my issue, I really appreciate it.
main
from kivymd.app import MDApp
from kivymd.uix.floatlayout import MDFloatLayout
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton, MDIconButton
from kivy.uix.scrollview import ScrollView
from kivy.uix.screenmanager import Screen, ScreenManager
from PyDictionary import PyDictionary
import sys
import json
import requests
class Manager(ScreenManager):
"""Manages Screens"""
class Main(Screen):
"""main application goes here"""
def close_dialog(self, obj):
self.dialog.dismiss()
def show_data(self):
message = """
This little program was
designed to help re-think
your sentences.
"""
close = MDIconButton(icon="close-circle", on_release=self.close_dialog)
#more = MDIconButton(icon="more")
self.dialog = MDDialog(title="Probably Knot", text=message,
size_hint=(0.5, 1), buttons=[close])
self.dialog.open()
class Analyzer(Screen):
def analyze(self, main): # main is pointing to ---> Main().show_data()
"""Analyse data with PyDictionary"""
sent = main.ids.sentence.text.lower()
wrd = main.ids.word.text.lower()
# Definition Section #
dictionary = PyDictionary()
define_wrd = dictionary.meaning(wrd)
noun = ''
verb = ''
adjective = ''
result = ''
try:
noun = " ".join(define_wrd['Noun'])
result += f"Definition:\n1. {wrd}:\n{noun}\n"
except TypeError or KeyError:
noun = False
print('Noun, is not found in API http://words.bighugelabs.com/api')
try:
verb = " ".join(define_wrd['Verb'])
result += f"2.\n{verb}\n"
except TypeError or KeyError:
verb = False
print('Verb, is not found in API http://words.bighugelabs.com/api')
try:
adjective = " ".join(define_wrd['Adjective'])
result += f"3.\n{adjective}\n"
except TypeError or KeyError:
adjective = False
print('Adjective, is not found in API http://words.bighugelabs.com/api')
if not noun and not verb and not adjective:
error = MDDialog(title="Error", text=f"Word: '{wrd}' is not in\n\n'dictionary'")
error.open()
if wrd != '' and sent != '':
API_KEY = 'a701e74e453ee6695e450310340401f5'
URL = f'http://words.bighugelabs.com/api/2/{API_KEY}/{wrd}/json'
if wrd not in sent:
error = MDDialog(title="Error", text=f"Word: '{wrd}' is not in\n\n'{sent}'")
error.open()
else:
r = requests.get(URL) # get's url json file
j = json.loads(r.text) # loads json into 'j' as a dict
if type(j) == dict: # check is 'j' variable is coming in as a Dict
# holds the new sentences
new = f"{result}\n"
try:
for num, w in enumerate(j['adjective']['syn'], 1):
new += f"{num}: {sent.replace(wrd, w)}\n"
except KeyError:
print(f'Adjective for "{wrd}" is not found.')
try:
for num, w in enumerate(j['noun']['syn'], 1):
new += f"{num}: {sent.replace(wrd, w)}\n"
except KeyError:
print(f'Noun for "{wrd}" is not found.')
try:
for num, w in enumerate(j['verb']['syn'], 1):
new += f"{num}: {sent.replace(wrd, w)}\n"
except KeyError:
print(f'Verb for "{wrd}" is not found.')
class ProbablyKnotApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "Yellow"
self.theme_cls.primary_hue = "A700"
return Manager()
ProbablyKnotApp().run()
kv file
<Manager>:
Main:
name: 'main'
Analyzer:
name: 'analyzer'
<Main>:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
MDToolbar:
title: "Probably Knot"
pos_hint_y: None
pos_y: 1
md_bg_color: app.theme_cls.accent_color
right_action_items: [["dots-vertical", lambda x: app.callback()]]
MDBoxLayout:
orientation: 'vertical'
MDRectangleFlatButton:
text: "help"
pos_hint: {'center_x': 0.75, 'center_y': 1}
on_release: app.root.get_screen('main').show_data()
MDTextField:
id: sentence
icon_right: "book-open-outline"
icon_right_color: app.theme_cls.primary_color
hint_text: "Enter Sentence"
helper_text: "Write a problem statement to analyze"
helper_text_mode: "on_focus"
pos_hint: {'center_x': 0.5, 'center_y': 0.7}
size_hint_x: None
width: 400
MDTextField:
id: word
icon_right: "lead-pencil"
icon_right_color: app.theme_cls.primary_color
hint_text: "Enter Word"
helper_text: "Write ONE word from the above sentence"
helper_text_mode: "on_focus"
pos_hint: {'center_x': 0.5, 'center_y': 0.6}
size_hint_x: None
width: 400
MDIconButton:
icon: "card-plus"
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
on_release: app.root.get_screen('analyzer').analyze(root)
<Analyzer>:
MDToolbar:
title: "Probably Knot"
md_bg_color: app.theme_cls.accent_color
right_action_items: [["dots-vertical", lambda x: app.callback()]]
MDList:
id: container
The problem is that you are not taking into account the default values for size_hint (1,1) and pos (0,0). So your AnchorLayout fills your Main Screen, because of the default values, but the anchor_y setting puts the MDToolBar at the top of the AnchorLayout.
Similarly, your MDBoxLayout also fills the entire Main Screen, but because the MDRectangleFlatButton and the MDTextField have pre-defined sizes, they don't fill the MDBoxLayout. So they only fill the bottom half of the MDBoxLayout.
So here is a version of your kv (for the Main Screen) that uses pos_hint for the MDToolBar and minimum_height for the MDBoxLayout and actually setting its y value to bump up against the tool bar:
<Main>:
MDToolbar:
id: toolbar
title: "Probably Knot"
pos_hint: {'top':1.0}
md_bg_color: app.theme_cls.accent_color
right_action_items: [["dots-vertical", lambda x: app.callback()]]
MDBoxLayout:
size_hint: 1, None
height: self.minimum_height
y: root.height - toolbar.height - self.height
orientation: 'vertical'
MDRectangleFlatButton:
text: "help"
pos_hint: {'center_x': 0.75, 'top': 1}
on_release: app.root.get_screen('main').show_data()
MDTextField:
id: sentence
icon_right: "book-open-outline"
icon_right_color: app.theme_cls.primary_color
hint_text: "Enter Sentence"
helper_text: "Write a problem statement to analyze"
helper_text_mode: "on_focus"
pos_hint: {'center_x': 0.5, 'top': 0.7}
size_hint_x: None
width: 400
MDTextField:
id: word
icon_right: "lead-pencil"
icon_right_color: app.theme_cls.primary_color
hint_text: "Enter Word"
helper_text: "Write ONE word from the above sentence"
helper_text_mode: "on_focus"
pos_hint: {'center_x': 0.5, 'center_y': 0.6}
size_hint_x: None
width: 400
MDIconButton:
icon: "card-plus"
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
on_release: app.root.get_screen('analyzer').analyze(root)

python kivy : How to make switch Button work with carousel

I get:
AttributeError: 'Carousel' object has no attribute 'switch_on'
error whenever I try to click on the button
-------main.py----------
class main(App):
def build(self):
class SampBoxLayout(BoxLayout):
# For Switch
def switch_on(self, instance, value):
if value is True:
print("Switch On")
else:
print("Switch Off")
return Carousel()
sample_app = kv_main()
sample_app.run()
----------main.kv--------------
:
Label:
text: "Page 1"
size_hint: 1, .1
width :100
SampBoxLayout:
# ----------Switch ----------
BoxLayout:
BoxLayout:
orientation: "horizontal"
size_hint_x: .25
CustLabel:
text: "On / Off"
Switch:
id: switch_id
on_active: root.switch_on(self, self.active)# <--need help on this
Label:
text: "Page 2"
size_hint: 1, .1
width :100
Button:
text: "Button 2.1"
size_hint: None, None
width :100
Label:
text: "Page 3"
size_hint: 1, .1
width :100
Button:
text: "Button 3.1"
size_hint: None, None
width :100
You are using root.switch_on. As the error indicates, your root class is the carousel. Since SampBoxLayout is not root, you should give SampBoxLayout an id, and call it with it´s id.
Edited from your example:
SampBoxLayout:
id: samp
BoxLayout:
BoxLayout:
orientation: "horizontal"
size_hint_x: .25
CustLabel:
text: "On / Off"
Switch:
id: switch_id
on_active: samp.switch_on(self, self.active)
I don't know if you did something wrong when posting this, or if your code really looks like this. But you should not define classes inside your app class. Keep the classes on top level to access them in kv.
And your kv code is unusual. You have your widgets in a label.

Access data from Kivy Popoup Input

I was trying to look at different examples online to solve this issue but Still cannot figure out. I have an app that calls a popup class. The popup has an input field that does some manipulation to the text in the input field. The manipulated data is stored in a variable inside of the popup class. Now how can the parent widget access the data obtained from this widget. Here is a short example of the code.
KV
<ScreenManagement>:
ScreenManager:
id: manager
size_hint_y: 93
Screen:
name: "Case_info_screen"
id: sc1
FloatLayout:
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 10
canvas.before:
Color:
rgb: 0.17, 0.17, 0.17 # your color here
Rectangle:
pos: self.pos
size: self.size
Label:
text_size: self.size
font_size: 20
valign: 'middle'
height: "75dp"
size_hint_y: None
color: 1,1,1,1
size_hint_x: 75
text: " Case Info"
RelativeLayout:
size_hint_x: 25
Button:
text_size: self.size
halign: 'center'
valign: 'middle'
size_hint: 0.70, 0.6
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
text: 'Automatic Filler'
on_press: root.formfiller()
BoxLayout:
size_hint_y: 5
spacing: 35
LabelCases:
text: ' Name: '
width: '125dp'
size_hint_x: None
TextInput:
id: first_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'First Name'
TextInput:
id: last_name_input
width: '300dp'
height: '40dp'
size_hint_x: None
font_size: 18
hint_text: 'Last Name'
<Formfillerpop>:
title: 'Automatic Filler'
size_hint: None, None
size: 600, 600
BoxLayout:
orientation: 'vertical'
Label:
size_hint_y: 20
text: 'Please Paste your text'
markup: True
TextInput:
id: sentence
size_hint_y: 65
BoxLayout:
size_hint_y: 10
orientation: 'horizontal'
Button:
text: 'Analyze'
on_press: root.on_analyze(sentence.text)
Button:
text: 'Close'
on_press: root.closepop()
Python:
class Formfillerpop(Popup):
selection = StringProperty
id = ObjectProperty
def on_analyze(self, selection):
analyze = TextExtractor(selection)
names = analyze.name()
def closepop(self):
self.dismiss()
class ScreenManagement(FloatLayout):
def formfiller(self, *args):
Formfillerpop().open()
class IOApp(App):
def build(self):
return ScreenManagement()
if __name__ == '__main__':
IOApp().run()
Ultimately I want to take the txt from names in the popup and then autopopulate the first name and last name in the main app with the analyzed data
Sorry if this is basic. I am fairly new to Kivy.
You can access popup content using its content property. You can use it to read text property of read underlying TextInput. For example this code binds this property to local popup_text StringProperty, which means that any change in the popup text input will be reflected there:
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import StringProperty
Builder.load_string('''
<CustomPopup>:
size_hint: .5, .5
auto_dismiss: False
title: 'Hello world'
BoxLayout:
text_input: text_input
orientation: 'vertical'
TextInput:
id: text_input
Button:
text: 'dismiss'
on_press: root.dismiss()
''')
class CustomPopup(Popup):
pass
class TestApp(App):
popup_text = StringProperty()
def build(self):
l = BoxLayout()
l.add_widget(Button(
text='show_popup', on_press=self.show_popup
))
l.add_widget(Button(
text='print popup text', on_press=self.print_popup_text
))
return l
def show_popup(self, *args):
p = CustomPopup()
p.content.text_input.bind(text=self.setter('popup_text'))
p.open()
def print_popup_text(self, *args):
print(self.popup_text)
if __name__ == '__main__':
TestApp().run()

Resources