【问题标题】:'Gui' object has no attribute 'after''gui' 对象没有属性 'after'
【发布时间】:2016-07-29 10:31:17
【问题描述】:

我使用了我的工作 tkinter 代码(仅绘制窗口/按钮等)并尝试在此处从批准的答案中添加一些代码:python code for serial data to print on window.

已批准的答案只需进行非常小的修改即可自行工作,但添加到我的代码中时出现错误“'Gui' object has no attribute 'after'”

我不明白为什么在 Gui 类中而不是在方法 process_serial 中查找属性“after”。

from tkinter import *
from tkinter import ttk

import serial
import threading
import queue

class SerialThread(threading.Thread):
    def __init__(self, queue):
        threading.Thread.__init__(self)
        self.queue = queue
    def run(self):
        s = serial.Serial('COM11',115200)
        while True:
            if s.inWaiting():
                text = s.readline(s.inWaiting())
                self.queue.put(text)

class Gui():
    def __init__(self, master):
        ###MAIN FRAME###
        mainFrame = Frame(master, width=50000, height=40000)
        mainFrame.pack(fill = BOTH, expand = 1)

        ###LIST FRAME###
        listFrame = Frame(mainFrame)
        listFrame.pack(side = TOP, fill = BOTH, expand = 1)

        self.sensorList = ttk.Treeview(listFrame)

        self.sensorList["columns"]=("MAC","Type","Value","Voltage","Firmware","Rate","RSSI")
        self.sensorList.column("MAC", width=200, minwidth=200)
        self.sensorList.column("Type", width=100, minwidth=100)
        self.sensorList.column("Value", width=100, minwidth=100)
        self.sensorList.column("Voltage", width=100, minwidth=100)
        self.sensorList.column("Firmware", width=100, minwidth=100)
        self.sensorList.column("Rate", width=100, minwidth=100)
        self.sensorList.column("RSSI", width=100, minwidth=100)
        self.sensorList.heading("MAC", text="MAC")
        self.sensorList.heading("Type", text="Type")
        self.sensorList.heading("Value", text="Value")
        self.sensorList.heading("Voltage", text="Voltage")
        self.sensorList.heading("Firmware", text="Firmware")
        self.sensorList.heading("Rate", text="Rate")
        self.sensorList.heading("RSSI", text="RSSI")

        self.sensorList.pack(fill = BOTH, expand = 1,  pady=5, padx=5)

        ###TEXT AREA FRAME###
        textAreaFrame = Frame(mainFrame)
        textAreaFrame.pack(side = TOP, fill = BOTH, expand = 1)

        self.textArea = Text(textAreaFrame)
        self.textArea.pack(fill = BOTH, expand = 1,  pady=5, padx=5)

        ###INPUT FRAME###
        inputFrame = Frame(mainFrame)
        inputFrame.pack(side = BOTTOM, fill = X, expand = 0)

        self.input = Entry(inputFrame)
        self.input.pack(side=LEFT, fill = X, expand = 1,  pady=5, padx=5)

        self.comboAction = ttk.Combobox(inputFrame)
        self.comboAction.pack(side = LEFT, pady=5, padx=5)

        self.comboDevice = ttk.Combobox(inputFrame)
        self.comboDevice.pack(side = LEFT, pady=5, padx=5)

        self.sendButton = Button(
            inputFrame, text="SEND", command=mainFrame.quit
        )

        self.sendButton.pack(side=LEFT,pady=5, padx=5)

        #self.button = Button(
        #   mainFrame, text="QUIT", fg="red", command=mainFrame.quit
        #)
        #self.button.pack(side=LEFT)

        #self.hi_there = Button(mainFrame, text="Hello", command=self.say_hi)
        #self.hi_there.pack(side=LEFT)

        ###AFFIX MINIMUM SIZE OF MAIN WINDOW TO PREVENT POOR SIZING###
        master.update()
        master.minsize(root.winfo_width(), root.winfo_height())
        master.minsize(master.winfo_width(), master.winfo_height())

        ###SERIAL PORT###
        self.queue = queue.Queue()
        thread = SerialThread(self.queue)
        thread.start()
        self.process_serial()

    def process_serial(self):
        while self.queue.qsize():
            try:
                self.textArea.delete(1.0, 'end')
                self.textArea.insert('end', self.queue.get())
            except Queue.Empty:
                pass
        self.after(100, self.process_serial)



    def say_hi(self):
        s = self.input.get()
        print ("hi there, everyone!" + s)

root = Tk()

gui = Gui(root)

root.mainloop()
root.destroy() # optional; see description below

【问题讨论】:

    标签: python multithreading tkinter pyserial


    【解决方案1】:

    罪魁祸首在process_serial函数的这一行:

    self.after(100, self.process_serial)
    

    这里的 self 变量是指 Gui 对象,而不是具有 'after' 功能的 tkinter 对象。

    您的代码与链接问题中的代码不匹配。您的课程没有扩展 tkinter 对象。答案中的类扩展了 tkinter Tk 对象,如下所示:

    class App(tk.Tk):
    

    从而从 Tk 类继承函数。

    要为您的代码解决此问题,请将 process_serial 函数中的 self 替换为 tkinter 对象,例如 self.textArea。

    self.textArea.after(100, self.process_serial)
    

    或者,您可以将 tk.Tk 子类化,就像在链接的答案中一样。但我在这里看不到额外的好处。

    【讨论】:

    • 谢谢。这行得通,但我必须花一些时间来真正理解发生了什么。解决此问题后,我的程序无法正常关闭。我的意思是我没有回到 cmd 行输入,当我 CTRL+C 时没有任何反应。我删除了最后一个 root.destroy() 因为它抛出了一个错误,说它已经被破坏了。是因为我正在运行那个 process_serial 循环吗?
    • 应用程序的关闭按钮默认为销毁它。然后它从 root.mainloop() 函数中出来并尝试调用 root.destroy()。这失败了,因为它已经被销毁了。因此,root.destroy() 是不必要的。您不应该被带回 cmd 行,因为 mainloop() 正在运行。要在按下 ctrl-C 时退出应用程序,请将线程的 thread.daemon 设置为 True。
    【解决方案2】:

    方法after 继承自Tkinter.TkCheck mentioned question

    你可能应该继承 Tkinter.Tk

    ...
    import Tkinter
    class Gui(Tkinter.Tk)
        ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-01-12
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      • 2012-12-01
      • 2021-08-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多