id not being passed to filechooser - python-3.x

I have attached an image showing that the correct filechooser path is being printed out to the console when selecting the file. From that, I assume that the problem is that the self.ids.image.source = filename[0] is failing. Specifically, the id referencing the Image.source. I have tried changing the id and referencing the new one. That doesn't work. I'm still learning Kivy, so I'm not sure if I messed up the hierarchy and I should be calling another id to reference the filechooser's.
Also, I deleted two MDBottomNavigationItems and the contents of the other screens to clean up the code. The question is referring to the LibraryWindow screen.
py file
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
# Screens
class LibraryWindow(Screen):
pass
class PlayingWindow(Screen):
pass
class VisualWindow(Screen):
pass
# Top Action Bar
class TopBar(BoxLayout):
pass
# App
class MainApp(MDApp):
def build(self):
self.theme_cls.theme_style = "Dark"
self.theme_cls.primary_palette = "BlueGray"
return Builder.load_file('Z:\\PycharmProjects\\kivyMD\\venv\\my.kv')
def selected(self, filename):
try:
print(filename[0])
self.ids.image.source = filename[0]
except:
pass
MainApp().run()
Kv outline
BoxLayout:
orientation: 'vertical'
TopBar:
MDBottomNavigation:
MDBottomNavigationItem:
name: 'navlib'
text: "Library"
icon: 'book'
LibraryWindow:
#############################
### S C R E E N S ###
#############################
<LibraryWindow>:
name: "library"
size: root.width, root.height
id: my_widget
canvas.before:
Color:
rgba: 0.5,0,0,1
Rectangle:
size: self.size
BoxLayout:
orientation: "vertical"
size: root.width, root.height
padding: 50
spacing: 20
Image:
id: image
source: ''
FileChooserIconView:
id: filechooser
color: 1,.3, .3, 1
on_selection: app.selected(filechooser.selection)
<PlayingWindow>:
<VisualWindow>:
<TopBar>:

Setting an id on the widget that is the root of a rule will not work. The ids are only assigned for children of the widget that is the root of the rule.
Note that the kivy lang documentation confuses the term root widget, using that term for both the root widget of the app and the root widget of a rule. The ids are only set in the ids dictionary of the widget that is the root of the rule where the id appears.
So, you can access the Image widget by adding an id to the LibraryWindow instance in the BoxLayout (the one that is the root of the app) like this:
BoxLayout:
orientation: 'vertical'
TopBar:
MDBottomNavigation:
MDBottomNavigationItem:
name: 'navlib'
text: "Library"
icon: 'book'
LibraryWindow:
id: library
Then you code to set the Image source can become:
self.root.ids.library.ids.image.source = filename[0]
The self.root gets the root widget of the app. The ids.library gets the LibraryWindow instance. The ids.image gets the Image instance that has the image id.

Related

How do I connect the Spinner ids from the kivy file with the data that I provide from my products database?

How do I connect my ids to the python code considering I want to load the string from self.listcode variable into the values of the spinner, I already use self. ids. and I don't get anything from the KV file. Thanks in advance for ur help. One of the errors popping out is the one below:
AttributeError: 'super' object has no attribute '__getattr__
I think if I'm not wrong that it has to do with that Screen doesn't having the possibility to access ids
KIVY FILE###
<WindowManager>:
FirstWindow:
SecondWindow:
<FirstWindow>:
name: "menu"
canvas.before:
Color:
rgba: (242/255, 202/255, 5/255, 1)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [55]
Image:
source: 'Logoapp.png'
BoxLayout:
orientation: "horizontal"
size: 50, 50
Button:
font_size: 20
size_hint: 0.3, 0.2
pos_hint: {"x":.5, "top":.2}
pos:100, 100
background_color: 0,0,0,0
text: "Cotizar"
color: 0,0,0,1
canvas.before:
Color:
rgba: (23/255,152/255,216/255,0.71)
RoundedRectangle:
size: self.size
pos: self.pos
radius:[55]
on_release:
app.root.current = "cotiza"
root.manager.transition.direction = "left"
<SecondWindow>:
name: "cotiza"
FloatLayout:
CodigoSpin:
id: "Cod_prod"
pos: 20, 100
Label:
text: "Descripcion"
pos: 20, 35
CodigoSpin:
id: "Cod_prod2"
pos: 20, 200
Label:
text: "Descripcion"
pos: 20, 130
CodigoSpin:
id: "Cod_prod3"
pos: 20, 300
Label:
text: "Descripcion"
pos: 20, 235
<CodigoSpin#Spinner>:
size_hint: None, None
size: 100, 44
text: "CodigoSpin"
Main Program
from types import new_class
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.config import Config
from kivy.core.window import Window
from kivy.properties import ListProperty
from kivy.uix.spinner import Spinner, SpinnerOption
from kivy.uix.label import Label
from kivy.uix.boxlayout import BoxLayout
from kivy.graphics import Color, Rectangle, RoundedRectangle
import sqlite3
Window.size = (250, 500 ) #Changed the size of the screen to fit my phone
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
class FirstWindow(Screen, FloatLayout):
pass
class SecondWindow(Screen, Widget):
def __init__(self, **kwargs):
super(SecondWindow, self).__init__(**kwargs)
#Create de Database connection
conn = sqlite3.connect("inventingt.db")
cursor = conn.cursor()
cursor.execute("""SELECT Codigo FROM masterinv """)
rows = cursor.fetchall()
#Create the variable listcode of objects from the database
self.listcode = [str(t[0]) for t in rows]
#This method will initialize the values on the Spinner
self.inicializarvalores()
def inicializarvalores(self):
self.ids.Cod_prod.values = self.listcode
class WindowManager(ScreenManager, Widget):
pass
class Buendes(App):
def build(self):
#Inicializamos el screen manager para inicializar las paginas
self.window = WindowManager()
#add widgets to window
#Agregamos el boton de inicializar la aplicacion
#Conectamos una base de datos
return self.window
if __name__ == "__main__":
Buendes().run()
Other way to connect your widgets which are created in .kv file to .py file is:
Give id to your widget. ( ✓ You did it as Cod_prod )
in .kv file, top of your class (under <SecondWindow>:), type this: Cod_prod:Cod_prod ( ☓ )
Import this : from kivy.properties import ObjectProperty ( ☓ )
Now under class SecondWindow(in .py file), identify your object: Cod_prod = ObjectProperty()
Now you can access your widget which is created in .kv file with:
def inicializarvalores(self):
self.Cod_prod.values = self.listcode
I couldn't understand the situation on Spinner and Screen connection. I had same problem. Also tried both solutions but couldn't get the solution.
I couldn't assign values to Spinner on root class inherited Screen.
What I tried:
On py file: self.ids.spinnerid.values = list -> not working. But py connected the spinner.
On kv file: Spinner: values: root.list -> not working.
Try to ListProperty, ObjectProperty... -> not working.
I turned around the problem using values: app.list on kv file and define the list on App class.

TextInput suddenly stopped working in Kivy app

I am building a simple Kivy app with a couple of screens. The first screen has a couple of buttons which, when clicked, move to the second screen. The second screen has a text input widget and a button inside a Float Layout. The layout is loaded as a root widget by an explicit call to the kv file through Builder.
Everything was working fine and I added a 'focus: True' tag in the text input attributes. The app worked fine and I could type in the text input field with focus set as True. However, the text input field suddenly stopped working without any change in code or layout. I was not sure and searched Google for a couple of probable solutions, none of which worked:
Removed the 'focus: True' attribute and reloaded the app but the text input field still did not respond. I was unable to type anything from my keyboard.
Another post pointed out that the kv file was being loaded twice resulting in erratic behaviour. I tried to remove the explicit Builder file call and returned the root widget (Screen Manager) in the main code. However, it messed up my entire app and only showed a black empty screen.
Can you please advise as to what I may be doing wrong? The code is provided below:
Python Code:
from kivy.config import Config
Config.set('kivy','window_icon','sivaicon.png')
Config.set('graphics', 'resizable', True)
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.button import Button
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.textinput import TextInput
from kivy.lang.builder import Builder
class SivaLoginScreen(Screen):
def twitter_authentication(self):
App.get_running_app().root.current='verify_screen'
def linkedin_authentication(self):
App.get_running_app().root.current='verify_screen'
class SivaVerifyScreen(Screen):
pass
class SivaTabbedScreen(Screen):
pass
class SivaScreenManager(ScreenManager):
pass
class ImageButton(ButtonBehavior, Image):
pass
# Tell Kivy to directly load a file. If this file defines a root widget, it will be returned by the method.
root_widget = Builder.load_file('siva.kv')
class SivaApp(App):
def build(self):
# Initialize root widget
return root_widget
if __name__ == '__main__':
# Run application
SivaApp().run()
kv file:
SivaScreenManager:
SivaLoginScreen:
SivaVerifyScreen:
SivaTabbedScreen:
<ImageButton>:
keep_ratio: True
<SivaLoginScreen>:
name: 'login_screen'
canvas.before:
Color:
rgba: 195/255, 60/255, 35/255, 1
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
size: root.width, root.height
Image:
id: login_logo_siva
source: 'images/sivalogo1.png'
keep_ratio: True
size_hint: 0.3, 0.3
pos_hint: {'center_x':0.5, 'center_y':0.75}
Label:
id: login_label_siva
pos: self.x*0.5-4, self.y*0.5+15
markup: True
font_name: 'roboto/Roboto-Medium.ttf'
text: '[color=#FDFD98]S.[/color][color=#B29DD9]I[/color][color=#FDFD98].[/color][color=#77DD77]V[/color][color=#FDFD98].[/color][color=#779ECB]A[/color]'
font_size: '40sp'
Label:
id: login_label_slogan1
pos: self.x*0.5-3, self.y*0.5-6
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]SLOGAN TEXT[/color]'
font_size: '13sp'
Label:
id: login_label_slogan2
pos: self.x*0.5-3, self.y*0.5-20
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: '[color=#FDFD98]HEADLINE TEXT[/color]'
font_size: '13sp'
BoxLayout:
id:login_button_layout
orientation: 'horizontal'
size_hint: 0.2, 0.2
pos_hint: {'center_x':0.5, 'center_y':0.25}
ImageButton:
id: twitter_button
source: {'normal': 'images/twitter-96.png', 'down': 'images/twitter-96.png'} [self.state]
on_release: root.twitter_authentication()
ImageButton:
id: linkedin_button
source: {'normal': 'images/linkedin-96.png', 'down': 'images/linkedin-96.png'} [self.state]
on_release: root.linkedin_authentication()
<SivaVerifyScreen>:
name: 'verify_screen'
canvas.before:
Color:
rgba: 195/255, 60/255, 35/255, 1
Rectangle:
pos: self.pos
size: self.size
FloatLayout:
size: root.width, root.height
Label:
id: verify_label
markup: True
font_name: 'roboto/Roboto-Regular.ttf'
text: 'Paste the verification code'
font_size: '16sp'
pos_hint: {'center_x':0.5, 'center_y':0.7}
size_hint: 1, 0.4
TextInput:
id: verify_input
multiline: False
font_size: '30sp'
pos_hint: {'center_x':0.5, 'center_y':0.55}
size_hint: 0.5, 0.1
ImageButton:
id: verify_button
source: {'normal': 'images/lock-96.png', 'down': 'images/lock-96.png'} [self.state]
pos_hint: {'center_x':0.5, 'center_y':0.35}
size_hint: 0.5, 0.5
<SivaTabbedScreen>:
name: 'tabbed_screen'
FloatLayout:
size: root.width, root.height
Label:
pos: self.x*0.5, self.y*0.5
text: 'SECOND SCREEN'
font_size: '50sp'
Please advise. I am helplessly stuck. :(
Thanks in advance
Okay so this was the problem: Some of my widgets were overlapping each other thereby rendering the widgets underneath as unresponsive. In my case, a button widget was overlapping my textinput widget due to which I was unable to enter text in the textinput widget.
I used the Kivy inspector tool to identify the extent of the widgets' dimensions:
python3 main.py -m inspector
Use Ctrl+e to launch the inspector while the app is running and click on each widget to check its size, position and parent. I reduced the button widget's size and converted the float layout into a stacked box layout and this resolved the issue.

RecycleView and ScreenManager problems

Can't seem to solve getting data from my database to populate into various textinputs when using Recycleview. The problem exist only when i use ScreenManager/Screen. When i call the screen directly from the def build(self): return Screen everything works but not when i call the screen manager like this def build(self): return ScreenManager
kv file
<Button>:
on_press: app.root.get_data(*args)
<Screen>:
BoxLayout:
orientation: 'vertical'
size_hint_x: .3
RV:
viewclass: 'Button'
data: [{'text': str(x)} for x in root.my_data]
RecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(32)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
The method get_data() and variable, my_data are implemented in class Screen. Without ScreenManager, the root is Screen. After adding ScreenManager, now the root is ScreenManager. In order to access the method get_data() from the class rule, Button, you need to do the following:
Add id: screen_rv after you have instantiated class rule, <Screen> under ScreenManager
Replace app.root.get_data(*args) with app.root.ids.screen_rv.get_data(*args)
kv - Snippets
<ScreenManagement>:
ScreenRV:
id: screen_rv
<Button>:
on_press: app.root.ids.screen_rv.get_data(*args)
<ScreenRV>:
name: 'screen_rv'

Add custom widgets at runtime to screens

I want to add Buttons (Basicly custom Buttons with Image) as a custom Widgets to "Screen1" but I always end up with "_event.pyx not found" Error.
I've tried with "super().init(**kwargs)" and without.
Python code:
sm = ScreenManager()
class DrinkWidget(Widget):
pass
class HomeScreen(BoxLayout):
def switch(self, to):
#Swithing funktion
#This is the Part, that causes the Problem I think:
class Screen1(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.add_widget(DrinkWidget(
lable_text_optn = 'test'
))
class Screen2(Screen):
pass
class ZapfanlageApp(App):
icon = 'GUI_Elemente/app_icon.png'
title = 'Zapfanlage'
def build(self):
pass
if __name__ == "__main__":
ZapfanlageApp().run()
Kivy code (separate .kv File. The part "HomeScreen" works so far):
HomeScreen:
sm: sm
name: 'ScreenManager'
BoxLayout:
orientation: 'vertical'
rows: 2
ActionBar:
pos_hint: {'top': 1}
size_hint_y: .065
ActionView:
ActionButton:
text: 'Cocktails'
on_press:
root.switch(1)
ActionButton:
text: 'Drinks'
on_press:
root.switch(2)
ActionButton:
text: 'Einstellungen'
on_press:
root.switch(3)
ScreenManager:
id: sm
size_hint_y: .935
Screen1:
name: "screen1"
id: screen1
Screen2:
name: "screen2"
id: screen2
<Screen1#Screen>:
name: "screen_1"
id: screen1
#Here should the Buttons in GridLayout appear
<Screen2#Screen>:
name: "screen_2"
id: screen2
#This is the Custom Button I want to be inserted above
<Drink_Widget#Button>:
image_path_optn: image_path
lable_text_optn: lable_text
Button:
size_hint_x: None
size_hint_y: None
height: (root.height) -10
width: 250
on_press:
BoxLayout:
orientation: "vertical"
width: root.width
height: root.height
pos_hint: root.pos
pos: root.pos
padding: 5
Image:
source: image_path
Label:
text: label_text
I want to show a various number of DrinkWidgets on screen1 vertically and add them in runtime. But I always end up with nothing showing up or with _event.pyx not found error. Passing the code under <Screen1#Screen>: directly works.
I hope someone can help me. Thanks a lot!
Okay, it looks like you want to add a number of your DrinkWidgets to your screen when your app loads. First things first, in your .py file you have defined a class named Drink_widget but in .kv you call it DrinkWidget
Next, since you have your DrinkWidget defined as inheriting the Button class from kivy, you can easily change the text in the DrinkWidget using the text: field. Similarly, you can change the image that the button displays to be whatever you like using the background_normal: field. To change the image displayed when you click the button, use the background_down: field. Example:
<DrinkWidget#Button>:
text: "some text"
background_normal: "image1.png"
background_down: "image2.png"
So you don't need your lable_text_optn or image_path_optn fields.
Also, you are trying to add a number of widgets to a Screen widget, when really you should be adding a number of widgets to a Layout widget (FloatLayout, BoxLayout, or GridLayout). Your Screen widget should only have the Layout widget as its direct child.
Another issue I see is you have two root widgets inside your .kv file -- HomeScreen and BoxLayout unless your indentation is correct in the question.
Here is a minimal example of what I believe you are trying to get working:
main.py
from kivy.app import App
from kivy.uix.button import Button
class DrinkWidget(Button):
pass
class MainApp(App):
def on_start(self):
# This command is automatically called when your app loads up
the_screen_grid = self.root.ids.some_descriptive_id
# self.root refers to the root widget, which is the GridLayout
# self.root.ids gets me a DictProperty of all children widgets that have an id associated with them
# self.root.ids.some_descriptive_id gets me the GridLayout widget I defined with the id: some_descriptive_id
for i in range(3):
the_screen_grid.add_widget(DrinkWidget(text="drink " + str(i)))
MainApp().run()
main.kv
GridLayout:
cols: 1
Screen:
# Widgets that aren't Layouts normally only have 1 child widget
# To "add multiple widgets" to a screen, give the screen a Layout, then add widgets to the layout
GridLayout:
id: some_descriptive_id
rows: 1
Your code is a bit too long to give you an exact solution for your case, but I hope this example gives you the knowledge to fix it up for yourself!

How to get/pass current ScreenManager to button callback function? (no kv file in use)

Question is simple. I have ScreenManager as sm variable, how do I get that, and screen information in to button callback. Thank you already for possible solutions.
Below is the issue part of my code, I have commented the section that I need to solve:
def build(self):
def callback_home(dt):
# How do I get the current sreenmanager here so
# things would work as below
sm.switch_to(screen1, direction='left')
app = FloatLayout()
# Ui top
anchor_top = AnchorLayout(anchor_x='center', anchor_y='top')
app.add_widget(anchor_top)
box_top = BoxLayout(orientation='horizontal',
size_hint=(1.0, 0.1))
anchor_top.add_widget(box_top)
btn_home = Button(text='Home')
btn_home.bind(on_press=callback_home) #Callback line is in here
btn_add = Button(text='Add')
btn_upload = Button(text='Upload')
box_top.add_widget(btn_home)
box_top.add_widget(btn_add)
box_top.add_widget(btn_upload)
# Ui bottom
anchor_bottom = AnchorLayout(anchor_x='center', anchor_y='bottom')
app.add_widget(anchor_bottom)
sm = ScreenManager(size_hint=(1.0, 0.9))
anchor_bottom.add_widget(sm)
screen1 = Screen(name='Home')
screen1.add_widget(Label(text='Home'))
sm.add_widget(screen1)
screen2 = Screen(name='Add')
screen2.add_widget(Label(text='Add'))
sm.add_widget(screen2)
screen3 = Screen(name='Upload')
screen3.add_widget(Label(text='Upload'))
sm.add_widget(screen3)
return app
Define your callback function after your create the ScreenManager. But this is 10 times easier if you use kv language.
Also - ScreenManager.switch_to() only works with new Screens. Using this method to switch to a Screen which has already been added to a ScreenManager will throw an Exception.
Finally, your layout can be much simpler if you use a BoxLayout instead of a FloatLayout and AnchorLayouts.
BoxLayout:
orientation: 'vertical'
BoxLayout:
size_hint_y: 0.1
Button:
text: 'Home'
on_press: sm.current = 'Home'
Button:
text: 'Add'
on_press: sm.current = 'Add'
ScreenManager:
id: sm
Screen:
name: 'Home'
Label:
text: 'Home'
Screen:
name: 'Add'
Label:
text: 'Add'

Resources