0

I want to create custom window header of a Kivy window. I am very new to kivy so please provide some explanation how the events work. I need to simply move the window by "moving" the label.

First of all I want to know, why this does call any function when I click or drag the label. It is in KvLang:

#:import main main.window

CustBoxLayout:
<CustBoxLayout>:
    orientation: 'vertical'

    Label:
        id: header
        text: 'MyApp'
        font_size: 24
        padding_x: 16
        color: self.theme_cls.primary_color

        on_touch_down: main.click
        on_touch_move: main.move

...

Any function is not called when I click or drag the label. However if I change main.click to for example print('touched!') it works.

So I created my own class:

class HeadLabel(MaterialLabel):
    def on_touch_down(self, touch):
        window.click(touch)

    def on_touch_move(self, touch):
        window.drag(touch)

This works. But now I don't know how to get the screen position out of the MotionEvent event. This is my actual code of window:

class WindowApp(App):
    theme_cls = ThemeManager()

    def build(self):
        self.theme_cls.theme_style = 'Light'
        self.theme_cls.primary_palette = 'Purple'

        return CustBoxLayout()

    def click(self, touch):
        self.touch_x, self.touch_y = touch.spos[0], touch.spos[1]

    def drag(self, touch):
        Window.top = self.touch_y + touch.spos[0]
        Window.left = self.touch_x + touch.spos[1])

Any help will be highly appreciated.

Jakub Bláha
  • 1,491
  • 5
  • 22
  • 43

1 Answers1

0

Define a class for the custom Label and implement on_touch_down and on_touch_move methods. Please refer to the example below for details.

Programming Guide » Input management » Touch event basics

By default, touch events are dispatched to all currently displayed widgets. This means widgets receive the touch event whether it occurs within their physical area or not.

In order to provide the maximum flexibility, Kivy dispatches the events to all the widgets and lets them decide how to react to them. If you only want to respond to touch events inside the widget, you simply check for collision.

Example

main.py

from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.core.window import Window
from kivymd.theming import ThemeManager


class CustomLabel(Label):

    def on_touch_down(self, touch):
        print("\nCustomLabel.on_touch_down:")

        if self.collide_point(*touch.pos):
            print("\ttouch.pos =", touch.pos)
            self.touch_x, self.touch_y = touch.spos[0], touch.spos[1]
            return True
        return super(CustomLabel, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        print("\nCustomLabel.on_touch_move:")

        if self.collide_point(*touch.pos):
            print("\ttouch.pos =", touch.pos)
            Window.top = self.touch_y + touch.spos[0]
            Window.left = self.touch_x + touch.spos[1]
            return True
        return super(CustomLabel, self).on_touch_move(touch)


class CustBoxLayout(BoxLayout):
    pass


class TestApp(App):
    theme_cls = ThemeManager()

    def build(self):
        self.theme_cls.theme_style = 'Light'
        self.theme_cls.primary_palette = 'Purple'

        return CustBoxLayout()


if __name__ == "__main__":
    TestApp().run()

test.kv

#:kivy 1.10.0

<CustomLabel>:


<CustBoxLayout>:
    orientation: 'vertical'

    CustomLabel:
        id: header
        text: 'MyApp'
        font_size: 24
        padding_x: 16
        color: app.theme_cls.primary_color

    Button:
        text: 'Button Widget'
        font_size: 24
        padding_x: 16
        color: app.theme_cls.primary_color

Output

Img01 - on touch down Img02 - on touch move

ikolim
  • 15,721
  • 2
  • 19
  • 29