使用 Python 中的一行图像创建 Knight Rider 风格的流式 LED
Creating a Knight Rider style streaming LED with a row of images in Python
我正在使用 raspberry pi 和 pi-face 扩展板学习 python。
我使用 Tkinter 创建了一个带有按钮的 Gui 来操作 pi-face LED。在代码的一部分中,我打开了一个新的 window,它显示了一个按钮和一行处于 'off' 状态的 LED 图像。我正在尝试添加一些代码,使 LED 图像行在 'on' 状态下沿着图像行从左到右流式传输 LED 图像,例如 Knight Rider 汽车的前灯。
我已经在 while 循环中尝试了一些东西,但是如果没有很多代码行,我不太明白如何实现它。我认为必须有一种方法可以做到这一点,就像增加数字写入以在 piface 扩展板上创建流式 LED 一样。这是我的代码...
class App2:
def __init__(self, master):
self.signal = False #added to stop thread
print('self.signal', self.signal)
self.master=master # I added this line to make the exit button work
frame = Frame(master)
frame.pack()
Label(frame, text='Turn LED ON').grid(row=0, column=0)
Label(frame, text='Turn LED OFF').grid(row=0, column=1)
self.button0 = Button(frame, text='Knight Rider OFF', command=self.convert0)
self.button0.grid(row=2, column=0)
self.LED0 = Label(frame, image=logo2) #added to create a row of images
self.LED1 = Label(frame, image=logo2)
self.LED2 = Label(frame, image=logo2)
self.LED3 = Label(frame, image=logo2)
self.LED4 = Label(frame, image=logo2)
self.LED5 = Label(frame, image=logo2)
self.LED6 = Label(frame, image=logo2)
self.LED7 = Label(frame, image=logo2)
self.LED0.grid(row=2, column=1)
self.LED1.grid(row=2, column=2)
self.LED2.grid(row=2, column=3)
self.LED3.grid(row=2, column=4)
self.LED4.grid(row=2, column=5)
self.LED5.grid(row=2, column=6)
self.LED6.grid(row=2, column=7)
self.LED7.grid(row=2, column=8)
self.button9 = Button(frame, text='Exit', command=self.close_window)
self.button9.grid(row=3, column=0)
def convert0(self, tog=[0]):
tog[0] = not tog[0]
if tog[0]:
print('Knight Rider ON')
self.button0.config(text='Knight Rider ON')
t=threading.Thread(target=self.LED)
t.start()
self.signal = True #added to stop thread
print('self.signal', self.signal)
print('tog[0]', tog[0])
self.LED0.config(image = logo)
else:
print('Knight Rider OFF')
self.button0.config(text='Knight Rider OFF')
self.signal = False #added to stop thread
print('self.signal', self.signal)
print('tog[0]', tog[0])
self.LED0.config(image = logo2)
def LED(self):
while self.signal: #added to stop thread
a=0
while self.signal: #added to stop thread
pfio.digital_write(a,1) #turn on
sleep(0.05)
pfio.digital_write(a,0) #turn off
sleep(0.05)
a=a+1
if a==7:
break
while self.signal: #added to stop thread
pfio.digital_write(a,1) #turn on
sleep(0.05)
pfio.digital_write(a,0) #turn off
sleep(0.05)
a=a-1
if a==0:
break
def close_window(self):
print('Knight Rider OFF')
print('self.signal', self.signal)
self.button0.config(text='Knight Rider OFF')
self.LED0.config(image = logo2)
self.signal = False #added to stop thread
print('self.signal', self.signal)
sleep(1)
print('Close Child window')
self.master.destroy() # I added this line to make the exit button work
root = Tk()
logo2 = PhotoImage(file="/home/pi/Off LED.gif")
logo = PhotoImage(file="/home/pi/Red LED.gif")
root.wm_title('LED on & off program')
app = App(root)
root.mainloop()
如此简单的任务不需要线程。在 tkinter 中设置持久重复任务非常容易,如果任务不超过几百毫秒(如果花费更长的时间,您的 UI 将开始滞后)。
基本模式是编写一个执行某些工作的函数,然后使用 after
使该函数再次调用自身。例如:
def animate():
# do something, such as turn an led on or off
<some code here to turn one led on or off>
# run this again in 100 ms
root.after(100, animate)
以上将创建一个在 tkinter 的主循环中运行的无限循环。只要 <some code here... >
不会花太长时间,动画就会显得流畅,你的 UI 也不会迟钝。
例子
这是该技术的一个简单的工作示例。它使用一个简单的迭代器循环遍历 LED,但您可以使用您想要选择下一个 LED 点亮的任何算法。您还可以同时打开或关闭屏幕上的 LED 和硬件 LED,或者打开或关闭多个 LED 等。
为了制作此代码 copy/paste-able,它使用彩色框而不是图像,但如果需要,您可以使用图像。
import tkinter as tk # Tkinter for python 2
from itertools import cycle
class LEDStrip(tk.Frame):
segments = 16
speed = 100 # ms
def __init__(self, parent):
tk.Frame.__init__(self, parent)
leds = []
for i in range(self.segments):
led = tk.Frame(self, width=12, height=8, borderwidth=1,
relief="raised", background="black")
led.pack(side="left", fill="both", expand=True)
leds.append(led)
self.current_segment = None
self.iterator = cycle(leds)
def animate(self):
# turn off the current segment
if self.current_segment:
self.current_segment.configure(background="black")
# turn on the next segment
self.current_segment = next(self.iterator) # self.iterator.next() for python 2
self.current_segment.configure(background="red")
# run again in the future
self.after(self.speed, self.animate)
root = tk.Tk()
strip = LEDStrip(root)
strip.pack(side="top", fill="x")
# start the loop
strip.animate()
root.mainloop()
可能不是您要找的东西,但您可以从中得到一些启发,先在终端上设置此 "cylon" 算法。 LED 没有中间颜色值,但我想光的剩余感知应该可以解决问题。
import sys,time
shift = lambda l, n=1: l[n:]+l[:n]
c = u' ▁▂▃▄▅▆▇' # possible color values
L = 8 # number of items
B = L*[0] # indices of items
A = [0] + list(range(7)) + list(range(7,0,-1)) + 6*[0] # light sequence
C = L*[' '] # start blank
while 1:
B[A[0]]=L # set the most brilliant light
for x in range(L):
B[x]-= 1 # decrease all lights values
B[x] = max(0,B[x]) # not under 0
C[x] = c[B[x]] # get the corresponding 'color'
A = shift(A,-1) # shift the array to the right
sys.stdout.write(('%s%s%s')%(' ',''.join(C[1:]),'\r'))
time.sleep(0.1)
我正在使用 raspberry pi 和 pi-face 扩展板学习 python。 我使用 Tkinter 创建了一个带有按钮的 Gui 来操作 pi-face LED。在代码的一部分中,我打开了一个新的 window,它显示了一个按钮和一行处于 'off' 状态的 LED 图像。我正在尝试添加一些代码,使 LED 图像行在 'on' 状态下沿着图像行从左到右流式传输 LED 图像,例如 Knight Rider 汽车的前灯。 我已经在 while 循环中尝试了一些东西,但是如果没有很多代码行,我不太明白如何实现它。我认为必须有一种方法可以做到这一点,就像增加数字写入以在 piface 扩展板上创建流式 LED 一样。这是我的代码...
class App2:
def __init__(self, master):
self.signal = False #added to stop thread
print('self.signal', self.signal)
self.master=master # I added this line to make the exit button work
frame = Frame(master)
frame.pack()
Label(frame, text='Turn LED ON').grid(row=0, column=0)
Label(frame, text='Turn LED OFF').grid(row=0, column=1)
self.button0 = Button(frame, text='Knight Rider OFF', command=self.convert0)
self.button0.grid(row=2, column=0)
self.LED0 = Label(frame, image=logo2) #added to create a row of images
self.LED1 = Label(frame, image=logo2)
self.LED2 = Label(frame, image=logo2)
self.LED3 = Label(frame, image=logo2)
self.LED4 = Label(frame, image=logo2)
self.LED5 = Label(frame, image=logo2)
self.LED6 = Label(frame, image=logo2)
self.LED7 = Label(frame, image=logo2)
self.LED0.grid(row=2, column=1)
self.LED1.grid(row=2, column=2)
self.LED2.grid(row=2, column=3)
self.LED3.grid(row=2, column=4)
self.LED4.grid(row=2, column=5)
self.LED5.grid(row=2, column=6)
self.LED6.grid(row=2, column=7)
self.LED7.grid(row=2, column=8)
self.button9 = Button(frame, text='Exit', command=self.close_window)
self.button9.grid(row=3, column=0)
def convert0(self, tog=[0]):
tog[0] = not tog[0]
if tog[0]:
print('Knight Rider ON')
self.button0.config(text='Knight Rider ON')
t=threading.Thread(target=self.LED)
t.start()
self.signal = True #added to stop thread
print('self.signal', self.signal)
print('tog[0]', tog[0])
self.LED0.config(image = logo)
else:
print('Knight Rider OFF')
self.button0.config(text='Knight Rider OFF')
self.signal = False #added to stop thread
print('self.signal', self.signal)
print('tog[0]', tog[0])
self.LED0.config(image = logo2)
def LED(self):
while self.signal: #added to stop thread
a=0
while self.signal: #added to stop thread
pfio.digital_write(a,1) #turn on
sleep(0.05)
pfio.digital_write(a,0) #turn off
sleep(0.05)
a=a+1
if a==7:
break
while self.signal: #added to stop thread
pfio.digital_write(a,1) #turn on
sleep(0.05)
pfio.digital_write(a,0) #turn off
sleep(0.05)
a=a-1
if a==0:
break
def close_window(self):
print('Knight Rider OFF')
print('self.signal', self.signal)
self.button0.config(text='Knight Rider OFF')
self.LED0.config(image = logo2)
self.signal = False #added to stop thread
print('self.signal', self.signal)
sleep(1)
print('Close Child window')
self.master.destroy() # I added this line to make the exit button work
root = Tk()
logo2 = PhotoImage(file="/home/pi/Off LED.gif")
logo = PhotoImage(file="/home/pi/Red LED.gif")
root.wm_title('LED on & off program')
app = App(root)
root.mainloop()
如此简单的任务不需要线程。在 tkinter 中设置持久重复任务非常容易,如果任务不超过几百毫秒(如果花费更长的时间,您的 UI 将开始滞后)。
基本模式是编写一个执行某些工作的函数,然后使用 after
使该函数再次调用自身。例如:
def animate():
# do something, such as turn an led on or off
<some code here to turn one led on or off>
# run this again in 100 ms
root.after(100, animate)
以上将创建一个在 tkinter 的主循环中运行的无限循环。只要 <some code here... >
不会花太长时间,动画就会显得流畅,你的 UI 也不会迟钝。
例子
这是该技术的一个简单的工作示例。它使用一个简单的迭代器循环遍历 LED,但您可以使用您想要选择下一个 LED 点亮的任何算法。您还可以同时打开或关闭屏幕上的 LED 和硬件 LED,或者打开或关闭多个 LED 等。
为了制作此代码 copy/paste-able,它使用彩色框而不是图像,但如果需要,您可以使用图像。
import tkinter as tk # Tkinter for python 2
from itertools import cycle
class LEDStrip(tk.Frame):
segments = 16
speed = 100 # ms
def __init__(self, parent):
tk.Frame.__init__(self, parent)
leds = []
for i in range(self.segments):
led = tk.Frame(self, width=12, height=8, borderwidth=1,
relief="raised", background="black")
led.pack(side="left", fill="both", expand=True)
leds.append(led)
self.current_segment = None
self.iterator = cycle(leds)
def animate(self):
# turn off the current segment
if self.current_segment:
self.current_segment.configure(background="black")
# turn on the next segment
self.current_segment = next(self.iterator) # self.iterator.next() for python 2
self.current_segment.configure(background="red")
# run again in the future
self.after(self.speed, self.animate)
root = tk.Tk()
strip = LEDStrip(root)
strip.pack(side="top", fill="x")
# start the loop
strip.animate()
root.mainloop()
可能不是您要找的东西,但您可以从中得到一些启发,先在终端上设置此 "cylon" 算法。 LED 没有中间颜色值,但我想光的剩余感知应该可以解决问题。
import sys,time
shift = lambda l, n=1: l[n:]+l[:n]
c = u' ▁▂▃▄▅▆▇' # possible color values
L = 8 # number of items
B = L*[0] # indices of items
A = [0] + list(range(7)) + list(range(7,0,-1)) + 6*[0] # light sequence
C = L*[' '] # start blank
while 1:
B[A[0]]=L # set the most brilliant light
for x in range(L):
B[x]-= 1 # decrease all lights values
B[x] = max(0,B[x]) # not under 0
C[x] = c[B[x]] # get the corresponding 'color'
A = shift(A,-1) # shift the array to the right
sys.stdout.write(('%s%s%s')%(' ',''.join(C[1:]),'\r'))
time.sleep(0.1)