I'm trying to make a simple application that uses buttons to cycle through different strings with a label, but how would one get the strings from the .py file to the KV string?
For example, I want it to say '[x_string]' in the middle of the screen. When the user presses a button (arrow facing right), it goes to '[y_string]' instead. When the user presses the other button (arrow facing left), it goes back to '[x_string]', etc.
Here is the code I have so far.
from PyDictionary import PyDictionary
from kivy.metrics import dp
from kivy.properties import StringProperty
from kivymd.uix.list import OneLineIconListItem
from kivymd.uix.menu import MDDropdownMenu
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.toolbar import MDToolbar
from kivy.core.window import Window
from kivymd.uix.dialog import MDDialog
from kivymd.uix.button import MDFlatButton
from kivymd.uix.swiper import MDSwiper
from kivymd.uix.label import MDLabel
from pathlib import Path
KV = '''
ScreenManager:
Screen1:
<Screen1>:
name: 'screen'
MDScreen:
name: 'screen'
MDToolbar:
title: 'Test App'
elevation: 20
pos_hint: {'top': 1}
md_bg_color: (1, 1, 1, 1)
specific_text_color: (76/255, 76/255, 77/255, 1)
right_action_items: [["information"],["home"]]
FloatLayout:
# Left Arrow
Button:
background_normal: 'buttonsNormal/chevron_arrow_left.png'
background_down: 'buttonsDown/chevron_arrow_left_down.png'
size_hint: (0.06, 0.16)
pos_hint: {'center_x': 0.06, 'center_y': 0.445}
border: [0, 0, 0, 0]
# Right Arrow
Button:
background_normal: 'buttonsNormal/chevron_arrow_right.png'
background_down: 'buttonsDown/chevron_arrow_right_down.png'
size_hint: (0.06, 0.16)
pos_hint: {'center_x': 0.94, 'center_y': 0.445}
border: [0, 0, 0, 0]
'''
Window.size = (1280, 720)
class Screen1(Screen):
def build(self):
MDLabel(
text = 'Raise your arm.',
font_size = dp(56),
halign = 'center'
)
class MainApp(MDApp):
dialog = None
def build(self):
sm = ScreenManager()
sm.add_widget(Screen1(name = 'follow_screen'))
return Builder.load_string(KV)
MainApp().run()
I am leaving out about 800 lines of completely unrelated code, so that's why there are so many imported modules as the top.
Thank you!
You can add a Label to the Screen1 kv:
Label:
text: root.text
size_hint: 0.25, 0.25
color: 0,0,0,1
size: self.texture_size
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
The text for this Label is set to root.text, which should be a StringProperty in the Screen1 class:
class Screen1(Screen):
text = StringProperty('x_string')
Then, you can adjust the value of the StringProperty Like this:
# Left Arrow
Button:
background_normal: 'buttonsNormal/chevron_arrow_left.png'
background_down: 'buttonsDown/chevron_arrow_left_down.png'
size_hint: (0.06, 0.16)
pos_hint: {'center_x': 0.06, 'center_y': 0.445}
border: [0, 0, 0, 0]
on_press:
root.text = 'x_string'
# Right Arrow
Button:
background_normal: 'buttonsNormal/chevron_arrow_right.png'
background_down: 'buttonsDown/chevron_arrow_right_down.png'
size_hint: (0.06, 0.16)
pos_hint: {'center_x': 0.94, 'center_y': 0.445}
border: [0, 0, 0, 0]
on_press:
root.text = 'y_string'
Related
I want to make a 2 Slide Carousel with auto scrolling in KivyMD with Python. On Startup, the App starts from the The first Slide of Carousel and it should be changed to 2nd slide after 3 seconds.
Here is my Code
.kv
<WelcomeScreen>:
MDFloatLayout:
md_bg_color : 1, 1, 1, 1
Carousel:
id: caraousel
on_current_slide: app.current_slide(self.index)
MDFloatLayout:
Image:
source: "Assets/1.png"
pos_hint: {"center_x": .5, "center_y": .6}
size_hint: .3, .3
MDLabel:
text: "Slide 1"
pos_hint: {"center_y": .087}
halign: "center"
font_name: "Poppins-Light"
font_size: "14sp"
color: rgba(135, 143, 158, 200)
MDFloatLayout:
Image:
source: "Assets/2.jpg"
pos_hint: {"center_x": .5, "center_y": .7}
size_hint: .8, .8
MDLabel:
text: "Slide 2"
pos_hint: {"center_y": .47}
halign: "center"
font_name: "Poppins-Regular"
font_size: "25px"
color: rgba(1, 3, 23, 225)
.py
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen,ScreenManager, NoTransition
from kivy.utils import rgba
from kivy.core.window import Window
from kivy.core.text import LabelBase
from kivy.clock import Clock
Window.size = (310, 580)
class WelcomeScreen(Screen):
pass
class AppApp (MDApp):
def build(self):
return Builder.load_file('app.kv')
def current_slide(self, index):
pass
AppApp().run()
Anyone can help me with this Issue? Thanks in Advance.
You can use method Clock.schedule_interval to perform automatic loading of sliders. Trigger that action from anywhere in your code, for example to make it happen from the very beginning, trigger it from the method on_start of class app as,
app.kv file.
<WelcomeScreen>:
MDFloatLayout:
md_bg_color : 1, 1, 1, 1
Carousel:
id: caraousel
on_current_slide: app.current_slide(self.index)
MDFloatLayout:
Image:
source: "Assets/1.png"
pos_hint: {"center_x": .5, "center_y": .6}
size_hint: .3, .3
MDLabel:
text: "Slide 1"
pos_hint: {"center_y": .087}
halign: "center"
# font_name: "Poppins-Light"
font_size: "14sp"
color: rgba(135, 143, 158, 200)
MDFloatLayout:
Image:
source: "Assets/2.jpg"
pos_hint: {"center_x": .5, "center_y": .7}
size_hint: .8, .8
MDLabel:
text: "Slide 2"
pos_hint: {"center_y": .47}
halign: "center"
# font_name: "Poppins-Regular"
font_size: "25px"
color: rgba(1, 3, 23, 225)
main.py file.
from kivy.lang import Builder
from kivymd.app import MDApp
from kivy.uix.screenmanager import Screen,ScreenManager, NoTransition
from kivy.utils import rgba
from kivy.core.window import Window
from kivy.core.text import LabelBase
from kivy.clock import Clock
Window.size = (310, 580)
class WelcomeScreen(Screen):
pass
class AppApp(MDApp):
def build(self):
Builder.load_file('app.kv')
return WelcomeScreen()
def on_start(self):
# Access the carousel.
carousel = self.root.ids.caraousel
# Set infinite looping (optional).
carousel.loop = True
# Schedule after every 3 seconds.
Clock.schedule_interval(carousel.load_next, 3.0)
def current_slide(self, index):
pass
AppApp().run()
Update:
Try avoiding the App's instance name as AppApp and related .kv file as app.kv simultaneously, that might cause problems during auto .kv loading. However loading the file explicitly and then returning the root from method build (or declaring in .kv file) should work.
i'm new in kivy programming and while it seems that there is a lot of documentation about this problem online, i don't seem to understand any of it so i hope you could help.
I have 4 Buttons and a label, by pressing the buttons, i'm hoping to move the label in that direction.
I have two variables pX and pY which are the label's position and want it to update its position each time these two are updated.
Thanks in advance.
// main.py
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color
from kivy.core.window import Window
from kivy.config import Config
from kivy.uix.floatlayout import FloatLayout
Window.size = (900, 600)
Config.set('graphics', 'resizable', True)
class FloatLayout(FloatLayout):
pX = 0.6
pY = 0.1
class FenetreApp(App):
def build(self):
return FloatLayout()
FenetreApp().run()
//fenetre.kv
<Button>:
size_hint: 0.1, 0.1
background_color: 0.1, 0.5, 0.6, 1
<Label>:
size_hint: 0.1, 0.1
background_color: 1, 0, 0, 1
canvas.before:
Color:
rgb: 0.1, 0.6, 0
Rectangle:
pos: self.pos
size: self.size
<FloatLayout>:
Button:
text: "Up"
pos_hint: {"x":0.8, "top":1}
on_press: root.pY= root.pY +0.1
Button:
text: "Down"
pos_hint: {"x":0.8, "top":0.8}
on_press: root.pY= root.pY -0.1
Button:
text: "Left"
pos_hint: {"x":0.7, "top":0.9}
on_press: root.pX= root.pX -0.1
Button:
text: "Right"
pos_hint: {"x":0.9, "top":0.9}
on_press: root.pX= root.pX +0.1
Label:
name: "L1"
text: "I wanna move"
pos_hint: {"x":root.pY, "top":root.pY} ```
You need to use NumericProperty for numeric values.Otherwise, kivy doesn't update its own childrens positions, texts and other stuffs.But if you don't want to use'em, check this code. I hope its clean to understand how it works:
main.py:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
Window.size = (900, 600)
kv = Builder.load_string('''
FloatLayout:
pY: .5
pX: .5
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Up"
pos_hint: {"x":0.8, "y":.8}
on_press: self.parent.pY+=.1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Down"
pos_hint: {"x":0.8, "top":0.8}
on_press: self.parent.pY-=.1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Left"
pos_hint: {"x":0.7, "top":0.9}
on_press: self.parent.pX-= .1
Button:
size_hint:.1,.1
background_color: 0.1, 0.5, 0.6, 1
text: "Right"
pos_hint: {"x":0.9, "top":0.9}
on_press: self.parent.pX+=.1
Label:
size_hint: .1,.1
text: "I like to moving moving"
pos_hint: {"x":self.parent.pX, "top":self.parent.pY}
''')
class sahm(App):
def build(self):
return kv
if __name__ == '__main__':
sahm().run()
The widgets on my popup window do not resize when the root window resizes. The popup window and the labels on the popup window stay where they are. Does it have something to do with the size_hint and size of the popup window itself? It seems that the widgets(icons) are independent of the popup window.
main file
from kivy.app import App
from kivy.uix.screenmanager import Screen
from kivy.uix.button import ButtonBehavior
from kivy.uix.image import Image
from kivy.properties import StringProperty, ObjectProperty,NumericProperty
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
class MainScreen(Screen, FloatLayout):
mantra_text = ObjectProperty(None)
def printMantra(self):
print(self.ids.mantra_text.text)
def icon_popup(self):
popup = Popup(title="Profile Icon", content=Popup_Content(), size_hint=(None, None), size=(300, 200))
popup.open()
class Popup_Content(FloatLayout):
pass
class ImageButton(ButtonBehavior, Image):
pass
class MainApp(App):
def build(self):
return MainScreen()
def set_profile_icon(self, image):
self.root.ids.profile_icon.source = image.source
print(image)
#print(self.root.ids.profile_icon)
MainApp().run()
kivy file
#:import utils kivy.utils
<MainScreen>
Popup_Content:
id: popup_content
FloatLayout:
canvas:
Color:
rgb: utils.get_color_from_hex("#ffbb99")
Rectangle:
pos: self.pos
size: self.size
GridLayout:
cols: 2
pos_hint: {"x":0.6, "top":1}
size_hint: 0.4,0.2
spacing_horizontal: [0.9*root.width]
Label:
text: "Name"
ImageButton:
id: profile_icon
source: "profile_icon"
on_release: root.icon_popup()
Label:
text: mantra_text.text
pos_hint: {"x":0, "top":0.8}
size_hint: 1, 0.2
text_size: self.size
halign: "center"
font_size: 25
TextInput:
id: mantra_text
pos_hint: {"x": 0.15, "top":0.6}
size_hint: 0.7, 0.1
#text_size: self.size
Label:
text: "Time"
pos_hint: {"x":0.3, "top":0.6}
size_hint: 0.4, 0.2
text_size: self.size
halign: "left"
font_size: 30
Button:
text: "Time"
pos_hint: {"x":0.3, "top":0.5}
size_hint: 0.4, 0.2
on_release: root.printMantra()
<Popup_Content>
#profile_icon: profile_icon
FloatLayout:
GridLayout:
cols: 5
pos_hint: {"x":0.95, "y":1.6}
ImageButton:
id: man_01
source: "icons/male_icon_01.png"
on_release: app.set_profile_icon(man_01)
ImageButton:
id: man_02
source: "icons/male_icon_02.png"
on_release: app.set_profile_icon(man_02)
ImageButton:
source: "icons/male_icon_01.png"
on_release: app.set_profile_icon()
ImageButton:
source: "icons/male_icon_01.png"
on_release: app.set_profile_icon()
ImageButton:
source: "icons/male_icon_01.png"
on_release: app.set_profile_icon()
ImageButton:
id: female_01
source: "icons/female_icon_01.png"
on_release: app.set_profile_icon(female_01)
If you want your Popup to change size when you resize the App, then use size_hint. Something like:
popup = Popup(title="Profile Icon", content=Popup_Content(), size_hint=(0.5, 0.5))
Using size_hint=(None, None), size=(300, 200) forces the Popup size to (300, 200) regardless of the size of MainScreen.
And to get the Popup content to follow the Popup, you can use RelativeLayout. In the documentation for RelativeLayout, it says:
When a widget with position = (0,0) is added to a RelativeLayout, the
child widget will also move when the position of the RelativeLayout is
changed. The child widgets coordinates remain (0,0) as they are always
relative to the parent layout.
So if you define your Popup_Content as a RelativeLayout, then the GridLayout will follow it. I suggest defining Popup_Content as:
class Popup_Content(RelativeLayout):
pass
Then, in the kv:
<Popup_Content>
#profile_icon: profile_icon
GridLayout:
cols: 5
# pos_hint: {"x":0.95, "y":1.6}
ImageButton:
id: man_01
.
.
.
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
# ...
I've some problems with multiple MDLabels in BoxLayout (that is contains by AnchorLayout), so all the MDLabel objects are stacked in one place on the screen!
I dont know how to make them centered and grouped like a list (with spacing and e.g.)
Please, help me with solving that problem!
Thanks a lot and sorry for bad english.
There is my main.py
from kivy.app import App
from kivymd.theming import ThemeManager
from kivymd.label import MDLabel
from kivy.uix.screenmanager import Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.metrics import dp, sp, pt
def toast(text):
from kivymd.toast.kivytoast import toast
toast(text)
class MyScreen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.menu_items = [
{
"viewclass": "MDMenuItem",
"text": "text%d" % i,
"callback": self.callback,
}
for i in range(1, 3)
]
self.menu_button = None
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
def callback(self, *args):
toast(args[0])
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen()
if __name__ == "__main__":
MainApp().run()
And there is my main.kv file contains:
#:import MDDropdownMenu kivymd.menus.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
#:import MDLabel kivymd.label.MDLabel
<MDMenuItem>:
on_release:
app.root.change_variable(self.text)
app.root.menu_button.text = self.text
<MyScreen>:
name: 'myscrn'
AnchorLayout:
anchor_y: 'center'
BoxLayout:
orientation: 'vertical'
size_hint: 0.1, 0.5
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
spacing: dp(10)
MDRaisedButton:
id: mainbutton
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton1'
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
opposite_colors: True
on_release:
root.menu_button = mainbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
MDRaisedButton:
id: secondbutton
size_hint: None, None
size: 3 * dp(48), dp(48)
text: 'MDButton2'
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
opposite_colors: True
on_release:
root.menu_button = secondbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
AnchorLayout:
anchor_y: 'top'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.5
padding: [0, 0, 0, 0]
spacing: dp(5)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDLabel:
font_size: dp(12)
text: '123'
MDLabel:
font_size: dp(22)
text: '456'
Woops, looks like a simple mistake. Your indentation on KV Lang is incorrect. You didn't nest your labels into BoxLayout correctly.
AnchorLayout:
anchor_y: 'top'
BoxLayout:
orientation: 'vertical'
size_hint: 0.95, 0.5
padding: [0, 0, 0, 0]
spacing: dp(5)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDLabel:
font_size: dp(12)
text: '123'
MDLabel:
font_size: dp(22)
text: '456'"""