Kivy >> On Press method triggered twice - kivy

For some reason the On Press event for the instance of Word_button is being triggered twice. The code below demonstrates this.
To repeat the problem.
run the code below
click on the "CREATE LIST OF WORD" button. This create a list of buttons. Each button has Boolean property if the word is correct or not.
then click on the word buttons. When clicking the button, the print statements print the correct boolean variable and the text of the button.
Problem:
The print commands are run twice.
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import Screen
from kivy.properties import (NumericProperty, BooleanProperty)
from kivymd.app import MDApp
from kivymd.uix.button import MDRaisedButton
from kivymd.uix.boxlayout import MDBoxLayout
kv = '''
<Word_button#MDRaisedButton>:
pos_hint: {'center_x': .5}
size_hint: 1, 1
font_size: "16sp"
on_press: self.check_word()
<Words_Box#MDBoxLayout>:
pos_hint: {'center_x': .5}
size_hint: 1, 1
Screen:
id: spelling_screen
name: "spelling_screen"
MDBoxLayout:
orientation: 'vertical'
padding: dp(15)
spacing: dp(10)
MDLabel:
text: 'Words'
Words_Box:
id: words_box
orientation: 'vertical'
padding: dp(15)
spacing: dp(10)
MDRaisedButton:
text: 'CREATE LIST OF WORDS'
on_release: root.ids.words_box.add_word_buttons()
'''
class Word_button(MDRaisedButton):
correct = BooleanProperty()
def check_word(self):
print('Answer is ', self.correct)
print('Button Text is ', self.text)
class Words_Box(MDBoxLayout):
def add_word_buttons(self):
app = MDApp.get_running_app()
words = ['$WORD 1', 'WORD 2', 'WORD 3']
for word in words:
correct = False
if '$' in word:
correct = True
word = word[1:]
btn = Word_button(text=word, correct=correct)
self.add_widget(btn)
class RootScreen(Screen):
def __init__(self, **kwargs):
super(RootScreen, self).__init__(**kwargs)
class Main(MDApp):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.screen = Builder.load_string(kv)
def build(self):
return self.screen
Main().run()

This was resolved by not naming the kv file main.kv.

Related

How to disable a widget when a button from a different class is pressed?

Im making a Button which disables a TopAppBar menu form my user interface, the problem is that the Button is on one class an the TopAppBar in another, because one belongs to the screen and the other is shared between multiple screens.
code:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.uix.screen import MDScreen
Window.size = (300, 500)
navigation_helper = """
<UserScreen>
name: 'user_screen'
MDBoxLayout:
orientation: "vertical"
pos_hint: {"top": 1}
adaptive_height: True
padding: (0, "80dp" , 0, 0)
FloatLayout:
MDRaisedButton:
id: save_btn_user
text: "Guardar"
md_bg_color: "white"
text_color: "black"
font_size: 16.2
pos_hint: {"left":1, "bottom": 1}
size_hint: (.2,.2)
disabled: True
on_press: root.save_btn_press()
MDRaisedButton:
id: edit_btn_user
text: "Editar"
md_bg_color: "white"
text_color: "black"
font_size: 16.2
pos_hint: {"right":1, "bottom": 1}
size_hint: (.2,.2)
disabled: False
on_press:
root.disable_top_bar()
<MainScreen>:
name: "main_screen"
BoxLayout:
orientation: 'vertical'
MDTopAppBar:
id: title_bar
title: 'Dietas'
md_bg_color: 0.08,0.07,0.45
specific_text_color: 1,1,1
left_action_items: [["menu", lambda x: nav_drawer.set_state('toggle')]]
Widget:
MDNavigationLayout:
ScreenManager:
id: scr
UserScreen:
MDNavigationDrawer:
id: nav_drawer
BoxLayout:
orientation: 'vertical'
spacing: '8dp'
ScrollView:
MDList:
OneLineIconListItem:
text: 'Usuario'
on_press:
scr.current= 'user_screen'
title_bar.title = "Usuario"
nav_drawer.set_state('close')
IconLeftWidgetWithoutTouch:
icon: 'account'
on_press:
scr.current= 'user_screen'
title_bar.title = "Usuario"
nav_drawer.set_state('close')
MainScreen:
"""
class UserScreen(MDScreen):
def disable_top_bar(self):
self.a=MainScreen()
self.a.disable_top_barr()
class MainScreen(MDScreen):
def disable_top_barr(self):
self.ids.title_bar.disabled = True
print("testmsg")
class DemoApp(MDApp):
def build(self):
self.theme_cls.theme_style = ("Dark")
screen = Builder.load_string(navigation_helper)
return screen
DemoApp().run()
As you may have seen, I tried creating two method, one in the TopAppBar class disabling it and printing a test message(that its shown) and the other in the Button class calling that function.
With the following approach
def disable_top_bar(self):
self.a=MainScreen()
self.a.disable_top_barr()
you will see no change in your GUI because each time you call that method, it will create a new instance of MainScreen (which is not related to your GUI) and call the asked method on it.
In order to access that specific instance you can use the method get_running_app of MDApp as follows,
def disable_top_bar(self):
# First access the running app instance.
app = MDApp.get_running_app()
# Access the target screen that you set as the root widget.
main_screen = app.root
# Call the method.
main_screen.disable_top_barr()
As a note avoid using predefined names like a, b, g etc. when working with KivyMD widgets.

When creating a widget with a button, how to specify an ID?

So I already make an expanding list when pressing a button, the problem is that I canĀ“t find I way to add an icon in the right part(as the sample one) of the ListItem
Code:
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivymd.uix.screen import MDScreen
from kivymd.uix.list import OneLineRightIconListItem
from kivymd.uix.list.list import IconRightWidget
Window.size = (300, 500)
navigation_helper = """
<DietScreen>:
Screen:
MDBoxLayout:
orientation: 'vertical'
padding: ("5dp", "65dp" , "5dp", "5dp")
pos_hint: {"top": 1}
MDScrollView:
MDList:
id: box
OneLineRightIconListItem:
id: hola
text: 'testitem'
on_press:
IconRightWidget:
icon: "dots-vertical"
MDRaisedButton:
text: "Nueva Dieta"
md_bg_color: "white"
text_color: "black"
font_size: 16.2
pos_hint: {"right": 1, "bottom": 1}
on_press: root.buttonClicked()
Screen:
MDNavigationLayout:
ScreenManager:
id: scr
DietScreen:
"""
class DietScreen(MDScreen):
def buttonClicked(self):
newButt = OneLineRightIconListItem(text='Button')
self.ids.box.add_widget(newButt)
class DemoApp(MDApp):
def build(self):
screen = Builder.load_string(navigation_helper)
return screen
DemoApp().run()
I tried to specify an id to the ListItem created, and in the same method after addind the ListItem, add an IconRightWidget with an icon determined, but it results in an error.
Replace your:
newButt = OneLineRightIconListItem(text='Button')
With:
newButt = OneLineRightIconListItem(IconRightWidget(icon='dots-vertical'), text="Button")

KivyMD, MDFloatingActionButton: correct placement

I've been trying to use floating action buttons alongside FileChooser:
import kivy
kivy.require("2.1.0")
from kivy.utils import platform
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivymd.app import MDApp
from kivymd.uix.tab import MDTabsBase
from kivymd.icon_definitions import md_icons
import os
USERPATH = os.path.expanduser("~")
if platform == "android":
from android.storage import primary_external_storage_path
from android.storage import secondary_external_storage_path
from android.permissions import request_permissions, Permission
USERPATH = primary_external_storage_path()
request_permissions(
[Permission.WRITE_EXTERNAL_STORAGE, Permission.READ_EXTERNAL_STORAGE]
)
KV = '''
#:kivy 2.1.0
#:set dark_gray (.5, .5, .5, 1)
MDBoxLayout:
orientation: "vertical"
MDTabs:
id: ps_tabs
TabList:
id: ps_tab_list
icon: "folder"
FileChooserListView:
id: ps_filechooser
canvas.before:
Color:
rgba: dark_gray
Rectangle:
size: self.size
pos: self.pos
MDFloatingActionButton:
id: fc_playdir
icon: "folder"
pos_hint: {"center_x": .4, "center_y": .5}
MDFloatingActionButton:
id: fc_playfile
icon: "file"
pos_hint: {"center_x": .6, "center_y": .5}
TabDetails:
id: ps_tab_details
icon: "book"
MDScrollView:
'''
class TabList(FloatLayout, MDTabsBase):
"""The engaged power supplies tab."""
class TabDetails(FloatLayout, MDTabsBase):
"""The engaged power supply details tab."""
class Ron(MDApp):
def build(self):
return Builder.load_string(KV)
def on_start(self):
self.theme_cls.primary_palette = "Gray"
self.theme_cls.material_style = "M3"
if platform != "android":
self.root.ids.ps_tabs.lock_swiping = True
self.root.ids.ps_filechooser.rootpath = USERPATH
if __name__ == "__main__":
Ron().run()
Mouse clicks, as well as taps, shoot right through the buttons and into the FileChooser, no matter what I do. I tried placing the buttons into their own box layout, tried moving them up and down the widget tree. Nothing helps, while the buttons remain visible. Besides, on visiting the second tab, one can see two thick black button footprints. Something's very wrong and I can't think of anything else to try.

Kivy ActionDropDown does not open

In the kivy gui below, when I press the button 'Pen', an ActionDropDown is supposed to come. I do not see it opening. But the 'Pen' button behaves as if a DropDown was opened with it (e.g. you can not press on it on the first try). What is wrong?
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.actionbar import ActionDropDown
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import Screen
Builder.load_string("""
<NoteScreen>:
BoxLayout:
orientation: 'vertical'
NoteScreenMenu:
Label:
text: 'i am a label'
<NoteScreenMenu>:
orientation: 'horizontal'
size_hint_y: None
height: 48
ActionBar:
pos_hint: dict(top=1)
ActionView:
use_separator: True
ActionPrevious:
title: 'Drawing Screen'
with_previous: False
ActionOverflow:
ActionButton:
id: pen_button
text: 'Pen'
on_release: root.pen_drop_down.open(self)
ActionButton:
text: 'Eraser'
<PenDropDown>:
Button:
text: 'Close this'
Button:
text: 'btn1'
""")
class NoteScreen(Screen):
pass
class NoteScreenMenu(BoxLayout):
def __init__(self, **kwargs):
super(NoteScreenMenu, self).__init__(**kwargs)
self.pen_drop_down = PenDropDown()
class PenDropDown(ActionDropDown):
pass
class TheApp(App):
def build(self):
return NoteScreen(name='note')
if __name__ == '__main__':
TheApp().run()
The problem was here:
<PenDropDown>:
Button:
text: 'Close this'
Button:
text: 'btn1'
I needed to add height information to buttons in the dropdown:
<PenDropDown>:
Button:
text: 'Close this'
height: 48
size_hint_y : None
Button:
text: 'btn1'
height: 48
size_hint_y : None

remove_widget in kivy doesn't remove widget

I'm having trouble removing a widget using remove_widget in kivy
I either get TypeError: 'Label' object has no attribute 'getitem' error
or it just doesn't remove the label that was created.
I think I'm not properly referring to the widget made but not sure how to...
Builder.load_string("""
<MenuScreen>:
FloatLayout:
#cols: 2
#rows: 2
size: 800,480
Button:
id: resetmash
text: "Reset"
font_size: 30
size_hint: None, None
background_color: 1,0.88,0.882,1
size: 100,100
pos: 1450,800
on_press: root.resetmash()
Button:
id: btn_0
text: "+"
size_hint: None, None
size: 100,100
pos: 550,700
on_press: root.listmashsteps()
""")
class MenuScreen(Screen):
def resetmash(self):
self.remove_widget(Label())
def listmashsteps(self, *largs):
self.add_widget(Label(text="Step"))
def __init__(self, **kwargs):
super(MenuScreen, self).__init__(**kwargs)
sm = ScreenManager()
menu_screen = MenuScreen(name='menu')
sm.add_widget(menu_screen)
class TestApp(App):
def build(self):
return sm
if __name__ == '__main__':
TestApp().run()
self.remove_widget(Label())
This doesn't make sense - you just instantiated that Label, so it isn't already added to the widget, so you can't remove it.
Instead store a reference to the Label when you add it, something like:
self.label = Label(text='Step')
self.add_widget(self.label)
Then later:
self.remove_widget(self.label)

Resources