0 Câu hỏi: Ngoại lệ trong cuộc gọi lại Tkinter: AttributionError: Đối tượng 'noneType' không có thuộc tính 'update'

câu hỏi được tạo ra tại Thu, May 9, 2019 12:00 AM

Tôi đang cố gắng thực hiện cốt truyện bằng cách sử dụng tkinter, nhưng tôi đang gặp lỗi này và tôi không thể theo dõi lại:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:\Python37\lib\tkinter\__init__.py", line 1705, in __call__
    return self.func(*args)
  File "C:\Python37\lib\tkinter\__init__.py", line 749, in callit
    func(*args)
  File "C:\Python37\lib\site-packages\matplotlib\backends\_backend_tk.py", line 346, in idle_draw
    self.draw()
  File "C:\Python37\lib\site-packages\matplotlib\backends\backend_tkagg.py", line 9, in draw
    super(FigureCanvasTkAgg, self).draw()
  File "C:\Python37\lib\site-packages\matplotlib\backends\backend_agg.py", line 402, in draw
    self.figure.draw(self.renderer)
  File "C:\Python37\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Python37\lib\site-packages\matplotlib\figure.py", line 1649, in draw
    renderer, self, artists, self.suppressComposite)
  File "C:\Python37\lib\site-packages\matplotlib\image.py", line 138, in _draw_list_compositing_images
    a.draw(renderer)
  File "C:\Python37\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Python37\lib\site-packages\matplotlib\axes\_base.py", line 2628, in draw
    mimage._draw_list_compositing_images(renderer, self, artists)
  File "C:\Python37\lib\site-packages\matplotlib\image.py", line 138, in _draw_list_compositing_images
    a.draw(renderer)
  File "C:\Python37\lib\site-packages\matplotlib\artist.py", line 50, in draw_wrapper
    return draw(artist, renderer, *args, **kwargs)
  File "C:\Python37\lib\site-packages\matplotlib\text.py", line 709, in draw
    bbox, info, descent = textobj._get_layout(renderer)
  File "C:\Python37\lib\site-packages\matplotlib\text.py", line 286, in _get_layout
    key = self.get_prop_tup(renderer=renderer)
  File "C:\Python37\lib\site-packages\matplotlib\text.py", line 871, in get_prop_tup
    x, y = self.get_unitless_position()
  File "C:\Python37\lib\site-packages\matplotlib\text.py", line 854, in get_unitless_position
    y = float(self.convert_yunits(self._y))
  File "C:\Python37\lib\site-packages\matplotlib\artist.py", line 195, in convert_yunits
    return ax.yaxis.convert_units(y)
  File "C:\Python37\lib\site-packages\matplotlib\axis.py", line 1530, in convert_units
    ret = self.converter.convert(x, self.units, self)
  File "C:\Python37\lib\site-packages\matplotlib\category.py", line 53, in convert
    unit.update(values)
AttributeError: 'NoneType' object has no attribute 'update'

Đây là mã của tôi:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
Graphic user interface that can be used with the experiment to write values and give live graphical feedback to the user
"""
import time
from collections import deque
try:
    # for Python2
    import Tkinter as tk
    import ttk
except ImportError:
    # Python 3
    import tkinter as tk
    from tkinter import ttk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from matplotlib.gridspec import GridSpec
from crio.communication_handler import Handler

bitfile = "../LabVIEW/FPGA Bitfiles/Live_bitfile.lvbitx"
compactRIO = "rio://169.254.47.210/RIO0"
steps = "../Examples/Step_Setter/Steps.yml"
test = "../Examples/test.yml"
config = "../Examples/YAML_Config.yml"
cm = Handler(config, test, steps, bitfile, compact_rio=None)
cm.verbose = False
cm.start()


# Setting constants
HISTORY_LEN = 200  # Number of data points to show in the plot
GRAPH_INTERVAL = 100  # milliseconds between graph updates
XLABEL = "Time (s)"
# For real time graphing
PAUSE = "Pause Graph"
UNPAUSE = "Unpause Graph"
START = "Start Graphing"
CLEAR = "Reset Graphs"
# GUI Colors
background_color = "#ffffff"
button_color = "cadet blue"
button_txt_color = "snow"

button_opts = dict(  # general button settings
    width=30,
    font=("MS Serif", 12),
    borderwidth=3.5,
    relief="raised",
    bg=button_color,
    fg=button_txt_color)

# Container for the plots so graphing is simplified
gs = GridSpec(3, 6)  # (x,y)
PLOTS = [
    # (ylabel, title, YLIM_HIGH, YLIM_LOW,  plot position, register)
    ('Phi', 'McKenna: Actual Equivalence Ratio (Phi)', 6, 0, gs[0, 0:-4],
     'Actual_Phi'),
    ('Velocity (cm/s)', 'McKenna: Actual Mixture Velocity', 500, 0,
     gs[0, 2:-2], 'Actual_Velocity'),
    ('Air, LPM', 'McKenna Air Flow rate (LPM)', 600, 0, gs[0, 4:], 'MFC_Air'),
    ('Hydrogen, LPM', 'Hydrogen Fuel Flow Rate (LPM)', 500, 0, gs[2, 0:-4],
     'MFC_Fuel'),
    ('Air SCCM', 'Tube Air Flow Rate (SCCM)', 75, 0, gs[1, 2:-2],
     'MFC_Tube_Air'),
    ('N₂, SCCM', 'Tube N₂ Flow Rate (SCCM)', 50, 0, gs[1, 4:], 'MFC_Tube_N2'),
    ('Temperature', 'Temperature Large', 1700, 0, gs[2, 4:],
     'Temperature_Large'),
    ('Amplitude', 'Microphone Readings', 15, -15, gs[2, 2:-2], 'Mic_Voltage'),
    ('Pressure (PSI)', 'Pressure Reading', 500, 0, gs[1, 0:-4],
     'Pressure_Reading')
]
COLUMNS = 2  # Determines entries in a row
# Fields will correspond with the Dynamic User Input entries i.e. the set points
FIELDS = (("Dynamic User Inputs", (
    cm.set_point
)), )


class GUI(tk.Tk):
    """GUI created from Tkinter

    Note:
        The __init__ method creates the GUI window with using a
        notebook tabbed style and initializes each tab.

        The input fields tab is created to allow for input values
        for the experiment.

        The graph window tab is where the live plotting of the
        results are to be displayed
    """

    def __init__(self):
        try:
            super(tk.Tk, self).__init__(self)
        except TypeError:
            super().__init__()
        # GUI window
        self.title("Python Graphic User Interface")

        # Maximizes window when exiting fullscreen mode
        # self.state('zoomed') # <-- not supported in Linux
        self.attributes("-fullscreen", True)
        self.configure(background=background_color)
        self.bind("<Escape>", self.end_fullscreen)

        # Title
        title = tk.Label(
            self,
            text="Microcombustion Project",
            bg=background_color,
            font=("Bodoni bold", 45))
        title.pack(fill=tk.BOTH)

        style = ttk.Style()
        style.theme_create(
            "MyStyle",
            parent="alt",
            settings={
                "TNotebook": {
                    "configure": {
                        "tabmargins": [0, 5, 0, 0],
                        "background": "#ffffff"
                    }
                },
                "TNotebook.Tab": {
                    "configure": {
                        "padding": [100, 8],
                        "font": ("MS Serif, bold", 14)
                    }
                }
            })

        style.theme_use("MyStyle")

        nb = ttk.Notebook(self)
        nb.pack(expand=True, fill=tk.BOTH)

        # Input fields
        input_fields = EntryWindow(self, background=background_color)
        nb.add(input_fields, text='Values')

        # Graph
        graph_window = GraphWindow(self)
        nb.add(graph_window, text='Graphs')

    def end_fullscreen(self, event=None):
        """Toggle full screen"""
        self.state = False
        self.attributes("-fullscreen", False)
        return "break"


# Creating labels and entries out of a tuple
class Entry:
    """Creating labels and entries out of a tuple

    Note:
        The Entry class is created to store/set dynamic inputs on the GUI

    Args:
            master: The main GUI
            text: Input field names
            value: Initial values
            idx: Index

    """
    instances = []

    def __init__(self, master, text, value, idx):
        self.text = text
        row, column = divmod(idx, COLUMNS)
        lbl = tk.Label(
            master,
            text=text.replace("_", " ") + ":",
            bg=background_color,
            font=("Bodoni bold", 15))
        lbl.grid(row=row, column=column * 2, sticky='e')
        self.ent = ttk.Entry(master, font="Bodoni 14", justify="right")
        self.ent.insert(0, '{}'.format(value))
        self.ent.grid(row=row, column=column * 2 + 1)
        self.instances.append(self)

    def get(self):
        """Retrieves the values

        Returns: The text formatted properly and entries

        """
        return self.text, self.ent.get()


class EntryWindow(tk.Frame):
    """The entry window for the GUI

    Args:
            master: The main GUI
            **kwargs: Tkinter's Frame method takes keyword arguments
    """

    def __init__(self, master=None, **kwargs):
        self.frame = tk.Frame.__init__(self, master, **kwargs)
        master.bind("<Return>", self.fetch_values)

        # Input fields
        for name, properties in FIELDS:
            namelbl = tk.Label(
                self,
                text=name,
                bg=background_color,
                font=("Bodoni bold", 30),
                pady=25)
            namelbl.pack()
            input_fields = tk.Frame(self, background=background_color)
            for idx, (field, initVal) in enumerate(properties.items()):
                Entry(input_fields, field, initVal, idx)
                input_fields.pack()

        # Buttons
        self.set_button = tk.Button(
            self, text='Set Values', command=self.fetch_values, **button_opts)
        self.set_button.pack()

    def fetch_values(self, event=None):
        """Fetching input entries

        Args:
            event: None

        Returns: Sets the TCP data to the inputted parameters
        """
        # Dictionary that will act like a JSON file
        data = dict(elem.get() for elem in Entry.instances)
        print('Values have been set.')


class GraphWindow(tk.Frame):
    """Frame containing graphed data"""

    def __init__(self, master=None, **kwargs):
        """

        Args:
            master: The main GUI
            **kwargs: Tkinter's Frame method takes keyword arguments
        """
        self.frame = tk.Frame.__init__(self, master, **kwargs)
        self.start_time = time.time()
        self.running = False
        self.ani = None

        # Graphing plots from predefined PLOTS
        self.fig = plt.Figure()
        self.plots = []  # a container for the plots
        for ylabel, title, ylim_high, ylim_low, position, register in PLOTS:
            ax = self.fig.add_subplot(position)
            line, = ax.plot([], [], lw=2)
            ax.set_ylim(ylim_low, ylim_high)
            ax.set_xlabel(XLABEL)
            ax.set_ylabel(ylabel)
            ax.set_title(title)
            bbox_props = dict(
                boxstyle="round,pad=0.3", fc="cyan", ec="b", lw=2)
            t = ax.text(
                0, 0, "0", ha="right", va="center",
                bbox=bbox_props)  # Indicator
            self.plots.append((ax, line, register, t))

        # Adjusting subplot placement
        self.fig.subplots_adjust(
            bottom=.075, left=.05, right=.99, top=.9, hspace=.35, wspace=0.35)
        self.canvas = FigureCanvasTkAgg(self.fig, master=self)
        self.canvas.draw()
        self.canvas.get_tk_widget().pack(expand=True, fill=tk.BOTH)

        # Start, pause, unpause button that is called from on_click()
        btn_frame = tk.Frame(self)
        self.btn = tk.Button(
            btn_frame, text=START, command=self.on_click, **button_opts)
        self.btn.pack(side=tk.LEFT)
        btn = tk.Button(btn_frame, text=CLEAR, command=cm.clear(), **button_opts)
        btn.pack(side=tk.LEFT)
        btn_frame.place(relx=0.5, rely=0, anchor='n')

    def on_click(self):
        """How buttons in the GraphWindow respond to being pressed"""
        if self.ani is None:
            return self.start()  # animation is not running; start it

        if self.running:
            self.ani.event_source.stop  # animation is running; pause it
            self.btn.config(text=UNPAUSE)
        else:
            self.ani.event_source.start()  # animation is paused; unpause it
            self.btn.config(text=PAUSE)
        self.running = not self.running

    def start(self):
        """Start graphing"""
        self.ani = animation.FuncAnimation(self.fig, self.update_graph, interval=GRAPH_INTERVAL)
        self.running = True
        self.btn.config(text=PAUSE)
        self.ani._start()


    def update_graph(self, i):
        """Function to constantly plot new data"""
        # If statement to check that data is being read
        if cm.set_point:
            dt = 10
            if self.start_time < dt:
                second_time = '00:00:00'
            else:
                hours, rem = divmod(time.time() - self.start_time - dt, 3600)
                minutes, seconds = divmod(rem, 60)
                second_time = '{:0>2}:{:0>2}:{:02.0f}'.format(
                    int(hours), int(minutes), seconds)

            """
                Run time and data needs to be set from cm
            """
            x_lim = second_time, max(cm.fpga.run_time)
            last_x = cm.fpga.run_time[-1]
            for ax, line, register, text in self.plots:
                line.set_data(cm.fpga.run_time, cm.fpga.result[register])
                ax.set_xlim(*x_lim)  # rescale X
                last_y = cm.fpga.run_time[-1]
                text.set_text(str(last_y))
                text.set_position((last_x, last_y))


class Plotting:
    """Plotting the data"""

    def __init__(self):
        self.output_data = {}  # initial data value
        self.xdata = deque([], maxlen=HISTORY_LEN)
        self.ydata = {}  # container for the ydata
        self.indicators = []  # container for the indicator functions
        for ylabel, title, ylim_high, ylim_low, position, register in PLOTS:
            self.ydata[register] = deque([], maxlen=HISTORY_LEN)

    def clear(self):
        """Clears the data read"""
        self.xdata.clear()
        for ydata in self.ydata.values():
            ydata.clear()
        self.start_time = time.time()


def run_gui():
    root = GUI()
    root.iconbitmap(r'../docs/lsu_tiger.ico')
    root.mainloop()

Và tôi chỉ gọi hàm run_gui để lấy AttributeError: 'NoneType' object has no attribute 'update' Tôi không chắc điều gì gây ra lỗi hoặc cách truy tìm lại. Tôi đã bị mắc kẹt trong vấn đề này từ lâu và thực sự có thể sử dụng một số trợ giúp

    
0
  1. Vui lòng thử giảm điều này xuống thành Ví dụ tối thiểu, đầy đủ và có thể xác minh . Bạn đã đăng quá nhiều mã.
    2019-05-09 15: 32: 44Z
  2. Tôi không chắc lỗi xuất phát từ đâu nên tôi đã thêm toàn bộ tệp GUI
    2019-05-09 15: 35: 15Z
  3. Tôi không nghĩ rằng điều này có liên quan trực tiếp đến vấn đề của bạn, nhưng xem ra: btn = tk.Button(btn_frame, text=CLEAR, command=cm.clear(), **button_opts) có lẽ nên là btn = tk.Button(btn_frame, text=CLEAR, command=cm.clear, **button_opts) trừ khi bạn cố ý muốn cm.clear() chương trình và không phải mỗi khi bạn nhấp vào nút Xoá.
    2019-05-09 15: 35: 51Z
  4. Nếu bạn không chắc chắn lỗi ở đâu, thì bạn cần phải gỡ lỗi nhiều hơn trước khi đặt câu hỏi. Ví dụ: tôi cá là bạn có thể xóa tất cả các mã liên quan đến kiểu mà không ảnh hưởng đến vấn đề. Bạn có thể xóa màu nền, các thuộc tính khác của cửa sổ, một số vật dụng, phương thức end_fullscreen, v.v. Không còn nghi ngờ gì nữa, bạn có thể xóa nhiều mã hơn.
    2019-05-09 15: 39: 29Z
0 Câu trả lời                              0                         
nguồn đặt đây