Kivy use two files .kv - python-3.x

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.

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 recycleview duplicating data items

I have a recycle view in kivy im writing to it with a list containing text and images, the text is fine but as soon as i write an image its duplicating the image in the view as i scroll down please see code below, how would i stop this from happening, here is my kv file I have a boxlayout with two sets of data, heres a picture of the problem as wellexample
kv file:
<SelectableReportTextbox#BoxLayout>:
text: ''
imagesource: ''
color: ''
Button:
size_hint: .8, 1
text_size : self.text_size
size_hint_y: None
foreground_color: [1, 1, 1, 1]
background_color: (0.2, 0.4, 0.8, 0.9) # root.color
font_name: 'C:\kivy_venv\Graphics\GIL_____.TTF'
font_size: self.height*0.2
background_normal: root.imagesource
text: root.text
ScreenTwo:
rv2: rv2
canvas.before:
Rectangle:
size:self.size #100, 100
pos: self.pos
source: "C:\kivy_venv\Graphics\Jetfireback.png"
RecycleView_B:
bar_width: 6
size_hint: (None, None)
do_scroll_y: True
id: scrlv2
size: (500, 500)
pos_hint: {'center_x': .75, 'center_y': .64}
multiline:True
ProjectRV:
viewclass: 'SelectableReportTextbox' #
orientation: "horizontal"
scroll_type: ['bars', 'content']
scroll_wheel_distance: dp(114)
key_size: "height"
padding:1, 1
space_x: self.size[0]/3
id: rv2
pos_hint: {'center_x': 0.32, 'center_y': 0.525}
bar_width: dp(25)
bar_color: (0.7, 0.1, 0.3, 0.7)
bar_inactive_color: (0.1, 0.1, 0.1 , 1)
scroll_y : 0
SelectableRecycleBoxLayout:
rv2:rv2
spacing : '6'
default_size_hint: 1, None
size_hint_y: None
size_hint_x: 1
height: self.minimum_height
multiselect: True
touch_multiselect: True
orientation: 'vertical'
main.py:
class SelectableRecycleBoxLayout(FocusBehavior,LayoutSelectionBehavior,RecycleBoxLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableReportTextbox(RecycleDataViewBehavior):
selectable = BooleanProperty(True)
index =None
selected = BooleanProperty(False)
def __init__(self, **kw):
super().__init__(**kw)
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableRecycleBoxLayout, self).refresh_view_attrs(
rv, index, data)
class ProjectRV(RecycleView):
def __init__(self, **kwargs):
super(ProjectRV, self).__init__(**kwargs)
class RecycleView_B(RecycleView):
pass
class ScreenTwo(Screen):
TEXT_FILE = open("output.txt", "a")
zdata = re.search('{.*,', strdata).group(0)
splitex = zdata.split(':' + "'")[1]
print (zdata)
TEXT_FILE.write(zdata)
TEXT_FILE.close()
with open("output.txt", "r") as f:
txtdata = eval(str('[' + ''.join(f.readlines()) + ']'))#ast.literal_eval
nstring = type(txtdata)
self.rv2.data = txtdata
self.rv2.refresh_from_viewport()
self.rv2.refresh_from_data()
The RecycleView re-uses viewclass object instances, and sets properties of those instances based on the data dictionaries. So, if one of your dictionaries sets the imagesource property of a viewclsas instance and then that instance is re-used for a dictionary that does not set the imagesource property, then that instance will retain that prior value of imagesource. The fix is to make sure that every dictionary in the data contains a value for every property of the viewclass. Each dictionary needs to include values for text, imagesource, and color, even if the value is ''.

How to add multiple widget at the same time to a scrollview?

I'm new at kivy, so I'm working on a test app. I want to create a screen with ScrollView and I want to add multiple things to a 'line' in the ScrollView, a text (description) and an image.
I have tried this way:
class PresentUploadedData(Screen):
container = ObjectProperty(None)
def __init__(self, **kwargs):
super(PresentUploadedData, self).__init__(**kwargs)
Clock.schedule_once(self.setup_scrollview, 1)
def setup_scrollview(self, dt):
self.container.bind(minimum_height=self.container.setter('height'))
self.add_text_inputs()
def add_text_inputs(self):
for x in range(30):
self.container.add_widget(Label(text="Label {}".format(x), size_hint_y=None, height=40, color= [128,0,0,1]))
self.container.add_widget(Image(source='test.jpg', size_hint=(None, None,), width=50, height=50))
with this .kv file:
<PresentUploadedData>:
name: "presentupload"
message: send
container: container
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
size: self.size
pos: self.pos
GridLayout:
rows: 3
cols: 1
spacing: 5
padding: 5
font_name: "Calibri"
background_color: 1,1,1, 1
ScrollView:
background_color: 1,1,1, 1
size_hint: (1, .9)
bar_width: 10
bar_color: 128,0,0,0.7
bar_inactive_color: 128,0,0,1
effect_cls: "ScrollEffect"
scroll_type: ['bars', 'content']
color: 128,0,0,1
StackLayout:
id: container
size_hint_y: None
color: 128,0,0,1
GridLayout:
cols: 2
BoxLayout:
spacing: 5
size_hint: .7, .1
Button:
text: "< BACK"
id: send
color: 0, 0, 0, 1
background_color: .88,.88,.88, 1
size_hint: .2, 1
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
But I've got ScrollView accept only one widget Exception.
Why I got this, and how can I resolve this?
There is an error in .kvfile:
GridLayout:
cols: 2
This is useless.
The problem can be solved with one more for inside the for loop:
row = [Label(text="Label {}".format(x), size_hint_y=None, height=50, color= [128,0,0,1]), Image(source='test.jpg', size_hint=(None, None,), width=50, height=50)]
for r in row:
self.container.add_widget(r)
But this also didn't put the things near each other, just let them be there.

Kivy make a grid layout inside a label or button

Is it possible to have a grid like layout inside a Label or a Button in kivy.
I have an app that takes in a CSV file with product information and I would like to populate MainScreen with rows from a CSV file.
Each row should look like this:
In the end the Label or Button should be pressable to open a pop up window for confirmation screen for quantity of the product and verify.
Is it even possible or am I approaching it from the wrong angle?
I do not have any code yet to populate the MainScreen with rows but this is how it looks so far.
To clarify. At this moment I don't need help with importing CSV files, but with the method to display it, that matches the above criteria(picture)
Code so far is as follows:
ATmain.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import StringProperty
Window.clearcolor = (1,1,1,1)
Window.size = (270, 480)
class LoginScreen(Screen):
input = StringProperty("")
class MainScreen(Screen):
username = StringProperty('')
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("app.kv")
class ATApp(App):
presentation = Builder.load_file("app.kv")
def build(self):
return presentation
if __name__ == '__main__':
ATApp().run()
app.kv:
# File name: main.py
#:import FadeTransition kivy.uix.screenmanager.FadeTransition
#:kivy 1.10.1
ScreenManagement:
transition: FadeTransition()
LoginScreen:
id: login
MainScreen:
username: login.input
<LoginScreen>:
name: "login"
canvas:
Color:
rgba: [1,1,1]
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
rows:2
cols:1
background_color: 1,1,1,1
Label:
size_hint: 0.3, 0.05
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.4}
text:"Kasutaja"
color: 0,0,0,1
TextInput:
id: input
size_hint: (0.3, None)
height: 30
pos_hint: {"x": 0.5 - 0.3/2, "center_y": 0.3}
multiline: False
Button:
id: confirm_login
text: "Login"
size_hint: 0.15, 0.07
pos_hint: {"x": 0.5 - 0.15/2, "center_y": 0.2}
background_color: 0.9,0.9,0.9,1
on_press: self.background_color = (1,0,0,1)
on_release: root.input = input.text; app.root.current = "main"
<MainScreen>:
name: "main"
canvas:
Rectangle:
pos: self.pos
size: self.size
Label:
id:name
text: root.username
color: (0,0,0,1)
size_hint_y: None
height: 30
size_hint_x: 1
pos_hint: {"right": 1, "top": 1}
BoxLayout:
orientation: "vertical"
size_hint_y: None
size_hint_x: 1
pos_hint_x: None
pos_hint_y: 1
Button:
text: "Item1"
color: (0,0,0,1)
height: self.height
size_hint_y: None
size_hint_x: 1
pos_hint: {"right": 1, "top": 0}
I would be very greatful if anyone could as much as point me in the right direction!
The kivy hack way will be to simply use a GridLayout or any layout for that matter then give your layout button properties so it is clickable like so :
from kivy.behaviors import ButtonBehavior
#then make a clickable grid
class GridButton(GridLayout, ButtonBehaviour):
def __init__(self, **kwargs):
super().__init__(**kwargs)
#Then do whatever you want to do
Another way to do it I guess would be to use the on_touch_down callback and check if the touch is within the widget's bounds

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