繁体   English   中英

Kivy:自定义按钮不会随着 self.state 变化而更新

[英]Kivy: Custom button not updating with self.state change

我正在尝试创建一个 GUI,在查看了这里的各种帖子后,我仍然感到困惑。 我的问题是,当我将self.state设置为不同的东西时,我用来反映 GPIO 按钮状态的自定义按钮没有更新其外观。 我认为它可能与对象构造有关,但我不知道如何修复它。

主文件

import kivy
kivy.require('1.11.1')

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.clock import Clock
from kivy.core.window import Window
import RPi.GPIO as GPIO

# make app run in fullscreen mode
Window.fullscreen = 'auto'  # uses display's current resolution

# Set up GPIO
ok_btn_pin = 4
GPIO.setmode(GPIO.BCM)
GPIO.setup(ok_btn_pin, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.add_event_detect(ok_btn_pin, GPIO.BOTH)    #detect if GPIO.RISING or GPIO.FALLING occur


class GPIOButton(Button):

    btn_gpio_pin = NumericProperty(-1)

    def __init__(self, **kwargs):
        super(GPIOButton, self).__init__(**kwargs)
        print("GPIOButton __init__ called")
        print("btn_gpio_pin =", self.btn_gpio_pin)

    def update(self, dt):
        #print("GPIOButton update() called")
        if GPIO.input(self.btn_gpio_pin) == GPIO.HIGH and GPIO.event_detected(self.btn_gpio_pin):
            self.state = 'down'            
            print("Pin", self.btn_gpio_pin, self.state)
        elif GPIO.input(self.btn_gpio_pin) == GPIO.LOW and GPIO.event_detected(self.btn_gpio_pin):
            self.state = 'normal'
            print("Pin", self.btn_gpio_pin, self.state)


class LeftSidebar(FloatLayout):

    ok_btn = GPIOButton(btn_gpio_pin = ok_btn_pin)

    def __init__(self, **kwargs):
        super(LeftSidebar, self).__init__(**kwargs)
        print("LeftSidebar __init__ called")

    def update(self, dt):
        #print("LeftSidebar update() called")
        self.ok_btn.update(dt)


class LifterGUI(FloatLayout):

    left_sidebar = LeftSidebar()

    def __init__(self, **kwargs):
        super(LifterGUI, self).__init__(**kwargs)
        print("LifterGUI __init__ called")
        Clock.schedule_interval(self.update, 1.0/10.0)

    def update(self, dt):
        #print("LifterGUI update() called")
        self.left_sidebar.update(dt)


class LifterApp(App):

    def build(self):
        self.root = LifterGUI()
        return self.root


if __name__ == '__main__':
    try:
        LifterApp().run()
    finally:
        GPIO.cleanup()

升降机.kv

#:kivy 1.11.1
#:set camera_width_percent 4.0/5.0
#:set sidebar_width_percent (1.0 - camera_width_percent) / 2.0

<LeftSidebar>:
    ok_btn_button: ok_btn

    #:set num_btns 10.0
    
    canvas:
        Color:
            rgb: 1, 0, 0
        Rectangle:
            pos: self.pos
            size: self.size
    GPIOButton:
        id: ok_btn
        btn_gpio_pin: 4
        text: "ok"
        size_hint: (1.0, 1.0/num_btns)
        pos_hint: {'top': 1.0/num_btns}
    

<LifterGUI>:
    left_sidebar_widget: left_sidebar

    LeftSidebar: 
        id: left_sidebar
        size_hint: (sidebar_width_percent, 1.0) 

终端输出

我单击 GPIO 按钮 3 次,这会打印到终端,但不会更新 GPIOButton 外观。 请注意,由于某种原因,LeftSidebar __init__ 和 GPIOButton __init__ 每个都被调用了两次(我认为一次来自我的类​​属性声明,一次来自 kv 文件,但我不确定)。 我已经尝试使用 ObjectProperty(None) 代替 ok_btn 和 left_sidebar 来查看是否有帮助,但后来我得到了AttributeError: 'NoneType' object has no attribute 'update'错误,所以我不确定这是正确的方法。

[INFO   ] [Logger      ] Record log in /home/pi/.kivy/logs/kivy_20-09-30_53.txt
[INFO   ] [Kivy        ] v1.11.1
[INFO   ] [Kivy        ] Installed at "/usr/local/lib/python3.7/dist-packages/kivy/__init__.py"
[INFO   ] [Python      ] v3.7.3 (default, Dec 20 2019, 18:57:59) 
[GCC 8.3.0]
[INFO   ] [Python      ] Interpreter at "/usr/bin/python3"
[INFO   ] [Factory     ] 184 symbols loaded
[INFO   ] [Image       ] Providers: img_tex, img_dds, img_sdl2, img_pil, img_gif (img_ffpyplayer ignored)
[INFO   ] [Text        ] Provider: sdl2(['text_pango'] ignored)
[INFO   ] [Window      ] Provider: sdl2(['window_egl_rpi'] ignored)
[INFO   ] [GL          ] Using the "OpenGL" graphics system
[INFO   ] [GL          ] Backend used <sdl2>
[INFO   ] [GL          ] OpenGL version <b'3.1 Mesa 19.3.2'>
[INFO   ] [GL          ] OpenGL vendor <b'VMware, Inc.'>
[INFO   ] [GL          ] OpenGL renderer <b'llvmpipe (LLVM 9.0.1, 128 bits)'>
[INFO   ] [GL          ] OpenGL parsed version: 3, 1
[INFO   ] [GL          ] Shading version <b'1.40'>
[INFO   ] [GL          ] Texture max size <8192>
[INFO   ] [GL          ] Texture max units <32>
[INFO   ] [Window      ] auto add sdl2 input provider
[INFO   ] [Window      ] virtual keyboard not allowed, single mode, not docked
GPIOButton __init__ called
btn_gpio_pin = 4
LeftSidebar __init__ called
LeftSidebar __init__ called
GPIOButton __init__ called
btn_gpio_pin = -1
LifterGUI __init__ called
[INFO   ] [ProbeSysfs  ] device match: /dev/input/event0
[INFO   ] [MTD         ] Read event from </dev/input/event0>
[INFO   ] [ProbeSysfs  ] device match: /dev/input/event0
[INFO   ] [HIDInput    ] Read event from </dev/input/event0>
[INFO   ] [Base        ] Start application main loop
[INFO   ] [HIDMotionEvent] using <WaveShare WS170120>
[INFO   ] [MTD         ] </dev/input/event0> range position X is 0 - 800
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range ABS X position is 0 - 800
[INFO   ] [MTD         ] </dev/input/event0> range position Y is 0 - 480
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range ABS Y position is 0 - 480
[INFO   ] [MTD         ] </dev/input/event0> range touch major is 0 - 0
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range ABS pressure is 0 - 255
[INFO   ] [MTD         ] </dev/input/event0> range touch minor is 0 - 0
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range position X is 0 - 800
[INFO   ] [MTD         ] </dev/input/event0> range pressure is 0 - 255
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range position Y is 0 - 480
[INFO   ] [MTD         ] </dev/input/event0> axes invertion: X is 0, Y is 0
[INFO   ] [HIDMotionEvent] <WaveShare WS170120> range pressure is 0 - 255
[INFO   ] [MTD         ] </dev/input/event0> rotation set to 0
[INFO   ] [GL          ] NPOT texture support is available
Pin 4 down
Pin 4 normal
Pin 4 down
Pin 4 normal
Pin 4 down
Pin 4 normal

GPIOButton__init__()被调用两次。 一旦调用build()方法并执行self.root = LifterGUI() 这将通过kv规则创建出现在您的 GUI 中的GPIOButton 当在LeftSidebar类中执行ok_btn = GPIOButton(btn_gpio_pin = ok_btn_pin)时,将再次调用__init__()方法。 第二个调用创建了一个GPIOButton实例,该实例未出现在您的 GUI 中,但它是在update()方法中引用的实例。

由于您已经在kv设置了对GPIOButton的引用,您可以修改LeftSidebar类以使用该引用:

class LeftSidebar(FloatLayout):

    ok_btn_button = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(LeftSidebar, self).__init__(**kwargs)
        print("LeftSidebar __init__ called")

    def update(self, dt):
        #print("LeftSidebar update() called")
        self.ok_btn_button.update(dt)

ok_btn_buttonkvok_btn_buttonLeftSidebar成立了以参考GPIOButton是建在kv 有了它,您可以在LeftSidebar类中使用self.ok_btn_button来引用按钮。

请注意,您的LifterGUI错误LifterGUI

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM