Светодиод мигает, когда кнопка pu sh НЕ нажата, и постоянно горит, когда кнопка нажата (Python) - PullRequest
1 голос
/ 25 апреля 2020

Итак, у меня есть светодиод, управляемый Raspy, а также базовый c GUI только с помощью кнопки pu sh, я хочу, чтобы он вел себя следующим образом:

  • Светодиод мигает, когда кнопка pu sh НЕ нажата.
  • Светодиод должен постоянно гореть, когда кнопка pu sh нажата.

Когда я выполняю, индикатор начинает мигать, но кнопка не отображается. Когда я прерываю программу, кнопка появляется. Почему?

from tkinter import *
import RPi.GPIO as GPIO
import time

GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT)
GPIO.output(8, False)
buttonPressed = False

master = Tk()

def callback():
    GPIO.output(8, True)
    buttonPressed = True

w = Button(master, text="Turn on light", command = callback)
w.pack()

while True:
    if buttonPressed == False:
        GPIO.output(8, True)
        time.sleep(0.5)
        GPIO.output(8, False)
        time.sleep(0.5)
    else:
        GPIO.output(8, True)

Ответы [ 3 ]

3 голосов
/ 25 апреля 2020

Я думаю, что @furas направил вас в правильном направлении, но, поскольку я работал над этим ради удовольствия, я решил оставить свое решение и здесь. Я вытащил код GPIO, чтобы я мог запустить его локально.

Ключевой особенностью обоих решений является то, что мы удалили вызовы на time.sleep, потому что, когда вы time.sleep, Tk's событие l oop не может обработать какие-либо события (которые проявляются в том, что пользовательский интерфейс появляется как «зависание» во время этих операторов сна).

import time
import tkinter

buttonpressed = False
lastchange = 0
ledstate = False

def button_down(event):
    global buttonpressed
    print('BUTTON DOWN')
    buttonpressed = True


def button_up(event):
    global buttonpressed
    print('BUTTON UP')
    buttonpressed = False


def myloop(master):
    global buttonpressed
    global lastchange
    global ledstate

    now = time.time()
    delta = now - lastchange

    if not buttonpressed:
        if now - lastchange > 0.5:
            ledstate = not ledstate
            print('LED', ledstate)
            lastchange = now
    else:
        if not ledstate:
            ledstate = True
            print('LED', ledstate)

    master.after_idle(myloop, master)


master = tkinter.Tk()
w = tkinter.Button(master, text="Turn on light")
w.bind('<ButtonPress>', button_down)
w.bind('<ButtonRelease>', button_up)
w.pack()

master.after(100, myloop, master)
master.mainloop()
3 голосов
/ 25 апреля 2020

A tkinter приложение должно вызывать .mainloop().

Также вам следует использовать функцию .after(...) для имитации времени l oop:

import tkinter as tk
import RPi.GPIO as GPIO

def led_on(state):
    global button_pressed
    button_pressed = state

def blink_led(state=True):
    # turn on LED if either state or button_pressed is True
    GPIO.output(8, state or button_pressed)
    master.after(500, blink_led, not state) # toggle the state half a second later

# setup the RPi board
GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT)
GPIO.output(8, False)

button_pressed = False

master = tk.Tk()

w = tk.Button(master, text='Turn on light')
w.pack()

w.bind('<ButtonPress-1>', lambda e: led_on(True))  # set button_pressed to True
w.bind('<ButtonRelease-1>', lambda e: led_on(False)) # set button_pressed to False

blink_led()  # start the LED blinking

master.mainloop()
2 голосов
/ 25 апреля 2020

Я не могу проверить его на RPi, но я мог бы выглядеть примерно так.

Обычный command= может распознавать только когда вы нажали кнопку, но не может распознать, когда вы отпустили его - вам нужно события связывания <ButtonPress> и <ButtonRelease>, которые будут запускать функции на "mouse left button press" и "mouse left button release"

Я использую after() для запуска функции с задержкой, поэтому мне не нужны sleep() и while который может заблокировать mainloop() (и он может заморозить все GUI).

И мне также не нужны while l oop, потому что я запускаю все внутри on_press и on_release и позже after() запускает turn_off_led, которые используют after() для запуска turn_on_led которые используют after() для повторного запуска turn_off_led, поэтому он работает как l oop.

import tkinter as tk  # PEP8: `import *` is not preferred
import RPi.GPIO as GPIO

GPIO.setmode(GPIO.BOARD)
GPIO.setup(8, GPIO.OUT)
GPIO.output(8, False)

button_pressed = False  # PEP8: preferred `lower_case_names`

# --- functions ---

def on_press(event):
    global button_pressed

    button_pressed = True
    GPIO.output(8, True)

def on_release(event):
    global button_pressed

    button_pressed = False
    GPIO.output(8, True)

    # run after 500ms (0.5s) instead of `sleep`
    master.after(500, blink_off)

def blink_off():
    if not button_pressed:
        GPIO.output(8, False)
        # run after 500ms (0.5s) instead of `sleep`
        master.after(500, blink_on)

def blink_on():
    if not button_pressed:
        GPIO.output(8, True)
        # run after 500ms (0.5s) instead of `sleep`
        master.after(500, blink_off)

# --- main ---

master = tk.Tk()

button = tk.Button(master, text="Turn on light")
button.pack()

# here "button" means "tk.Button" and "Button" means "mouse left button"
button.bind('<ButtonPress>',   on_press)   # mouse left button pressed on tk.Button 
button.bind('<ButtonRelease>', on_release) # mouse left button released on tk.Button

# start blinking - it will use `after()` to loop
blink_on()

master.mainloop()
...