我想要一个"开始按钮"开始将数据收集到图表中。无论是否存在空白图表,都需要在GUI中。
此代码给我一个错误
(_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack)
。
当我没有按钮和单独的" def事件"时,它会运行并创建两个窗口。
我尝试的其他代码在按下按钮时在单独的窗口中创建图形。我是否遗漏了一些相当简单的东西,使图表自动进入GUI而不是单独的窗口?
from tkinter import * #import everything from tkinter
import tkinter as tk
from PIL import ImageTk, Image
import time
import serial
import matplotlib.animation as animation
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import time
import numpy as np
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
root = Tk()
root.configure(background='gray26')
topFrame = tk.Frame(root) #insvisible rectangle that you can put stuff in (widgets). This goes in the main window (root)
topFrame.pack() #pack actually displays it in the window
middleFrame = Frame(root)
middleFrame.pack()
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.stopbits = 2
def event():
def animate(i):
f = open('serial.txt', 'w+')
data=ser.readline()
print(data, file = f)
f.close()
lines = open('serial.txt', 'r+')
read_serial=lines.readline()
mylist = [int(x) for x in read_serial.split(',') if x.strip().isdigit()]
x = np.linspace(340, 850, num=len(mylist))
ax1.clear()
ax1.plot(x, mylist)
plt.ylim([0, 1000])
canvas = FigureCanvasTkAgg(fig, master=root)
canvas.get_tk_widget().grid(column=0, row=1)
ani = animation.FuncAnimation(fig, animate)
plt.show()
startbutton = Button(middleFrame, text="Start Graph", command=event)
startbutton.pack()
bottomFrame = Frame(root)
bottomFrame.pack()
time1 = ' '
clock = Label(topFrame, font=('times', 20, 'bold'), fg = 'snow', bg='gray26')
clock.pack(side="left")
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
if time2 != time1:
time1 = time2
clock.config(text=time2)
clock.after(200,tick)
tick()
root.mainloop()
以下是单击按钮运行的代码!
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from PIL import ImageTk, Image
import time
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
import numpy as np
import random
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=1)
ser.stopbits = 2
def get_data():
while True:
f = open('serial.txt', 'w+')
data=ser.readline()
print(data, file = f)
f.close()
lines = open('serial.txt', 'r+')
read_serial=lines.readline()
mylist = [int(x) for x in read_serial.split(',') if x.strip().isdigit()]
x = np.linspace(340, 850, num=len(mylist))
ax1.clear()
ax1.plot(x, mylist)
plt.ylim([0, 1000])
return x, mylist
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="Number of times to run")
lbl.pack(side=tk.LEFT)
self.points_ent = tk.Entry(btns, width=5)
self.points_ent.insert(0, '50')
self.points_ent.pack(side=tk.LEFT)
lbl = tk.Label(btns, text="update interval (ms)")
lbl.pack(side=tk.LEFT)
self.interval = tk.Entry(btns, width=5)
self.interval.insert(0, '100')
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,1000)
self.ax1.set_xlim(340,850)
def on_click(self):
if self.ani is None:
return self.start()
if self.running:
self.ani.event_source.stop()
self.btn.config(text='Un-Pause')
else:
self.ani.event_source.start()
self.btn.config(text='Pause')
self.running = not self.running
def start(self):
self.points = int(self.points_ent.get()) + 1
self.ani = animation.FuncAnimation(
self.fig,
self.update_graph,
frames=self.points,
interval=int(self.interval.get()),
repeat=False)
self.running = True
self.btn.config(text='Pause')
self.ani._start()
print('started animation')
def update_graph(self, i):
self.line.set_data(*get_data()) # update graph
if i >= self.points - 1:
self.btn.config(text='Start')
self.running = False
self.ani = None
return self.line,
def main():
root = tk.Tk()
app = App(root)
app.pack()
root.mainloop()
if __name__ == '__main__':
main()
答案 0 :(得分:1)
这是我之前处理过的棘手问题。这是一个模板,其中包含一些未记录的功能,可帮助您入门。
try:
import Tkinter as tk
except ImportError:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
import matplotlib.animation as animation
import random
def get_data():
'''replace this function with whatever you want to provide the data
for now, we just return soem random data'''
rand_x = list(range(100))
rand_y = [random.randrange(100) for _ in range(100)]
return rand_x, rand_y
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="Number of times to run")
lbl.pack(side=tk.LEFT)
self.points_ent = tk.Entry(btns, width=5)
self.points_ent.insert(0, '50')
self.points_ent.pack(side=tk.LEFT)
lbl = tk.Label(btns, text="update interval (ms)")
lbl.pack(side=tk.LEFT)
self.interval = tk.Entry(btns, width=5)
self.interval.insert(0, '100')
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,100)
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.points = int(self.points_ent.get()) + 1
self.ani = animation.FuncAnimation(
self.fig,
self.update_graph,
frames=self.points,
interval=int(self.interval.get()),
repeat=False)
self.running = True
self.btn.config(text='Pause')
self.ani._start()
print('started animation')
def update_graph(self, i):
self.line.set_data(*get_data()) # update graph
if i >= self.points - 1:
# code to limit the number of run times; could be left out
self.btn.config(text='Start')
self.running = False
self.ani = None
return self.line,
def main():
root = tk.Tk()
app = App(root)
app.pack()
root.mainloop()
if __name__ == '__main__':
main()