未按下按钮时 LED 闪烁,按下按钮时 LED 持续亮起 (Python)
LED to blink when a push button is NOT pressed and to be continually on when the button IS pressed (Python)
所以,我有一个由 Raspy 控制的 LED,还有一个只有一个按钮的基本 GUI,我希望它的行为如下:
- 未按下按钮时 LED 闪烁。
- 当按下按钮时,LED 应持续亮起。
当我执行时,指示灯开始闪烁,但按钮没有显示。
当我中断程序时,按钮出现。为什么?
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)
我无法在 RPi 上测试它,但我可以像这样。
普通command=
只能在点击按钮时识别,松开按钮时无法识别 - 需要绑定事件<ButtonPress>
和<ButtonRelease>
,这将运行 在 "mouse left button press"
和 "mouse left button release"
上运行
我使用 after()
到 运行 功能延迟所以我不需要 sleep()
和 while
可以阻止 mainloop()
(它可以冻结所有 GUI)。
我也不需要 while
循环因为我 运行 都在 on_press
和 on_release
以及后来的 after()
运行 s turn_off_led
使用 after()
到 运行 turn_on_led
再次使用 after()
到 运行 turn_off_led
所以它像循环一样工作。
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()
我认为@furas 已经为您设定了正确的方向,但由于我是为了好玩而研究它,所以我想我也会把我的解决方案留在这里。我提取了 GPIO 代码,以便我可以在本地 运行 它。
这两种解决方案的一个关键特征是我们删除了对 time.sleep
的调用,因为当您 time.sleep
ing 时,Tk 的事件循环无法处理任何事件(这将表现为 UI 在那些睡眠语句中出现在 "freeze" 中)。
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()
一个tkinter
应用程序需要调用.mainloop()
。
你还应该使用 .after(...)
函数来模拟 while 循环:
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()
所以,我有一个由 Raspy 控制的 LED,还有一个只有一个按钮的基本 GUI,我希望它的行为如下:
- 未按下按钮时 LED 闪烁。
- 当按下按钮时,LED 应持续亮起。
当我执行时,指示灯开始闪烁,但按钮没有显示。 当我中断程序时,按钮出现。为什么?
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)
我无法在 RPi 上测试它,但我可以像这样。
普通command=
只能在点击按钮时识别,松开按钮时无法识别 - 需要绑定事件<ButtonPress>
和<ButtonRelease>
,这将运行 在 "mouse left button press"
和 "mouse left button release"
我使用 after()
到 运行 功能延迟所以我不需要 sleep()
和 while
可以阻止 mainloop()
(它可以冻结所有 GUI)。
我也不需要 while
循环因为我 运行 都在 on_press
和 on_release
以及后来的 after()
运行 s turn_off_led
使用 after()
到 运行 turn_on_led
再次使用 after()
到 运行 turn_off_led
所以它像循环一样工作。
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()
我认为@furas 已经为您设定了正确的方向,但由于我是为了好玩而研究它,所以我想我也会把我的解决方案留在这里。我提取了 GPIO 代码,以便我可以在本地 运行 它。
这两种解决方案的一个关键特征是我们删除了对 time.sleep
的调用,因为当您 time.sleep
ing 时,Tk 的事件循环无法处理任何事件(这将表现为 UI 在那些睡眠语句中出现在 "freeze" 中)。
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()
一个tkinter
应用程序需要调用.mainloop()
。
你还应该使用 .after(...)
函数来模拟 while 循环:
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()