简体   繁体   English

用Python创建带有一行图像的Knight Rider风格的流式LED

[英]Creating a Knight Rider style streaming LED with a row of images in Python

I'm learning python with the raspberry pi and a pi-face expansion board. 我正在用树莓派和pi-face扩展板学习python。 Using Tkinter I've created a Gui with buttons to operate the pi-face LED's. 使用Tkinter,我创建了一个带有按钮的Gui,用于操作pi面LED。 In one part of the code I open a new window which shows a button and a row of images of a LED in the 'off' state. 在代码的一部分中,我打开了一个新窗口,其中显示了一个按钮以及处于“关闭”状态的一排LED图像。 I'm trying to add some code to make the row of LED images stream an LED image in the 'on' state left to right along the row of images, like the Knight Rider car's front lights. 我正在尝试添加一些代码,以使该行LED图像沿着图像行从左到右以“打开”状态流式传输LED图像,例如Knight Rider汽车的前灯。 I've tried a few things in the while loop but can't quite see how to achieve it without a lot of lines of code. 我在while循环中尝试了一些事情,但是如果没有很多代码行就看不到如何实现它。 I think there must be a way to do it in the same way that the digital write is incremented to create the streaming LED on the piface expansion board. 我认为必须有一种方法可以像增加数字写入一样在piface扩展板上创建流式LED。 Here is my code... 这是我的代码...

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()

You don't need threads for such a simple task. 您不需要线程即可完成如此简单的任务。 It's very easy to set up a persistent repeating task in tkinter, if the task doesn't take more than a couple hundred milliseconds (if it takes much longer, your UI will start to lag). 在tkinter中设置持久重复任务非常容易,如果该任务花费的时间不超过几百毫秒(如果花费的时间更长,则用户界面将开始滞后)。

The basic pattern is to write a function that does some work, and then have that function cause itself to be called again using after . 基本模式是编写一个完成某些工作的函数,然后使该函数使用after再次调用自身。 For example: 例如:

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)

The above will create an infinite loop that runs inside tkinter's mainloop. 上面的代码将创建一个在tkinter的mainloop中运行的无限循环。 As long as <some code here... > doesn't take too long, the animation will appear fluid and your UI won't be laggy. 只要<some code here... >花费的时间不长,动画就会显得流畅并且您的UI不会太迟钝。

Example

Here's a simple working example of the technique. 这是该技术的一个简单的工作示例。 It uses a simple iterator to cycle through the leds, but you can use any algorithm you want to pick the next led to light up. 它使用一个简单的迭代器来遍历所有led,但是您可以使用要选择下一个led点亮的任何算法。 You could also turn on or off both the on screen and hardware led at the same time, or turn on or off multiple leds, etc. 您也可以同时打开或关闭屏幕上的LED和硬件LED,或者打开或关闭多个LED等。

To make this code copy/paste-able, it uses colored frames rather than images, but you can use images if you want. 为了使此代码可复制/粘贴,它使用彩色框架而不是图像,但是您可以根据需要使用图像。

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()

Might not be exactly what you are looking for, but you can get some inspiration to set up this "cylon" algorithm on the terminal first. 可能不完全是您要查找的内容,但是您可以从中得到一些启发,首先在终端上设置此“ cylon”算法。 LEDs don't have intermediate color values, but I guess the remnant perception of light should do the trick. 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)

Or try that one https://www.trinket.io/python/79b8a588aa 或尝试一个https://www.trinket.io/python/79b8a588aa

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

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