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
Related
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()
I am currently building a mobile app with kivy. In one of my screens I am trying to include an MDExpansionPanel, although I have tried with a lot of different codes, and searched on the web for solutions, either I get an error, or simply the Expansion Panel is not rendered in my screen. I am using ScreenManager since I have 5 screens, with the possibility of increasing such number.
The relevant Python code is the following:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.app import MDApp
from kivymd.theming import ThemeManager
from kivymd.toast import toast
from kivymd.uix.picker import MDDatePicker, MDTimePicker
from kivymd.uix.expansionpanel import MDExpansionPanel
from kivymd.uix.boxlayout import MDBoxLayout
class LoginWindow(Screen):
pass
class CreateAccountWindow(Screen):
pass
class MainWindow(Screen):
pass
class TravelManagerWindow(Screen):
pass
class IngActivWindow(Screen):
panel_container = ObjectProperty(None)
def on_pre_enter(self, *args):
self.add_panels()
def show_timepicker(self):
picker = MDTimePicker()
picker.bind(time=self.got_time)
picker.open()
def got_time(self, picker_widget, time):
self.text = str(time.hour) + ":" + str(time.minute)
self.focus = False
# selectedTime= self.text
print(self.text)
self.ids.tiempoActiv.text = self.text
def add_panels(self):
for i in range(5):
IngActivWindow.ids.panel_container.add_widget(
MDExpansionPanel(
icon="actividades.png",
content=MyContent(),
panel_cls=MDExpansionPanelOneLine(
text="Text",
)
)
)
class MyContent(MDBoxLayout):
pass
class WindowManager(ScreenManager):
ScreenManager().add_widget(LoginWindow(name='login'))
ScreenManager().add_widget(CreateAccountWindow(name='create'))
ScreenManager().add_widget(MainWindow(name='main'))
ScreenManager().add_widget(IngActivWindow(name='ingActiv'))
ScreenManager().add_widget(TravelManagerWindow(name='travelManager'))
class powerApp1(MDApp):
def build(self):
self.theme_cls.primary_palette = "Teal"
return WindowManager()
if __name__ == "__main__":
powerApp1().run()
The relevant kv code is the following:
(I have an image on the background and an Action Bar before the MDBoxLayout where I am trying to add the Expansion Panel)
<WindowManager>:
LoginWindow:
CreateAccountWindow:
MainWindow:
IngActivWindow:
TravelManagerWindow:
<IngActivWindow>:
name: 'ingActiv'
panel_container: panel_container
FloatLayout:
cols:1
canvas.before:
Rectangle:
pos: self.pos
size: self.size
source: 'ingActiv_background.png'
ActionBar:
pos_hint: {'top':1}
ActionView:
use_separator: True
ActionPrevious:
title: '---------'
with_previous: False
ActionButton:
icon: 'homeIcon.png'
on_press:
root.manager.current = 'main'
root.manager.transition.direction = 'right'
ActionGroup:
text: 'Gastos de Viaje'
mode: 'spinner'
size_hint:(None,None)
size: root.width/5,root.height/12
ActionButton:
text: 'Solicitar'
on_release:
root.manager.current = 'solicitud'
root.manager.transition.direction = 'left'
ActionButton:
text: 'Comprobar'
on_release:
root.manager.current = 'comprobar'
root.manager.transition.direction = 'left'
ActionGroup:
text: 'Opciones'
mode: 'spinner'
size_hint:(None,None)
size: root.width/5,root.height/12
ActionButton:
text: 'Ingresar Actividad'
on_release:
root.manager.current = 'ingActiv'
root.manager.transition.direction = 'left'
ActionButton:
text: 'Enviar Reporte'
ActionButton:
text: 'Cerrar Sesion'
on_release:
root.manager.current = 'login'
root.manager.transition.direction = 'down'
MDBoxLayout:
cols:1
size_hint: 1,0.6
pos_hint: {"center_x": 0.5, "center_y": 0.5}
ScrollView:
GridLayout:
id: panel_container
cols: 1
pos_hint: {"center_x": 0.5, "center_y": 0.5}
<MyContent>:
size_hint: 1, None
height: self.minimum_height
orientation: 'horizontal'
Button:
size_hint: None, None
Thanks a lot in advance for your support,
Have a great day.
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()
I have problem with setting the labels texts.
I need to set different text on the different labels that just have an id in .kv file, so that means that I don't want to create a class for each of the labels.
But I want to have the access to changing each labels text.
Please, help me with that problem on Python 3.6 and Kivy 1.11.1
There is my main.py code:
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()
def results(self):
msc = MyScreen()
msc.ids.firstlabel.text = 'FIRST TEXT'
msc.ids.secondlabel.text = 'SECOND TEXT'
msc.ids.thirdlabel.text = 'THIRD TEXT'
if __name__ == "__main__":
MainApp().run()
There is my main.kv code:
#: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
<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)
MDRB:
id: mainbutton
text: 'MDButton1'
on_release:
root.menu_button = mainbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
MDRB:
id: secondbutton
text: 'MDButton2'
on_release:
root.menu_button = secondbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
MDRB:
text: 'set the labels'
on_release:
app.results()
OptionalLabel:
id: firstlabel
text: 'label1'
OptionalLabel:
id: secondlabel
text: 'label2'
OptionalLabel:
id: thirdlabel
text: 'label3'
Thanks for attention!
You are pretty close. Accessing a text by ids is the way you want to go, you just have another issue here.
In short, you are actually creating two different MyScreen objects, you have one in your build() (which is actually what shows on the window) and then you are creating another screen in local scope of the "results" function.
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen() ///THIS IS A OBJECT IN MEMORY
def results(self):
msc = MyScreen() /// THIS IS A DIFFERENT OBJECT IN MEMORY, BUT DOESN'T REFERENCE THE SCREEN IN Build
msc.ids.firstlabel.text = 'FIRST TEXT'
msc.ids.secondlabel.text = 'SECOND TEXT'
msc.ids.thirdlabel.text = 'THIRD TEXT'
In this situation, I'd suggest taking your results function and bringing down into your MyScreen class like the below example. Key point here, you can bind to the on_release function from either KV lang or in Python Class. In the example below, I'm doing so in Python class.
from kivy.app import App
from kivy.lang import Builder
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
Builder.load_string("""
#: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
<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)
MDRB:
id: mainbutton
text: 'MDButton1'
on_release:
root.menu_button = mainbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
MDRB:
id: secondbutton
text: 'MDButton2'
on_release:
root.menu_button = secondbutton
MDDropdownMenu(items=root.menu_items, width_mult=4).open(self)
MDRB:
id: changesresultsbutton
text: 'set the labels'
OptionalLabel:
id: firstlabel
text: 'label1'
OptionalLabel:
id: secondlabel
text: 'label2'
OptionalLabel:
id: thirdlabel
text: 'label3'
""")
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
self.ids.changesresultsbutton.bind(on_release = self.results)
def change_variable(self, value):
print("\nvalue=", value)
self.VARIABLE = value
print("\tself.VARIABLE=", self.VARIABLE)
def callback(self, *args):
toast(args[0])
def results(self, value):
self.ids.firstlabel.text = 'FIRST TEXT'
self.ids.secondlabel.text = 'SECOND TEXT'
self.ids.thirdlabel.text = 'THIRD TEXT'
class MainApp(App):
title = "KivyMD MDDropdownMenu Demo"
theme_cls = ThemeManager()
def build(self):
return MyScreen()
if __name__ == "__main__":
MainApp().run()
I want that on pressing enter in a TextInput widget it should do two things-
change the screen (i am using screen manager)
and search for the keyword
I do know that with on_text_validate we can perform either of the tasks by-
1.root.manager.current='namesomething'
2.root.function_which_has_search_algorithm()
is there anyway with which i can do both the things(changing_the_screen,calling_the_search_function) using on_text_validate or do i have to use some other technique?
here a sample code:
import kivy
kivy.require("1.10.0")
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.lang import Builder
Builder.load_file('screenswitch.kv')
class MainScreen(Screen):
def SelectWord(self):
''' some search
code'''
class OtherScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class ScreenSwitchApp(App):
def build(self):
return sm
obj = ScreenSwitchApp()
obj.run()
heres my kivy code:
<MainScreen>:
BoxLayout:
TextInput:
text: "Search your word here"
color: 1,1,1,1
id: search_input
width: 200
size_hint: None, .20
pos_hint: {"center_x": .5, "center_y": 0.5}
multiline: False
on_text_validate: root.SelectWord() # i want this to change screen also
<OtherScreen>:
BoxLayout:
Button:
text: 'back to main screen'
on_press: root.manager.current='main'
A possible solution is to create a new function that calls that 2 functions:
*.py
import kivy
kivy.require("1.10.0")
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager,Screen
from kivy.lang import Builder
Builder.load_file('screenswitch.kv')
class MainScreen(Screen):
def some_function(self):
self.SelectWord()
self.manager.current='other'
def SelectWord(self):
print("SelectWord")
class OtherScreen(Screen):
pass
sm = ScreenManager()
sm.add_widget(MainScreen(name='main'))
sm.add_widget(OtherScreen(name='other'))
class ScreenSwitchApp(App):
def build(self):
return sm
obj = ScreenSwitchApp()
obj.run()
*.kv
<MainScreen>:
BoxLayout:
TextInput:
text: "Search your word here"
color: 1,1,1,1
id: search_input
width: 200
size_hint: None, .20
pos_hint: {"center_x": .5, "center_y": 0.5}
multiline: False
on_text_validate: root.some_function() # i want this to change screen also
<OtherScreen>:
BoxLayout:
Button:
text: 'back to main screen'
on_press: root.manager.current='main'
TextInput:
id:qty_inp
size_hint_x:.1
multiline:False
on_text_validate:root.update_price()
on_text_validate:root.update_purchase
Like the above code you can add one more on_text_validate: root.method()