I'm having trouble dynamically adding widgets in my kv file, everything I've seen so far has been around adding widgets in the py file. The reason I'd like to use the kv file for this is that I've got a modified Button widget I'd like to use that's written in the kv file and I don't know how to create it in the py file.
So I guess there are two possible questions:
1) How do I use add_widget correctly in the kv file. In the below code I get the NameError: SmoothButton is not defined.
Or
2) How do I create my SmoothButton in the py file?
kv file:
WindowManager:
ChatPage:
<ChatPage>:
name: "chat_page"
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
NavigationDrawerIconButton:
text: "Test"
on_release: app.root.current = "login"
FloatLayout:
MDToolbar:
pos_hint: {'top': 1}
md_bg_color: 0.2, 0.6, 1, 1
left_action_items: [['menu', lambda x: root.ids.nav_layout.toggle_nav_drawer()]]
Button:
text: "Create button"
pos_hint: {"x": 0.65, "top": 0.15}
size_hint: 0.35, 0.15
on_release: root.add_widget(SmoothButton)
<SmoothButton#Button>:
background_color: 0,0,0,0
background_normal: ""
back_color: 1,0,1,1
border_radius: [6]
canvas.before:
Color:
rgba: self.back_color
RoundedRectangle:
size: self.size
pos: self.pos
radius: self.border_radius
py file:
import kivy
from kivy.app import App
from kivy.properties import ObjectProperty, StringProperty, NumericProperty, ListProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.core.window import Window
from kivymd.theming import ThemeManager
import mysql.connector
from kivymd.uix.picker import MDDatePicker
class ChatPage(Screen):
pass
class WindowManager(ScreenManager):
pass
class MyApp(App):
theme_cls = ThemeManager()
def build(self):
kv = Builder.load_file("kivy.kv")
sm = WindowManager()
screens = [ChatPage(name="chat_page")]
for screen in screens:
sm.add_widget(screen)
sm.current = "chat_page"
return sm
if __name__ == '__main__':
MyApp().run()
Thanks
If you want to add modified widgets in the .kv it doesn't mean you have to add it there. The solution is to expose the modified widget in the .kv to the .py, and create a method in "ChatPage" where you add the widget:
*.py
# ...
class SmoothButton(Button):
pass
class ChatPage(Screen):
def on_released(self):
self.add_widget(SmoothButton())
# ...
*.kv
# ...
<ChatPage>:
name: "chat_page"
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
NavigationDrawerIconButton:
text: "Test"
on_release: app.root.current = "login"
FloatLayout:
MDToolbar:
pos_hint: {'top': 1}
md_bg_color: 0.2, 0.6, 1, 1
left_action_items: [['menu', lambda x: root.ids.nav_layout.toggle_nav_drawer()]]
Button:
text: "Create button"
pos_hint: {"x": 0.65, "top": 0.15}
size_hint: 0.35, 0.15
on_release: root.on_released() # <---
<SmoothButton>: # <---
background_color: 0,0,0,0
# ...
Related
I am a new programmer, working on a Kivy app and I need to use screens (screen manager), the issue is that I am using element cards as but buttons, and it is supposed that when using on_release it will change the screen, however if I include root.manager.transition.direction = "left" I get the error AttributeError: 'MyContentComunes' object has no attribute 'screen'. I don't know if anyone could help me with this.
Here is a piece of code.
from kivy.app import App
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivymd.uix.expansionpanel import MDExpansionPanel, MDExpansionPanelTwoLine
from kivy.core.window import Window
from kivymd.color_definitions import colors
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.screen import MDScreen
KV = '''
WindowManager:
id: screen_manager
PrincipalWindow:
LenghtWindow:
<PrincipalWindow>:
name: "principal"
BoxLayout:
MDToolbar:
title: "Conversor"
pos_hint: {"top": 1}
ScrollView:
pos_hint: {"center_x": .5, "center_y": .5} #UbicaciĆ³n
size_hint: 0.90, 0.75
GridLayout:
halign: 'center'
cols: 1
adaptive_height: True
id: box
<LenghtWindow>:
name: "Lenght"
md_bg_color: 0.34,0.024,0.292,1
MDBoxLayout:
orientation: "vertical"
MDToolbar:
title: "Conversor"
pos_hint: {"top": 1}
Button:
text: "Back"
font_size: 32
on_release:
app.root.current = "principal"
root.manager.transition.direction = "right"
<MyContentComunes>:
orientation: 'vertical'
padding: dp(10)
spacing: dp(10)
size_hint_y: None
height: self.minimum_height
ElementCard:
image:"1490820814-13_82405.png"
text:"Longitud"
id:longitud
on_release:
app.root.current = "Lenght"
root.manager.transition.direction = "left"
<ElementCard#MDCard>:
md_bg_color: app.theme_cls.primary_color
padding: dp(15)
spacing: dp(15)
size_hint: 1, None
ripple_behavior: True
# on_release: print("worked")
image:''
text:""
items_count:""
subtext:''
orientation: "vertical"
Image:
source:root.image
halign:"center"
padding: dp (4)
spacing: dp(4)
MDBoxLayout:
orientation: "vertical"
MDLabel:
halign:"center"
text:root.text
MDLabel:
halign:"center"
font_style:"Caption"
text:root.subtext
'''
Window.size = 324, 720
class Conversor(MDApp):
def build(self):
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.list_items = [] # Dictionary where the items are stored
self.category_list1 = ['Comunes']
def on_start(self):
for category in self.category_list1:
self.root.get_screen('principal').ids.box.add_widget(
MDExpansionPanel(
icon="3.png",
content=MyContentComunes(),
panel_cls=MDExpansionPanelTwoLine(
text=category,
secondary_text="Ver las unidades"
)
)
)
class MyContentComunes(BoxLayout):
pass
class PrincipalWindow(Screen):
pass
class LenghtWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
Conversor().run()
The element card is inside an expansion panel, which is also inside a screen.
Try adding Screen to class MyContentComunes.
class MyContentComunes(BoxLayout, Screen):
pass
And I recommend you to organize your code like this. It will make your work more eaisier.
from kivy.app import App
from kivymd.app import MDApp
# import libraries ...
KV = '''
# Your KV File
'''
Window.size = 324, 720
class MyContentComunes(BoxLayout, Screen):
pass
class PrincipalWindow(Screen):
pass
class LenghtWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class Conversor(MDApp):
def build(self):
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
def __init__(self, **kwargs):
# Code
.
.
.
def on_start(self):
# Code
.
.
.
Conversor().run()
I have this small issue where I'm trying to create a label in LabelScreen when a button in the MenuScreen is pressed. The closest I managed to do was making the Label appear in the same screen as the button.
The following code is just an simple example of what I would like to acheive. Any help is always appreciated!
.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.button import Button,ButtonBehavior
from kivy.uix.image import Image
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.popup import Popup
from kivy.core.window import Window
from kivy.properties import ObjectProperty, NumericProperty
class MenuScreen(Screen):
def Item1(self,button):
App.get_running_app().cart += 5
label1 = Label(text="Item 1: $5", font_size=25)
self.add_widget(label1)
class LabelScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(App):
cart = NumericProperty(0)
def build(self):
return WindowManager()
if __name__ == "__main__":
ExampleApp().run()
.kv
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
<WindowManager>:
MenuScreen:
LabelScreen:
<MenuScreen>:
name: "menu"
FloatLayout:
Button:
text: "Add to cart"
size_hint: 0.5,0.05
pos_hint: {"x": 0.25, "y": 0.25}
on_release:
root.Item1(self)
Label:
text: "Cart: " + str(app.cart)
font_size: 25
pos_hint: {"x": 0.25, "y": 0.25}
Button:
text: "Label Screen"
size_hint: 0.5,0.05
pos_hint: {"x": 0.25, "y": 0.1}
on_release:
app.root.transition = SlideTransition(direction = "left")
app.root.current = "label"
<LabelScreen>:
name: "label"
FloatLayout:
Label:
text: "I want Item1 Label to appear here \n instead of in the MenuScreen"
font_size: 25
pos_hint: {"x": 0, "y": 0.25}
Button:
text: "Back"
size_hint: 0.5,0.05
pos_hint: {"x": 0.25, "y": 0.1}
on_release:
app.root.transition = SlideTransition(direction = "right")
app.root.current = "menu"
You have to reference the right screen window you want to add the wiget.
Since you are adding the widget whitin the python class first we have to get the app running, then we can navigate to the screen we want:
def Item1(self,button):
App.get_running_app().cart += 5
label1 = Label(text="Item 1: $5", font_size=25)
app_running = App.get_running_app()
root_screen = app_running.root
label_screen = root_scren.get_screen('label')
label_screen.add_widget(label1)
# Or simply:
# App.get_running_app().root.get_screen('label').add_widget(label1)
I am new to Kivy and I recently started to create my own application. But there's one problem I have that I can't figure out why it's doing it.
Basically when I open my app and press the button to go to the other screen it does the sliding transition succesfully. But when I open a pop up and close it and hit the same button again, it doesn't do any transition and both screens overlap each other. Why exactly is this the case?
The thing that almost fixed it is using self.manager.current = "second" in the python file but the sliding animation is still not there and it just cuts to the next screen. Or pehaps is there a way to make the sliding animation inside the python file?
I have provided a simple example code to demonstrate the issue. I didn't want to put all of what I've done since it would be too much code.
Any help or suggestions would be appriciated!
Here is the example code
import kivy
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.button import Button,ButtonBehavior
from kivy.uix.widget import Widget
from kivy.uix.screenmanager import Screen, ScreenManager, SlideTransition, CardTransition, FadeTransition
from kivy.uix.popup import Popup,PopupException
from kivy.lang import Builder
class FirstScreen(Screen):
def screen1btn(self):
popup = FloatLayout()
pop = Popup(title="Popup", content=popup, size_hint=(0.6, 0.6))
pop.open()
class SecondScreen(Screen):
pass
class WindowManager(ScreenManager):
pass
class ExampleApp(App):
def build(self):
return WindowManager()
if __name__ == "__main__":
ExampleApp().run()
.kv file
#:import SlideTransition kivy.uix.screenmanager.SlideTransition
<WindowManager>:
FirstScreen:
SecondScreen:
<FirstScreen>:
name: "first"
FloatLayout:
Label:
text: "Screen 1"
font_size: 20
pos_hint: {"x": 0.35,"y": 0.3}
Button:
text: "Popup"
size_hint: 0.3,0.1
pos_hint: {"x": 0.35,"y": 0.4}
on_release:
app.root.transition = SlideTransition(direction = "left")
app.root.current = root.screen1btn()
Button:
text: "Go to second screen"
size_hint: 0.5,0.1
pos_hint: {"x": 0.35,"y": 0.1}
on_release:
app.root.transition = SlideTransition(direction = "right")
app.root.current = "second"
<SecondScreen>:
name: "second"
FloatLayout:
Label:
text: "Screen 2"
font_size: 20
pos_hint: {"x": 0.35,"y": 0.3}
Button:
text: "Go back"
size_hint: 0.5, 0.1
pos_hint: {"x": 0.35,"y": 0.1}
on_release:
app.root.transition = SlideTransition(direction = "left")
app.root.current = "first"
The problem is your 'kv' code for the Popup Button:
Button:
text: "Popup"
size_hint: 0.3,0.1
pos_hint: {"x": 0.35,"y": 0.4}
on_release:
app.root.transition = SlideTransition(direction = "left")
app.root.current = root.screen1btn()
Not sure what that is tying to do, but I believe it should just be opening the Popup, like this:
Button:
text: "Popup"
size_hint: 0.3,0.1
pos_hint: {"x": 0.35,"y": 0.4}
on_release: root.screen1btn()
Note that the two lines referencing app.root have been removed. Now the Button just opens the Popup.
I was brainstorming an idea I had for a project but the one part I got stuck at was collecting a variable from a text input box and displaying its Value as a Label in another screen, I tried putting it in a variable then just calling it as the text for the label in the kivy file but it always came back as an error, what am I doing wrong.
Kivy-
WindowManager:
Enter_Name
List
<Enter_Name>
airline: input_1
name: 'enter_name'
id: enter_nom
FloatLayout:
cols: 3
size: root.size
Label:
text: "Name of Airline?"
size_hint: 1, 0.3
pos_hint: {"x": 0, "top":1}
TextInput:
multiline: False
name: 'input_one'
id: input_1
size_hint: 0.6, 0.06
pos_hint: {"x": 0.20, "top":0.6}
Button:
size_hint: 0.2, 0.1
pos_hint: {"x": 0.4, "top":0.4}
text: "Enter"
on_release:
app.root.current = 'list'
root.line()
<List>
name: 'list'
Python -
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.lang import Builder
from kivy.uix.popup import Popup
import time
from kivy.properties import StringProperty
class Enter_Name(Screen):
input_1 = StringProperty()
def line(self):
self.gon = self.ids.input_1.text
print(self.gon)
pass
class List(Screen):
Enter_Name.line
pass
class WindowManager(ScreenManager):
pass
kv = Builder.load_file("pot.kv")
class am4(App):
def build(self):
return kv
if __name__ == "__main__":
am4().run()
Here is a modified version of your code that does what I think you want:
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
class Enter_Name(Screen):
def line(self):
App.get_running_app().root.get_screen('list').lab_text = self.airline.text
class List(Screen):
pass
class WindowManager(ScreenManager):
pass
# kv = Builder.load_file("pot.kv")
kv = Builder.load_string('''
WindowManager:
Enter_Name
List
<Enter_Name>
airline: input_1
name: 'enter_name'
id: enter_nom
FloatLayout:
cols: 3
size: root.size
Label:
text: "Name of Airline?"
size_hint: 1, 0.3
pos_hint: {"x": 0, "top":1}
TextInput:
multiline: False
name: 'input_one'
id: input_1
size_hint: 0.6, 0.06
pos_hint: {"x": 0.20, "top":0.6}
Button:
size_hint: 0.2, 0.1
pos_hint: {"x": 0.4, "top":0.4}
text: "Enter"
on_release:
app.root.current = 'list'
root.line()
<List>
lab_text: ''
name: 'list'
Label:
text: root.lab_text
''')
class am4(App):
def build(self):
return kv
if __name__ == "__main__":
am4().run()
I have added a Label to the List Screen, as well as a lab_text property that is used as the text of the Label. The line() method now just sets the value of that lab_text.
I have used load_string() instead of load_file() just for my own convenience.
I have a app in kivy with a screen manager and a popup within it. The popup works until the point I put a button with the close function into the popup window. At this point i get the message:
PopupException: Popup can have only one widget as content
There is another post on this topic but it does not seem to work.
The python code
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.lang import Builder
from kivy.uix.popup import Popup
class CustomPopup(Popup):
pass
class MainScreen(Screen):
pass
class ContentScreen(Screen):
def open_popup(self):
the_popup = CustomPopup()
the_popup.open()
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("am.kv")
class AMApp(App):
def build(self):
return presentation
if __name__ == "__main__":
AMApp().run()
The kivy file is below. The issue seems to come in the button function when calling the custompop
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
ContentScreen:
<CustomPopup>:
size_hint: .5 , .5
auto_dismiss: False
title: "The Popup"
Button:
text: "Close"
on_press: root.dismiss()
<MainScreen>:
name: "Welcome"
Button:
text: "First Screen"
size_hint: 1, .5
font_size: 40
pos_hint: {'center_x': 0.5, 'center_y': 0.7}
on_release: app.root.current = "other"
Button:
text: 'Welcome Mr and Mrs Shaw'
size_hint: 1, .5
font_size: 25
pos_hint: {'center_x': 0.5, 'center_y': 0.3}
on_release: app.root.current = "other"
<ContentScreen>:
name: "other"
BoxLayout:
orientation: "vertical"
size_hint_x: .22
Button:
text: "open Popup"
on_press: root.open_popup()
The code posted above, runs fine on Linux Buster, Kivy 1.11.0-dev and 1.10.1, and Python 3.7.3rc1
Solution
Try adding a layout e.g. BoxLayout into CustomPopup to solve the PopupException.
Example
The following example illustrates a popup window with a message and a button.
Snippets
<CustomPopup>:
size_hint: .5 , .5
auto_dismiss: False
title: "The Popup"
BoxLayout:
orientation: 'vertical'
Label:
text: "Hello Kivy"
Button:
text: "Close"
on_press: root.dismiss()