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'
Related
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.
I am working on the same issue from my previous post. Now I added screen manager, and I can switch to different pages.
why is my kivy program not calling the function from another class?
I am still confused about OOP with GUIs, however I tried the following, and none of them worked.
I tried to add an instance of Screen 1() in the main app(), and it did nothing. Then, I tried to add the contractor method init into Screen_1() and it says I don't have a build method. And few other ideas that didn't work at all.
Then I realized that there is no link between Screen_Manager() and Screen_1() because all of my methods are in Screen_1(), but the build method is returning Screen_Manager(). On my kv file, there is this code:
<Screen_Manager>:
Screen_1:
Screen_2:
isn't this is where the program "links" between the Screen_Manager() class to other classes?
if someone can help me understand what I am not understanding and help me correct my problem, it would help me to learn about kivy. I understand, <> is like apply to rules, which has 2 widgets screen 1 and screen 2, and also have their own rules.
here is my main.py
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.lang.builder import Builder
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.modules import keybinding
from kivy.core.window import Window
from kivy.uix.screenmanager import ScreenManager, Screen
class Screen_Manager(ScreenManager):
pass
class Screen_1(Screen):
main_display = ObjectProperty()
text_input = ObjectProperty()
def plus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value + 1)
def minus_1(self):
self.value = int(self.main_display.text)
self.main_display.text = str(self.value - 1)
def up(self):
self.main_display.text = self.text_input.text
self.text_input.text = ''
class Keyboard(Widget):
def __init__(self, instance):
super().__init__()
self.a = instance
self.keyboard = Window.request_keyboard(None, self)
self.keyboard.bind(on_key_down=self.on_keyboard_down)
def on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'enter':
self.a.up()
return True
class Screen_2(Screen):
pass
class MainApp(App):
def build(self):
self.title = "Number Control App"
self.sm = Screen_Manager()
key = Keyboard(self.sm)
return self.sm
if __name__=="__main__":
MainApp().run()
my kv file
<Screen_Manager>:
Screen_1:
Screen_2:
<Screen_1>:
name: "first"
main_display: display_1
text_input: text_input_1
#------inherenting from BoxLayout
BoxLayout:
orientation: "vertical"
#------begining of conent--
BoxLayout:
size_hint_y: 1
#-nexted content------
Label:
id: display_1
text: "0"
font_size: "150sp"
background_color: 0.1, 0.5, 0.6,
#--------
BoxLayout:
size_hint_y: .35
orientation: "horizontal"
#-nexted content------
Button:
text: "-"
font_size : "60sp"
on_press: root.minus_1()
#-nexted content------
Button:
text: "+"
font_size : "35sp"
background_color: (0, 1, 0, 1)
on_press: root.plus_1()
#--------
BoxLayout:
size_hint_y: .15
orientation: "horizontal"
#-nexted content-------
Button:
text: "Config"
size_hint_x: .25
on_release:
root.manager.current = "second"
root.manager.transition.direction = "left"
#-nexted content-------
TextInput:
id: text_input_1
size_hint_x: 1
hint_text: "Enter your initial # here"
multiline: False
#-nexted content-------
Button:
text: "Up"
size_hint_x: .25
on_press: root.up()
<Screen_2>:
name: "second"
Button:
text: "Go Back"
on_press:
app.root.current = "first"
root.manager.transition.direction = "right"enter code here
thanks again for taking the time to help.
Not sure I understand your question, but pressing Enter in your TextInput executed your code:
self.a.up()
but a in your KeyBoard is the Screen_Manager as set at the line:
self.sm = Screen_Manager()
key = Keyboard(self.sm)
and Screen_Manager has no up method. You can fix that by changing the code in your KeyBoard code to:
self.a.current_screen.up()
Note that this will only work when the current screen is Screen_1.
I have a error in my code, I want to get or to print the product text but when i run it it gave me an error.
here is my code:
import kivy
from kivy.properties import ObjectProperty
from selenium import webdriver
import requests
from selectorlib import Extractor
from selenium.webdriver.common.keys import Keys
from kivymd.app import MDApp
from kivy.app import App
from kivy.lang import Builder
KV = '''
BoxLayout:
product: product
size_hint: .8, .8
pos_hint: {"center_x": .5, "center_y": .5}
spacing: dp(100)
orientation: "vertical"
MDTextFieldRound:
id: product
hint_text: 'Enter a product'
icon_left: 'magnify'
on_text_validate: app.System()
'''
class Main(MDApp):
def build(self):
return Builder.load_string(KV)
product = ObjectProperty(None)
def System(self):
print(self.product.text)
if __name__ == "__main__":
Main().run()
it always gave me the next error
File "C:/Users/Yesnia/Desktop/PYTHON/Apps development/App/App_Checking_Store.py", line 34, in
System
print(self.product.text)
AttributeError: 'NoneType' object has no attribute 'text'
help me please
So you build your kv string but have no way to reference it. There are many ways to mend the situation, heres an example.
KV = '''
BoxLayout:
###product: product ### this does not achieve anything, you're just giving
#some generic box layout a product attribute. this does not assign the App attribute.
size_hint: .8, .8
pos_hint: {"center_x": .5, "center_y": .5}
spacing: dp(100)
orientation: "vertical"
MDTextFieldRound:
id: product
hint_text: 'Enter a product'
icon_left: 'magnify'
on_text_validate: app.System()
'''
class Main(MDApp):
product = ObjectProperty(None)
my_kv = None
def build(self):
self.my_kv = Builder.load_string(KV)
self.product = self.my_kv.ids.product
return self.my_kv
def System(self):
print(self.product.text)
notice the comment i've left in your kv string, the addition of the new my_kv attribute to your App class, and the changes I've made to your build function.
Hope this helps!
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!
I am new to Kivy. I would like multiple textInputs to be displayed properly inside the Kivy scrollView dynamically where the textInput size fits the content. The current code displays only 3 as the height of the gridLayout is set to 1000. I would like to use height: self.minimum_height so that I can dynamically add more textInputs and they will be displayed properly, however but cannot seem to get it working.
My kv file:
<MyNote#BoxLayout>:
orientation: 'vertical'
TextInput:
height: self.minimum_height
multiline: True
text_size: self.size
size_hint_y: None
text: '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15'
<MainNotesBoxLayout>
orientation: 'vertical'
ScrollView:
GridLayout:
cols: 1
size_hint_y: None
height: 1000
#height: self.minimum_height
MyNote:
MyNote:
MyNote:
My main file:
import kivy
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
class MainNotesBoxLayout(BoxLayout):
pass
class NotesApp(App):
def build(self):
return MainNotesBoxLayout()
if __name__ == '__main__':
NotesApp().run()
Replace GridLayout with BoxLayout
Set the minimum height of the boxlayout so that there is something to scroll.
ScrollView
layout.bind(minimum_height=layout.setter('height'))
Example
notes.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.textinput import TextInput
from kivy.properties import ObjectProperty
class MyNote(TextInput):
pass
class MainNotesBoxLayout(BoxLayout):
container = ObjectProperty(None)
def __init__(self, **kwargs):
super(MainNotesBoxLayout, self).__init__(**kwargs)
self.container.bind(minimum_height=self.container.setter('height'))
self.add_text_inputs()
def add_text_inputs(self):
for x in range(100):
my_note = MyNote()
self.container.add_widget(my_note)
class NotesApp(App):
def build(self):
return MainNotesBoxLayout()
if __name__ == '__main__':
NotesApp().run()
notes.kv
#:kivy 1.10.0
<MyNote>:
height: self.minimum_height
multiline: True
text_size: self.size
size_hint_y: None
text: '1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15'
<MainNotesBoxLayout>
container: container
orientation: 'vertical'
ScrollView:
size_hint: (1, 1)
bar_width: 10
bar_color: 1, 0, 0, 1 # red
bar_inactive_color: 0, 0, 1, 1 # blue
effect_cls: "ScrollEffect"
scroll_type: ['bars']
BoxLayout:
id: container
orientation: 'vertical'
size_hint: 1, None
Output