0

I'm trying to plot data from serial port in a tkinter gui. The plot should be plotted and updated only when a specific pack comes from serial. I can parse the new incoming data and update the GUI (text area). But when I call the "plot()" function from the "update_gui" thread, the program quit and I get the

"Process finished with exit code -1073741819 (0xC0000005)"

message.

Instead, if I call "plot()" from somewhere else (command button, or simply before mainloop()), the plot is generated and shown.

Here is the relevant part of the code:


import threading
import tkinter as tk
import tkinter.scrolledtext as st
import rx_seriale as rx_ser
from matplotlib.figure import Figure
from matplotlib.backends.backend_tkagg import (FigureCanvasTkAgg, NavigationToolbar2Tk)
import queue

running = True
serial_data = ''
filter_data = ''
update_period = 5
serial_object = None
gui = tk.Tk()
gui.title("UART Interface")
my_queue = queue.Queue()
t1 = ''


def plot(valori):
    global frame_plot1

    try:
        # the figure that will contain the plot
        fig = Figure(figsize=(4.5, 4), dpi=100)

        # adding the subplot
        plot1 = fig.add_subplot(111)

        #dummy values
        y = [i ** 2 for i in range(101)]

        # plotting the graph
        plot1.plot(y)

        # creating the Tkinter canvas
        # containing the Matplotlib figure
        canvas = FigureCanvasTkAgg(fig, master=frame_plot1)
        canvas.draw()

        # placing the canvas on the Tkinter window
        canvas.get_tk_widget().pack()

        # creating the Matplotlib toolbar
        #toolbar = NavigationToolbar2Tk(canvas, frame_plot1)
        #toolbar.update()

        # placing the toolbar on the Tkinter window
        #canvas.get_tk_widget().pack()
    except Exception as e:
        print('Errore:' + str(e))


def update_gui():
    global filter_data
    global update_period
    global my_queue
    global type_test, test_status,flag

    while (1):

        data = my_queue.get(block=True)

        text.insert('end', test_status[data[0]] + " - " + type_test[data[1]])
        text.insert('end', '\n')
        text.see('end')

        if (data[1] == 6):
            plot(1)


if __name__ == "__main__":
   
'''
...
all the stuff for design TK windows
...
'''

    # threads
    t2 = threading.Thread(target=update_gui)
    t2.daemon = True
    t2.start()

    # mainloop
    gui.geometry('1000x500')
    gui.mainloop()

What goes wrong? Thank you.

Lorecn1
  • 39
  • 4
  • You shouldn't call any tkinter methods from threads other than the one where you initially created the `tk.Tk()` window – TheLizzard Apr 27 '21 at 15:45
  • @TheLizzard: ok, but why the text area updating method works? I forget to mention that the "plot()" function is correctly executed until the "canvas.draw()" call. – Lorecn1 Apr 27 '21 at 16:07
  • Some (or most?) of `tkinter`'s behaviour is undefined when you call its methods from other threads so you can't expect anything. You should use a `.after` loop instead. For more info look at [this](https://stackoverflow.com/a/459131/11106801) – TheLizzard Apr 27 '21 at 16:10
  • @TheLizzard: Thank you for your comment. I tried `.after ` but, if I haven't misunderstood something, this method is executed one time. Actually my issue is to trigger a Tkinter update with an event that it isn't raised from a button, or a key press, etc, but comes from a serial receiver thread. I can pass data through threads with queues, but how can I programmatically raise a tk event? – Lorecn1 Apr 29 '21 at 10:12
  • You shouldn't. Try changing `my_queue.get(block=True)` to `my_queue.get(block=False)`. Also if you use `.after` inside a `.after` callback you can make a loop. Look at [this](https://stackoverflow.com/a/459131/11106801) – TheLizzard Apr 29 '21 at 10:17

0 Answers0