我正在使用Tkinter构建一个GUI,它将在窗口中显示动画图形(以及其他一些小部件)。这很好用,但第二个matplotlib窗口也会与Tkinter主窗口一起打开。我怎样才能防止这种情况发生?
import matplotlib
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, NavigationToolbar2TkAgg
from matplotlib.figure import Figure
import Tkinter as tk
import ttk
class Application(tk.Frame):
def __init__(self, master=None):
tk.Frame.__init__(self, master)
#self.a = Arduino() #the data is coming in from an arduino
self.createWidgets()
def createWidgets(self):
fig = plt.figure(figsize=(6,6))
ax = fig.add_axes([0,0,1,1])
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().place(x=0, y=0)
self.plotbutton=tk.Button(master = root, text="plot", command=lambda: self.plot(canvas,ax))
self.plotbutton.place(x=500, y=0)
self.quitButton = tk.Button(master=root, text="quit", command=self.quit)
self.quitButton.place(x=600, y=0)
def plot(self,canvas,ax):
while(1):
print "plotting"
plt.pause(0.1)
ax.clear() # clear axes from previous plot
#values = self.getData(arduino) #in the full program, I get new theta and r data from an arduino
theta = [0, 1, 2, 3, 4, 5] #arbitrary axis values for testing purposes
r = [0, 1, 2, 3, 4, 5]
ax.plot(r, theta)
plt.xlim([0, 6]) #arbitrary axes limits
plt.ylim([0, 6])
canvas.draw()
def quit(self):
self.master.destroy()
root=tk.Tk()
root.geometry("950x500+300+300")
app=Application(master = root)
app.mainloop()
谢谢!
编辑:将程序变成工作示例
答案 0 :(得分:1)
谢谢你的例子。它是plt.pause()
函数调用一个新窗口(我也不知道)。请改用time.sleep
。但是你有一个更大的问题:在GUI中有任何while(1)
循环将锁定GUI。使用matplotlib动画功能正确完成。这是我为另一个SO答案做的一个例子;我添加了一个随机数据生成器,因此您可以看到它在没有数据连接的情况下运行:
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
#~ import serial
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
import matplotlib.animation as animation
from collections import deque
import random
import time
HISTORY_LEN = 200
class App(tk.Frame):
def __init__(self, master=None, **kwargs):
tk.Frame.__init__(self, master, **kwargs)
self.running = False
self.ani = None
btns = tk.Frame(self)
btns.pack()
lbl = tk.Label(btns, text="update interval (ms)")
lbl.pack(side=tk.LEFT)
self.interval = tk.Entry(btns, width=5)
self.interval.insert(0, '30')
self.interval.pack(side=tk.LEFT)
self.btn = tk.Button(btns, text='Start', command=self.on_click)
self.btn.pack(side=tk.LEFT)
self.fig = plt.Figure()
self.ax1 = self.fig.add_subplot(111)
self.line, = self.ax1.plot([], [], lw=2)
self.canvas = FigureCanvasTkAgg(self.fig,master=self)
self.canvas.show()
self.canvas.get_tk_widget().pack()
self.ax1.set_ylim(0,100)
self.ax1.set_xlim(0,500)
def on_click(self):
'''the button is a start, pause and unpause button all in one
this method sorts out which of those actions to take'''
if self.ani is None:
# animation is not running; start it
return self.start()
if self.running:
# animation is running; pause it
self.ani.event_source.stop()
self.btn.config(text='Un-Pause')
else:
# animation is paused; unpause it
self.ani.event_source.start()
self.btn.config(text='Pause')
self.running = not self.running
def start(self):
self.xdata = deque([], maxlen=HISTORY_LEN)
self.ydata = deque([], maxlen=HISTORY_LEN)
#~ self.arduinoData = serial.Serial('com5', 115200)
#~ self.arduinoData.flushInput()
self.ani = animation.FuncAnimation(
self.fig,
self.update_graph,
interval=int(self.interval.get()),
repeat=True)
self.running = True
self.btn.config(text='Pause')
self.ani._start()
self.start_time = time.time()
print('started animation')
def update_graph(self, i):
self.xdata.append(i)
#~ self.ydata.append(int(self.arduinoData.readline()))
self.ydata.append(random.randrange(100)) # DEBUG
self.line.set_data(self.xdata, self.ydata)
self.ax1.set_ylim(min(self.ydata), max(self.ydata))
self.ax1.set_xlim(min(self.xdata), max(self.xdata))
return self.line,
def main():
root = tk.Tk()
app = App(root)
app.pack()
root.mainloop()
if __name__ == '__main__':
main()