如何同时运行一个更新matplotlib图和一个更新tkinter程序?

fsi0uk1n  于 2023-03-13  发布在  其他
关注(0)|答案(1)|浏览(128)

所以我想运行一段代码,它使用一个更新的Tkinter窗口,然后“结果”会显示在一个更新的matplotlib图形上。
我试着正常地写它们,但是其中一个不更新。这是因为两个窗口都需要一种“while True”循环才能工作。我试过的另一件事是在不同的文件中运行matplotlib图,并从主文件导入变量。但是这不起作用,因为“绘图文件”中的代码只是运行“主文件”中的代码而不运行其自己的代码。
举个简单的例子:
主文件(main_test):

from tkinter import *
from random import randint
from time import sleep

square_id = []
numberofsquares = 0
numberofsquares_list = []
time = 0
time_list = []

def create_window(color, title, height, width):
    global c, window, HEIGHT, WIDTH
    HEIGHT = height
    WIDTH  = width
    window = Tk()
    window.title(title)
    c = Canvas (window, width=WIDTH, height=HEIGHT, bg=color)
    c.pack()

def create_squares():
    global numberofsquares
    numberofsquares = numberofsquares + 1
    x = randint(0, HEIGHT)
    y = randint(0, WIDTH)
    square = c.create_rectangle(0,0,30, 30, fill='red')
    square_id.append(square)
    c.move(square, x, y)


create_window('white', 'test', 500, 500)

while True:
    time_list.append(time)
    time = time + 1
    window.update()
    for i in range(randint(0, 3)):
        create_squares()
    sleep(0.1)
    numberofsquares_list.append(numberofsquares)

打印文件:

from main_test import numberofsquares_list, time_list
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation


def animate(i):
    plt.cla()
    plt.plot(numberofsquares_list, time_list)

ani = FuncAnimation(plt.gcf(), animate, interval=1000)

plt.tight_layout()
plt.show()

如果我运行Plot文件,它只运行Main文件,Matplotlib窗口永远不会打开。
你知道有什么方法可以解决这个问题吗?谢谢:)

ercv8c1e

ercv8c1e1#

你不应该在gui应用程序中使用while Truetime.sleep,这两个过程都会导致gui冻结,迫使你使用像window.update()这样不必要的方法。
您的while True循环也可以使用预定的回调来轻松实现,这将允许您调用mainloop方法,以便您可以真正地将控制权交给GUI。
您还应该学习使用classes,以避免处理容易出错且难以读取的全局变量。
为了回答你的问题,你可以在更新绘图的同时继续保持gui的运行,一种方法是在一个单独的线程中运行绘图。
例如:

import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from tkinter import *
from random import randint
import threading

class Thread(threading.Thread):

    def __init__(self, window):
        super().__init__()
        self.window = window

    def animate(self, i):
        plt.cla()
        plt.plot(window.numberofsquares_list, window.time_list)

    def run(self): 
        # the run method gets automatically triggered when you start the thread
        FuncAnimation(plt.gcf(), self.animate, interval=3000)
        plt.tight_layout()
        plt.show()

class Window(Tk):  # the window class is your window
    # the __init__ method is essentially the same as your create window function
    def __init__(self, color, title, width, height):  
        super().__init__()  
        self.square_id = []  # make all your global variables class attributes
        self.numberofsquares = 0
        self.numberofsquares_list = []
        self.time = 0
        self.time_list = []
        self.height = height
        self.width  = width
        self.title(title)
        self.c = Canvas (self, width=width, height=height, bg=color)
        self.c.pack()
        self.create_squares()   # run the create squares at the end

    def create_squares(self):  
        # combined your create_squares function and your while loop into a single method
        self.time_list.append(self.time)  
        self.time = self.time + 1
        for _ in range(1, randint(1,20)):
            self.numberofsquares += 1
            x = randint(0, self.height)
            y = randint(0, self.width)
            square = self.c.create_rectangle(0,0,30, 30, fill='red')
            self.square_id.append(square)
            self.c.move(square, x, y)
        self.numberofsquares_list.append(self.numberofsquares)
        # this reschedules the function to run again at a random interval 
        # between half a second and 2 seconds
        self.after(randint(500,2000), self.create_squares)  

if __name__ == "__main__":
    window = Window('white', 'test', 500, 500)  # create the window
    thread = Thread(window)   # create the thread passing the window as argument
    thread.start()            # start the thread
    window.mainloop()         # run the gui event loop

相关问题