1

Hello Raspberry Pi people,

I am using Kivy v1.11.1 on my Raspberry Pi with Python v3.7.3. The goal is to use a GPIO input to toggle the button state (parallel use of a real button and the touchscreen button possible). To change the state of the button I used the StringProperty that I attached to the state property in the KV file.

As you can see, the variable Gui.key_state will change (this is why I added the loop function every second). And also the initial value of RoundedButton text property is set to "normal" (I chose to attach my key_state StringProperty also to the text property so I can see if it is working).

The issue is, that the property does not get updated in the gui as it should (if I understand the kivy docs correctly).

Best regards and thanks for the help, Martin

main.py

#!/usr/bin/python3
# -*- coding: utf-8 -*-

import kivy
from kivy.app import App
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget
from kivy.clock import Clock

import RPi.GPIO as GPIO

class Gui(Widget):

    input_key = 12 #number of pin
    key_state = StringProperty('normal')
    print(key_state)

    def __init__(self, **kwargs):
        Clock.schedule_interval(self.loop, 1)
        super(Gui, self).__init__(**kwargs)

    def gpio_isr(obj):     
        if GPIO.input(Gui.input_key) == 0: #key pressed
            Gui.key_state = 'down'
        else:
            Gui.key_state = 'normal'       
        print(Gui.key_state)   

    GPIO.setmode(GPIO.BOARD)
    GPIO.setup(input_key, GPIO.IN, pull_up_down=GPIO.PUD_UP)
    GPIO.add_event_detect(input_key, GPIO.BOTH, callback=gpio_isr, bouncetime=200)

    def loop(self, *args):
        print(Gui.key_state)

class GuiApp(App):

    def build(self):
        return Gui()

if __name__ == '__main__':
    GuiApp().run()


gui.kv

#:kivy 1.11.1

<RoundedButton@Button>:
    background_color: (.0, .0, .0, .0) # delete background property
    canvas.before:
        Color:
            rgba: (.5, .5, .5, 1) if self.state=='normal' else (.0, .569, .863, 1)  # visual feedback of press
        RoundedRectangle:
            pos: self.pos
            size: self.size
            radius: [5,]
<Gui>:

    RoundedButton:
        pos: self.parent.pos
        size: self.parent.size
        size_hint: None, None
        state: root.key_state
        text: root.key_state

0

Ok. One thing that works is using the isr add_event_detect to call the GUI function that is shared with the key. Then a synchronize routine every 100 ms will set the states of the buttons (in this context I can use the ids function). Yeah, it's bad. But do you have any better idea?

class Gui(Widget):
    key_state = False

    def gpio_isr(obj):
        Gui.key(Gui, False) if GPIO.input(Gui.input_key) else Gui.key(Gui, True) # inverted buttons

        GPIO.setmode(GPIO.BOARD)
        GPIO.setup(12, GPIO.IN, pull_up_down=GPIO.PUD_UP) # example pin 12
        GPIO.add_event_detect(12, GPIO.BOTH, callback=lambda x: Gui.gpio_isr(), bouncetime=20) # routine can not be found if lambda is not used.

    def __init__(self):
        Clock.schedule_interval(self.loop, .1) # set a synchronize-routine every 100 ms.
        super(Gui, self).__init__()

    def loop(self, *args):        
        self.ids.key.state = 'down' if self.key_state else 'normal'

    def key(self, *args):
        self.key_state = args[0] # because when I try to change the state here it returns AttributeError: 'kivy.properties.DictProperty' object has no attribute 'key'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.