【问题标题】:tkinter loop and serial writetkinter 循环和串行写入
【发布时间】:2014-02-27 05:51:15
【问题描述】:

我使用 tkinter 编写了一个 gui,我需要将 2 个刻度的值实时发送到 arduino。我已经验证了 arduino 正在使用另一个将值发送到 arduino 的草图工作,并且这些草图已被接收,我已将以下代码添加到我的 python 代码中

while True:
    #command = raw_input("Enter level ")
    #if command == '1' :
    ser.write("c"+str (c1v.get()))
    ser.write(":d"+str (c2v.get()))

我已将其移至 tkinter 主循环的内部和外部,并从 gui 不加载到仅在 gui 关闭后发送的数据中获得不同的结果。有人可以告诉我如何让 gui 运行,当我移动刻度时,值会通过串行方式实时发送到 arduino。

代码如下:

from Tkinter import *
import serial

ser = serial.Serial('/dev/ttyAMA0', 9600)



master= Tk()
master.geometry('500x500+0+0')

def print_value(val):
    print ("c1="+str (c1v.get()))
    print ("c2="+str(c2v.get()))


c1v=DoubleVar()
c2v=DoubleVar()

c1 = Scale(master, from_=255, to=0, length =400,width =100, troughcolor = 'blue',command=print_value, variable =c1v)
c1.grid(row=1,column=1)
c2 = Scale(master, from_=255, to=0, length =400,width =100, troughcolor = 'blue',command=print_value, variable =c2v)
c2.grid(row=1,column=2)


def load_p1():
    pass
    lp1 = open("/home/pi/Desktop/IEP/test/preset_test.txt")
    val1, val2 = (x.split("=")[1] for x in lp1)
    c1.set(val1)
    c2.set(val2)
    lp1.close()

#
def record():

    save_path = '/home/pi/Desktop/IEP/test'
    name_of_file = ("preset_test")
    completeName = os.path.join(save_path, name_of_file+".txt")
    file1 = open(completeName , "w")
    toFile = ("c1="+str (c1.get())+ "\n""c2="+str(c2.get()))
    file1.write(toFile)
    file1.close()



rec=Button(master, text="Record",width=20, height=10, bg='Red', command=record)
rec.grid(row=2, column=1)

load=Button(master, text="Load",width=20, height=10, bg='gold',command=load_p1)
load.grid(row=2, column=2)


master.mainloop()

while True:
    #command = raw_input("Enter level ")
    #if command == '1' :
    ser.write("c"+str (c1v.get()))
    ser.write(":d"+str (c2v.get()))

【问题讨论】:

  • 看看stackoverflow.com/questions/21440731/… 和两个答案。如果您没有看到连接,请随时询问。
  • 我没有关注,你是说因为我有一个while循环吗?我已经阅读了两个答案,但我不明白。你能解释一下我的情况有什么问题吗?
  • 不清楚你是想在程序的生命周期内发送一个连续的流,还是只在用户移动刻度时发送新值。

标签: python loops tkinter serial-port


【解决方案1】:

上下文

您使用 Tkinter mainloopwhile 循环,现在您想将两者放在一个程序中。

while X:
    do_y()

master.mainloop()

解决方案

有几种解决方案适合您。

  1. 拆分循环并使用after 让GUI 给您回电:

    def do_y2():
        do_y()
        if X:
            master.after(123, do_y2) # after 123 milli seconds this is called again
    do_y2()
    master.mainloop()
    

    如需更详细的答案,请参阅this answerBryan Oakley

  2. 由我使用guiLoop

    from guiLoop import guiLoop # https://gist.github.com/niccokunzmann/8673951#file-guiloop-py
    @guiLoop
    def do_y2():
        while X:
            do_y()
            yield 0.123 # give the GUI 123 milli seconds to do everything
    do_y2(master)
    master.mainloop()
    

    guiLoop 使用 1. 中的方法,但允许您使用一个或多个 while 循环。

  3. 使用 update 刷新 GUI。

    while X:
        do_y()
        master.update()
    

    这种方法是一种不寻常的方法,因为它取代了作为大多数 GUI 框架(如 Tkinter)的一部分的 mainloop。请注意,使用 1 和 2 您可以有多个循环,而不仅仅是 3 中的一个。

  4. 使用一个新的执行线程来并行执行您的循环。 !该线程不能直接访问 master 或任何 GUI 元素,因为 Tkinter 可能会崩溃!

    import threading
    def do_y_loop():
         while X:
             do_y()
    thread = threading.Thread(target = do_y_loop)
    thread.deamon = True # use this if your application does not close.
    thread.start()
    master.mainloop()
    
  5. 在一个新线程中启动主循环。如 4. 如果您从线程访问 GUI,Tkinter 可能会崩溃。

    import threading
    thread = threading.Thread(target = master.mainloop)
    thread.deamon = True # use this if your application does not close.
    thread.start()
    while X:
        do_y()
    

    在 4. 和 5. 中,GUI 和 while 循环之间的通信可以/应该通过全局变量,但从不通过 tkinter 方法。


对于 PyQT,请参阅以下问题:

【讨论】:

  • 我已经设法使用 guiLoop 做到了,谢谢,您认为哪种方式是最快的做事方式?
  • 在 C-Python 中没关系。您可以采用选项 1-5(选项 1-2 为 0 毫秒)。我这么认为是因为 Standart-CPython 只使用一个线程(如果你启动了多个线程)。如果你真的有并发和许多处理器,你可以使用线程版本甚至多处理。也许我可以将其添加为选项 6。但在您的情况下,所有版本都应该没问题。如果你测量一些东西,你可以告诉我/我们。顺便说一句 - 如果它有效,请接受它作为答案;)每周有 2 人问同样的问题。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-09-26
  • 1970-01-01
  • 2016-03-08
相关资源
最近更新 更多