Search code examples
videokivybind

Kivy binding events/properties across classes


My guess is that I'm just not understanding bindings correctly or I don't know how to call it correctly. My thought process: bind(*event/property* = function). If the property changes or the event is fired off, then the function runs.

What I'm trying to do is create a media player that sends a command via I2C at certain times. I would like to know when the video is loaded (if possible) but more importantly I need to know the current position of the video (current time).

My main python file:

from kivy.app import App
from kivy.clock import Clock
from kivy.uix.video import Video
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.lang.builder import Builder
from kivy.uix.gridlayout import GridLayout
from kivy.properties import Property
from kivy.properties import ObjectProperty
import tkinter
from tkinter import filedialog
import csv
import numpy as np
import time
import os
# import busio
# import board
# import adafruit_mcp4725
#
# os.environ["BLINKA_FT232H"]
# i2c = busio.I2C(board.SCL, board.SDA)
# dac = adafruit_mcp4725.MCP4725(i2c)


Builder.load_file("Main.kv")


class Videos(Video):
    def __(self, **kwargs):
        super(Videos, self).__init__(**kwargs)
        self.bind(on_loaded=MainApp.get_running_app().loading)
         #self.bind(position=MainApp.get_running_app().slider_position)

    pass


class RootWindow(GridLayout):
    default_time = '0:00 / 0:00'
    tkinter.Tk().withdraw()
    interval_event = None

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.values = [None]
        self.times = [None]

    def start_checking(self):
        self.interval_event = Clock.schedule_interval(self.check_time, .9)
        self.interval_event()

    def stop_checking(self):
        if self.interval_event is not None:
            self.interval_event.cancel()

    def loading(self):
        print('loaded')

    def slider_position(self):
        print('position')

    def load_video(self):

        file_input = filedialog.askopenfilename(title='Video')
        if file_input != '':
            self.ids.video.source = file_input
            # Videos.video._do_video_load(self.ids.video)

    def load_data(self):
        csv_file_path = filedialog.askopenfilename(title='Data')
        with open(csv_file_path) as import_data:
            reader = csv.reader(import_data)
            times_reader = next(reader)
            times = []
            for time in times_reader:
                times.append(time)
            values_reader = next(reader)
            values = []
            for value in values_reader:
                values.append(value)
        self.times = times
        self.values = values

    def play_pause(self):
        print(self.ids.video.loaded)
        if self.ids.video.state == 'play':
            self.ids.video.state = 'pause'
            self.ids.play_pause_img.source = "play_icon.png"
        else:
            self.ids.video.state = 'play'
            self.ids.play_pause_img.source = "pause_icon.png"
        # Clock.schedule_interval(self.check_time, .9)

    def check_time(self, dt):
        print(self.ids.video.state)
        # if RootWindow().ids.video.state == 'stop' or RootWindow().ids.video.state == 'pause':
        #     # dac.raw_value = 0
        #     print('0')
        # else:
        #     print('playing')
            # for idx, row in enumerate(times):
            #     if row == position:
            #         print(row)
            #         send = (4095 / 80) * values[idx]
            #         dac.raw_value = send


class MainApp(App):

    def build(self):
        return RootWindow()


MainApp().run()

My kv file:

<RootWindow>
    video:video

    rows: 2

    GridLayout:
        rows: 1
        size_hint: 1, 1
        pos_hint: {'center_x': 0.5, 'center_y': 0.5}
        Videos:
            id: video
            #source: 'RepMot.mp4'
            #state: 'play'
            ##on_load: root.start_checking
            on_eos: root.stop_checking

    GridLayout:
        rows: 1
        size_hint: 1, None
        height: 35
        row_force_default: True
        row_default_height: 35
        pos_hint: {'y': 0, 'center_x': 0.5}

        Button:
            id: vid
            #text: 'vid'
            background_color: 0,0,0,0
            size_hint: None, 1
            width: 35

            on_press: root.load_video()

            Image:
                id: vid_img
                source: "vid_icon.png"
                pos_hint: {'center_x': 0.5, 'center_y': 0.5}
                size: 35,35

        Button:
            id: data
            #text: 'data'
            background_color: 0,0,0,0
            size_hint: None, 1
            width: 35

            on_press: root.load_data()

            Image:
                id: data_img
                source: "data_icon.png"
                center_x: self.parent.center_x
                center_y: self.parent.center_y
                size: 35,35

        Button:
            id: play_pause
            #text: 'play'
            background_color: 0,0,0,0
            size_hint: None, 1
            width: 35

            on_press: root.play_pause()

            Image:
                id: play_pause_img
                source: "play_icon.png"
                center_x: self.parent.center_x
                center_y: self.parent.center_y
                size: 35,35

        Button:
            id: vol
            #text: 'vol'
            background_color: 0,0,0,0
            size_hint: None, 1
            width: 35

            Image:
                id: volume_img
                source: "volume_icon.png"
                center_x: self.parent.center_x
                center_y: self.parent.center_y
                size: 35,35

        Slider:
            size_hint_x: 1
            id: slider
            background_width: '26sp'
            min: 0
            max: 100

        Label:
            id: timestamp
            size_hint: None, 1
            pos_hint: {'right': 1}
            width: 80
            text: '0:00 / 0:00'

I have tried all sorts of different calls to bind it many from different video and article sources but I either get errors or they do nothing.


Solution

  • I suspect the problem is with your code:

    class Videos(Video):
        def __(self, **kwargs):
    

    Try changing that to:

    class Videos(Video):
        def __init__(self, **kwargs):