KivyMD: Buttons don't work in custom MDDialog

Description of the Bug

The Buttons in the example for custom dialog don’t work. This is because it is not possible to define height: “120dp” in the KV-file. A workaround is to replace it with an integer.

This gets borked in dialog.py

        if self.type == "custom":
            if self.content_cls:
                self.ids.container.remove_widget(self.ids.scroll)
                self.ids.container.remove_widget(self.ids.text)
                self.ids.spacer_top_box.add_widget(self.content_cls)
                self._spacer_top = self.content_cls.height + dp(24)   # <<<<------ here
                self.ids.spacer_top_box.padding = (0, "24dp", "16dp", 0)

Code and Logs

from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout

from kivymd.app import MDApp
from kivymd.uix.button import MDFlatButton
from kivymd.uix.dialog import MDDialog

KV = '''
<Content>
    orientation: "vertical"
    spacing: "12dp"
    size_hint_y: None
    height: "120dp"

    MDTextField:
        hint_text: "City"

    MDTextField:
        hint_text: "Street"


FloatLayout:

    MDFlatButton:
        text: "ALERT DIALOG"
        pos_hint: {'center_x': .5, 'center_y': .5}
        on_release: app.show_confirmation_dialog()
'''


class Content(BoxLayout):
    pass


class Example(MDApp):
    dialog = None

    def build(self):
        return Builder.load_string(KV)

    def show_confirmation_dialog(self):
        if not self.dialog:
            self.dialog = MDDialog(
                title="Address:",
                type="custom",
                content_cls=Content(),
                buttons=[
                    MDFlatButton(
                        text="CANCEL", text_color=self.theme_cls.primary_color, on_release=self.callback
                    ),
                    MDFlatButton(
                        text="OK", text_color=self.theme_cls.primary_color
                    ),
                ],
            )
        self.dialog.open()

    def callback(self, *args):
        print('it works!')

Example().run()

Versions

  • KivyMD: 0.104.1

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Reactions: 1
  • Comments: 15 (8 by maintainers)

Most upvoted comments

ModalView has these functions:

    def on_touch_down(self, touch):
        self._touch_started_inside = self.collide_point(*touch.pos)
        if not self.auto_dismiss or self._touch_started_inside:
            super(ModalView, self).on_touch_down(touch)
        return True

    def on_touch_up(self, touch):
        if self.auto_dismiss and not self._touch_started_inside:
            self.dismiss()
            return True
        super(ModalView, self).on_touch_up(touch)
        return True

When someone interacts with the dialog, it checks whether the touch was inside the dialog window, or outside. If it was outside, the dialog is dismissed. The problem is, that the actual size of MDDialog does not correspond to the size of ModalView. Therefore the dialog is dismissed even if the interaction was inside the window.

OK, so the issue is that MDDialog inherits from ModalView and ModalView does not update its size when widgets are added to it, or when children widgets change their size. Therefore, the collide_point property of MDDialog does not correspond to the real size of MDDialog. This can be fixed by updating the size of MDDialog at the end of initialisation.

        sum_over = ['title',
                    'spacer_top_box',
                    'text',
                    'scroll',
                    'spacer_bottom_box',
                    'root_button_box',
                    ]
        for name, widget in self.ids.items():
            if hasattr(widget, 'height') and name in sum_over:
                total_height += widget.height

        total_height += self.ids.container.padding[1]
        total_height += self.ids.container.padding[-1]

        self.height = total_height```

@agisbrec The question is closed!