Hi I was wondering how to make a dropdown menu and I cant figure it out I have read the documentation but I do not understand so I would be grateful if someone told my the problem with my attempt at is in my code.
PYTHON FILE:
from kivymd.app import MDApp
from kivymd.uix.screen import Screen
from kivymd.uix.button import MDRectangleFlatButton, MDRoundFlatButton
from kivymd.uix.textfield import MDTextField
from kivy.lang import Builder
from kivymd.uix.menu import MDDropdownMenu
from kivy.metrics import dp
from kivy.properties import StringProperty
from kivymd.uix.list import OneLineIconListItem
class IconListItem(OneLineIconListItem):
icon = StringProperty()
class DemoApp(MDApp):
def show_data(self):
inputFahrenheit = self.root.ids.fahrenheit.text
print(inputFahrenheit)
def fahrenheitSelected(self):
fahrenheit = True
celsius = False
def on_start(self):
self.theme_cls.primary_palette = "Green"
self.theme_cls.primary_hue = "A700"
self.theme_cls.theme_style = "Light"
self.dropdown1 = MDDropdownMenu()
self.dropdown1.items.append(
{"viewclass": "MDMenuItem",
"text": "option1",
"callback": self.callback()}
)
def callback(self):
print("cookies")
def build(self):
kv = Builder.load_file("test.kv")
screen = Screen()
return kv
DemoApp().run()
KV FILE:
Screen:
MDTextField:
id: fahrenheit
hint_text:"Enter Fahrenheit"
helper_text: "Once you enter the fahrenheit the press submit"
helper_text_mode: "on_focus"
icon_right: "temperature-fahrenheit"
pos_hint: {'center_x': 0.5, 'center_y': 0.9}
size: 200, 25
size_hint: None, None
MDRoundFlatButton:
text: "Enter"
pos_hint: {'center_x': 0.5, 'center_y': 0.2}
text_color: 0, 1, 0, 1
size_hint: 0.25, 0.20
on_release: app.show_data()
MDIconButton:
icon: "language-python"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.dropdown.open(root)
I don't know what is going on hear so I would appreciate it if someone knew the answer and posted it here.
I do not know what this class is - "MDMenuItem", you did not present it in your example, but as I understood you want to use it in the list menu, so I specified OneLineListItem as a viewclass, the list does not have a callback method (and in general it does not exist in almost all kivy classes), instead you should use on_release or on_press as in my example. If you do not want to use lambda, then you do not need to explicitly call the function - "on_release": self. callback. Also, to access some object of the class (in your example, it is MDDropdownMenu), it must be defined in __init__. Also, menu_items should be a list, not a dictionary as in your example, read the documentation carefully. You also forgot to specify the caller argument of the MDDropdownMenu class. I also noticed that you have the IconListItem class, but you don't use it anywhere, so I deleted it, if you want to create a list with icons, see this. And you should not specify the definition of the theme and color in the examples, this does not affect anything.
from kivymd.app import MDApp
from kivymd.uix.menu import MDDropdownMenu
from kivy.properties import StringProperty
from kivy.lang import Builder
KV = """
Screen:
MDTextField:
id: fahrenheit
hint_text:"Enter Fahrenheit"
helper_text: "Once you enter the fahrenheit the press submit"
helper_text_mode: "on_focus"
icon_right: "temperature-fahrenheit"
pos_hint: {'center_x': 0.5, 'center_y': 0.9}
size: 200, 25
size_hint: None, None
MDRoundFlatButton:
text: "Enter"
pos_hint: {'center': (0.5,0.2)}
text_color: 0, 1, 0, 1
size_hint: 0.25, 0.20
on_release: app.show_data()
MDIconButton:
id: button
icon: "language-python"
pos_hint: {"center_x": .5, "center_y": .5}
on_release: app.dropdown1.open()
"""
class DemoApp(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_string(KV)
menu_items = [
{
"viewclass": "OneLineListItem",
"text": "Option1",
"on_release": lambda *args: self.callback()
}
]
self.dropdown1 = MDDropdownMenu(items=menu_items, width_mult=4, caller=self.screen.ids.button)
def build(self):
return self.screen
def show_data(self):
input_fahrenheit = self.root.ids.fahrenheit.text
print(input_fahrenheit)
#staticmethod
def callback():
print("cookies")
DemoApp().run()
Related
I followed a tutorial on youtube so I could learn how to use kivy, but when I try to switch screen it doesn't work, I write my code the exact same way the guy does it, but for some reason nothing happens when I click the button "Se dine produkter".
I have written where I need help in the .kv file, I added the rest of the code only in case if you need to know why I have done certain things. In line 10 and 25 I have written what I want to happen, I have tried so many different things and different ways to approach what I want, but I haven't succeed with any of them.
main.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file("struktur.kv")
class HovedVindu(Screen and Widget):
def nyttProdukt(self):
show_popup()
def dineProdukter(self):
print("dine produkter")
ScreenManager.current = "dineprodukter"
def leggTilNyttProdukt(self, navn, dato):
self.navn = navn
self.dato = dato
print(self.navn, self.dato)
class DineProdukter(Screen):
pass
class WindowManager(ScreenManager):
pass
class P(FloatLayout):
pass
class MainApp(App):
def build(self):
return HovedVindu()
def show_popup():
show = P()
popupWindow = Popup(title="Legg til ett nytt produkt", content=show, size_hint=(None,None),size=(400,400), title_align="center")
popupWindow.open()
if __name__ == "__main__":
MainApp().run()
struktur.kv:
#:kivy 2.1.0
<WindowManager>:
HovedVindu:
DineProdukter:
<DineProdukter>:
name: "dineprodukter"
Button:
text: "Go to main"
on_release: switch to (hoved)
<HovedVindu>:
name: "hoved"
FloatLayout:
Button:
text: "Nytt produkt"
size_hint: 2, 1
pos_hint: {"x": 3, "top": 5}
on_release: root.nyttProdukt()
Button:
text: "Se dine produkter"
size_hint: 2, 1
pos_hint: {"x": 3, "top": 3}
on_release: switch to (dineprodukter)
<P>:
TextInput:
hint_text: "Navnet på produktet"
size_hint: .6, .15
pos_hint: {"x": .2, "top": .9}
TextInput:
hint_text: "Siste forbruksdag"
size_hint: .6, .15
pos_hint: {"x": .2, "top": .7}
Button:
text: "Legg til produkt"
size_hint: 0.8, 0.2
pos_hint: {"x":0.1, "y":0.1}
It happens because you are actually not using Screen Manager.
Please follow official kivy documentation on how to use ScreenManager.
https://kivy.org/doc/stable/api-kivy.uix.screenmanager.html
Example code of build function using ScreenManager:
def build(self) -> ScreenManager:
self.sm = ScreenManager()
self.sm.add_widget(SplashScreen(name='splash_screen'))
self.sm.add_widget(DownloadScreen(name='download_screen'))
self.sm.add_widget(InfoScreen(name='info_screen'))
self.sm.add_widget(FileManager(name='file_manager'))
return self.sm
Example usage in .kv file:
MDFillRoundFlatIconButton:
text: 'Download'
icon: 'download'
pos_hint: {'x': 0.77, 'y': 0.01}
md_bg_color: 64/255, 120/255, 192/255, 1
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'download_screen'
There is some other ways to do it, but I don't think your code is exactly the same as the code of the guy from YouTube. Stick to kivy documentation, it is actually good and you will learn 'kivy ways' of doing things.
Using switch_to(screen_name) not switch to(screen_name) won't work either if you won't use instance of your Screen Manager. Without that is just non existing function.
Here please you have your code fixed up a bit:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.popup import Popup
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Builder.load_file("struktur.kv")
class HovedVindu(Screen):
def nyttProdukt(self):
show_popup()
def dineProdukter(self):
print("dine produkter")
ScreenManager.current = "dineprodukter"
def leggTilNyttProdukt(self, navn, dato):
self.navn = navn
self.dato = dato
print(self.navn, self.dato)
class DineProdukter(Screen):
pass
class P(FloatLayout):
pass
class MainApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(HovedVindu(name="hoved"))
sm.add_widget(DineProdukter(name="dineprodukter"))
return sm
def show_popup():
show = P()
popupWindow = Popup(title="Legg til ett nytt produkt", content=show, size_hint=(None,None),size=(400,400), title_align="center")
popupWindow.open()
if __name__ == "__main__":
MainApp().run()
And kivy file:
#:kivy 2.1.0
<DineProdukter>:
FloatLayout:
Button:
text: "Go to main"
pos_hint: {"center_x": .5, "center_y": .5}
size_hint: .2, .2
on_release: root.manager.current = "hoved"
<HovedVindu>:
FloatLayout:
Button:
text: "Nytt produkt"
size_hint: .3, .1
pos_hint: {"x": .7, "y": .5}
on_release: root.nyttProdukt()
Button:
text: "Se dine produkter"
size_hint: .3, .1
pos_hint: {"x": .3, "y": .5}
on_release: root.manager.current = "dineprodukter"
<P>:
TextInput:
hint_text: "Navnet på produktet"
size_hint: .6, .15
pos_hint: {"x": .2, "top": .9}
TextInput:
hint_text: "Siste forbruksdag"
size_hint: .6, .15
pos_hint: {"x": .2, "top": .7}
Button:
text: "Legg til produkt"
size_hint: 0.8, 0.2
pos_hint: {"x":0.1, "y":0.1}
Haven't done everything but it displays screens and buttons do work.
I have kicked out your class of ScreenManager and actually created an instance of it in the root of your app. That way you can call it from any screen, as they are added to the Manager. Like you need to give screens to the Manager before it can manage it. That way always works fine and you won't experience any problems even if your app will contain 20 or more different classes with screens.
I'm new to KIVYMD and have been trying to play around by creating a log in screen that transfers the user to a new page. I've gotten making the core of the screen down, like adding the textfields and buttons, but am not sure how I can implement a screen changing functionality to my code. Any help is greatly appreciated.
For reference here is my main code block:
from kivymd.app import MDApp
from kivy.lang.builder import Builder
from helpers import username_helper,password_helper
from kivy.uix.screenmanager import Screen
from kivymd.uix.button import MDRectangleFlatButton
class Demo_app(MDApp):
def build(self):
screen = Screen()
self.theme_cls.primary_palette= "Pink"
self.username= Builder.load_string(username_helper)
screen.add_widget(self.username)
self.password = Builder.load_string(password_helper)
screen.add_widget(self.password)
login = MDRectangleFlatButton(text="Log In", pos_hint={"center_x": 0.5, "center_y":0.4})
screen.add_widget(login)
signin = MDRectangleFlatButton(text="Sign Up", pos_hint={"center_x": 0.5, "center_y": 0.3})
screen.add_widget(signin)
return screen
Demo_app().run()
And here is my .kv file:
username_helper="""
MDTextField:
hint_text: "Create/Enter your Username"
helper_text:"Or click here if you forgot your Username"
helper_text_mode: "on_focus"
icon_right: "language-python"
icon_right_color: app.theme_cls.primary_color
pos_hint:{"center_x":0.5,"center_y":0.6}
size_hint_x:None
width:300
"""
password_helper="""
MDTextField:
hint_text: "Create/Enter your Password"
helper_text:"Or click here if you forgot your password "
helper_text_mode: "on_focus"
icon_right: "language-python"
icon_right_color: app.theme_cls.primary_color
pos_hint:{"center_x":0.5,"center_y":0.5}
size_hint_x:None
width:300
"""
I think you want to transfer those textinput data to a label in different class. I think this is what you need.(keep an eye on ids):
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class FirstPage(FloatLayout):
def switch_screen(self):
secondpage = self.login_name = self.ids.login_name.text
myapp.secondpage.update_name1(secondpage)
secondpage = self.password_name = self.ids.password_name.text
myapp.secondpage.update_name2(secondpage)
myapp.screen_manager.transition = SlideTransition(direction='left', duration=.25)
myapp.screen_manager.current = 'SecondPage'
class SecondPage(FloatLayout):
def switch_back(self):
myapp.screen_manager.transition = SlideTransition(direction='right', duration=.25)
myapp.screen_manager.current = 'FirstPage'
def update_name1(self, name_login):
self.ids.name_login.text = (f'{name_login}:')
def update_name2(self, name_password):
self.ids.name_password.text = (f'{name_password}:')
class MyApp(App):
def build(self):
self.screen_manager = ScreenManager()
self.firstpage = FirstPage()
screen = Screen(name='FirstPage')
screen.add_widget(self.firstpage)
self.screen_manager.add_widget(screen)
self.secondpage = SecondPage()
screen = Screen(name='SecondPage')
screen.add_widget(self.secondpage)
self.screen_manager.add_widget(screen)
return self.screen_manager
myapp = MyApp()
myapp.run()
Here's kivy code:
FirstPage:
<FirstPage>:
TextInput:
id: login_name
size_hint: .65, .08
multiline: False
font_size: 20
pos_hint: {'x': .2, 'y': .57}
TextInput:
id: password_name
size_hint: .65, .08
multiline: False
font_size: 20
pos_hint: {'x': .2, 'y': .47}
Button:
text: "First"
size_hint: .1, .1
on_release: root.switch_screen()
<SecondPage>:
Button:
text: "Second"
size_hint: .1, .1
on_release: root.switch_back()
Label:
id: name_login
text: "Login"
size_hint: .2, .2
pos_hint: {'x': .2, 'y': .57}
Label:
id: name_password
text: "Password"
size_hint: .2, .2
pos_hint: {'x': .2, 'y': .47}
I'm trying to display some data by changing the text_hint value of a TextInput. If I print the values they are correct however I can't get them to update on the screen. Here's how I declare and use the the template in a .kv file.
<InformationBox#FloatLayout>
lblTxtIn: 'Unknown Variable Name'
txtInHint: "..."
Label:
text: root.lblTxtIn
color: 235/255, 235/255, 235/255, 1
pos_hint: {'center_x': 0.5, 'center_y': 0.7}
bold: True
TextInput:
readonly: True
hint_text: root.txtInHint
multiline: False
pos_hint: {'center_x': 0.5, 'center_y': 0.4}
size_hint: (0.3, 0.25)
hint_text_color: 0, 0, 0, 1
<MainMenu>:
InformationBox:
id: mylabel
lblTxtIn: "Data Type Name"
txtInHint: root.custom
And here's how I try to change the value in python.
from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
from kivy.properties import ObjectProperty, StringProperty
import random
class MainMenu(FloatLayout):
custom = "0"
class MyMainApp(App):
def build(self):
return MainMenu()
def txt_change(self, *args):
MainMenu.custom = str(random.randrange(1, 10))
print(MainMenu.custom)
Clock.schedule_interval(txt_change, 1)
if __name__ == "__main__":
MyMainApp().run()
I also tried to change it using ObjectProperty although then it shows an error telling that the object has no 'text_hint' attribute.
class MainMenu(FloatLayout):
mylabel = ObjectProperty()
def change_text(self, *args):
MainMenu.mylabel.text_hint = "1"
class MyMainApp(App):
def build(self):
return MainMenu()
Clock.schedule_interval(MainMenu.change_text, 1)
I'm a beginner and have no idea whether I'm doing a simple mistake or should approach the issue in a completely different way. I would be glad if someone could help me.
You can use the following approach to update the textinput field:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.clock import Clock
import random
APP_KV = """
FloatLayout:
lblTxtIn: "Data Type Name"
txtInHint: "..."
Label:
text: root.lblTxtIn
color: 235/255, 235/255, 235/255, 1
pos_hint: {'center_x': 0.5, 'center_y': 0.7}
bold: True
TextInput:
id: mytxtinput
readonly: True
hint_text: root.txtInHint
multiline: False
pos_hint: {'center_x': 0.5, 'center_y': 0.4}
size_hint: (0.3, 0.25)
hint_text_color: 0, 0, 0, 1
"""
class MyMainApp(App):
def build(self):
return Builder.load_string(APP_KV)
def txt_change(self, *args):
app.root.ids.mytxtinput.hint_text = str(random.randrange(1, 10))
print(app.root.ids.mytxtinput.hint_text)
Clock.schedule_interval(txt_change, 1)
if __name__ == "__main__":
app = MyMainApp()
app.run()
Hello everyone who have faced the KivyMD lib!
The problem is that I can't make MDTextField works as I need to.
Thats the task that it shall perform:
User inputting the key in the MDTextField and after that press the
button
If the key is correct - something goes after that (for example - toast("Key is CORRECT!"))
If the key is incorrect - that shall be an ERROR (for example - toast('KEY IS INCORRECT!'))
If there are too much characters (for example - more than 5), it have to display something (for example - toast('Too much text!'))
There is 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
from kivymd.toast.kivytoast import toast
from kivymd.textfields import MDTextField
class keyinput(MDTextField):
pass
def toast(text):
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()
def keycheck(self):
if keyinput.text == '12345':
toast('KEY IS CORRECT')
elif len(keyinput.text) > 5:
toast('Too much text!')
else:
toast('KEY IS INCORRECT!')
if __name__ == "__main__":
MainApp().run()
There is main.kv:
#:import MDDropdownMenu kivymd.menus.MDDropdownMenu
#:import MDRaisedButton kivymd.button.MDRaisedButton
#:import MDLabel kivymd.label.MDLabel
<OptionalLabel#MDLabel>:
halign: 'center'
font_size: dp(12)
<MDRB#MDRaisedButton>:
size_hint: None, None
size: 3 * dp(48), dp(48)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
opposite_colors: True
<keyinput>:
size_hint_x: 0.5
halign: 'center'
pos_hint: {'center_x': .5, 'center_y': .5}
max_text_length: 5
<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.5, 0.5
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
spacing: dp(10)
MDRB:
text: 'check the key'
on_release:
app.keycheck()
keyinput:
hint_text: "print the key here"
You need to assign your keyinput widget an id. Right now it looks like
in your keycheck function, it probably doesn't know what keyinput
means. kivy.org/doc/stable/guide/lang.html#referencing-widgets
Erik
Question: How do I update Label text in this scenario?
Python code:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.textinput import TextInput
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.uix.scrollview import ScrollView
from kivy.properties import StringProperty, ObjectProperty, NumericProperty
class SearchForPart(Widget):
def searchforpart(self):
Barty = 'text update';
demogar = DemoGarage()
demogar.ids.scrollref.UpdateParam(Barty)
class ScrollableLabel1(ScrollView):
text_variable_1 = StringProperty()
def __init__(self, **kwargs):
super(ScrollableLabel1, self).__init__(**kwargs)
self.text_variable_1 = 'initial'
def UpdateParam(self, param):
self.param = param
self.text_variable_1 = param
print(param)
class AnotherScreen(Screen):
pass
class MainScreen(Screen):
pass
class DemoGarage(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("garagemainexample.kv")
class MainApp(App):
def build(self):
return presentation
if __name__ == "__main__":
MainApp().run()
Kv code:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
ScreenManagement:
transition: FadeTransition()
MainScreen:
DemoGarage:
<BigButton#Button>:
font_size: 40
size_hint: 0.5, 0.15
color: 0,1,0,1
<MainScreen>:
name: "main"
FloatLayout:
BigButton:
on_release: app.root.current = "demogarage"
text: "Demo Garage"
pos_hint: {"x":0.25, "top": 0.4}
<DemoGarage>:
name: "demogarage"
ScrollableLabel1:
id:scrollref
SearchForPart:
id:searchpart
<ScrollableLabel1>:
Label:
id: mylabel
text: root.text_variable_1
font_size: 20
text_size: self.width, None
size_hint_y: None
height: self.texture_size[1]
padding_y: 10
padding_x: 140
<SearchForPart>:
size_hint: 1,1
FloatLayout:
Label:
text: "Search for Part:"
font_size: 30
pos_hint: {"x": 0.95, "y": 0.85}
color: 0,1,0,1
size_hint: 0.3, 0.2
TextInput:
id: partname
multiline: False
font_size: 30
pos_hint: {"x": 0.85, "y": 0.15}
color: 0,1,0,1
on_text_validate: root.searchforpart()
size_hint: 1, 0.5
After initializing program, the Label text is successfully initialized and outputs 'initial text'.
Once the 'searchforpart' method runs (as a response to hitting enter in search box), even though 'print(param)' prints 'text update', the label text isn't updated.
Question: How do I update Label text in this scenario?
Am I misunderstanding a core concept of how changes to the Kivy event loop are triggered?
Use a Kivy property:
from kivy.properties import StringProperty
class (YourClass):
text_variable_1 = StringProperty()
When you reference this property in kv, and its value changes, the gui will automatically update. If you don't use a property this doesn't happen because the kv code has no way to know the value changed.
Also, you don't have to follow pep8, but the property name should start with a lower case letter - it probably doesn't matter for your example, but can matter in kv if you try to set the property there.