python - 为什么 Python Tkinter Canvas 绘制会导致冻结?
问题描述
我写了一段代码,其中有一个带有画布的简单 gui。在这个画布上我画了一个matplot。matplot 每秒更新一次,其中的数据来自我在 SQLite DB 中创建的假传感器数据(目前仅用于测试)。
我的问题是画布的重绘导致我的窗口/gui每秒都滞后。
我什至试图在另一个线程中更新情节。但即使在那里我也有滞后。
这里没有线程的想法:
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import tkinter as tk
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import sqlite3
from datetime import datetime
from random import randint
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
root.update_idletasks()
f = Figure(figsize=(5,5), dpi=100)
x=1
ax = f.add_subplot(111)
line = ax.plot(x, np.sin(x))
def animate(i):
# Open Database
conn = sqlite3.connect('Sensor_Data.db')
c = conn.cursor()
# Create some fake Sensor Data
NowIs = datetime.now()
Temperature = randint(0, 100)
Humidity = randint(0, 100)
# Add Data to the Database
c = conn.cursor()
# Insert a row of data
c.execute("insert into Sensor_Stream_1 (Date, Temperature, Humidity) values (?, ?, ?)",
(NowIs, Temperature, Humidity))
# Save (commit) the changes
conn.commit()
# Select Data from the Database
c.execute("SELECT Temperature FROM Sensor_Stream_1 LIMIT 10 OFFSET (SELECT COUNT(*) FROM Sensor_Stream_1)-10")
# Gives a list of all temperature values
x = 1
Temperatures = []
for record in c.fetchall():
Temperatures.append(str(x)+','+str(record[0]))
x+=1
# Setting up the Plot with X and Y Values
xList = []
yList = []
for eachLine in Temperatures:
if len(eachLine) > 1:
x, y = eachLine.split(',')
xList.append(int(x))
yList.append(int(y))
ax.clear()
ax.plot(xList, yList)
ax.set_ylim(0,100)
ax.set_xlim(1,10)
ax.grid(b=None, which='major', axis='both', **kwargs)
label = tk.Label(root,text="Temperature / Humidity").pack(side="top", fill="both", expand=True)
canvas = FigureCanvasTkAgg(f, master=root)
canvas.get_tk_widget().pack(side="left", fill="both", expand=True)
root.ani = animation.FuncAnimation(f, animate, interval=1000)
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.mainloop()
在这里我尝试另一个线程:
import tkinter as tk
from tkinter import messagebox
import numpy as np
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import sqlite3
from datetime import datetime
from random import randint
#
from concurrent import futures
from time import sleep, time
#
class MainApplication(tk.Frame):
def __init__(self, parent, *args, **kwargs):
tk.Frame.__init__(self, parent, *args, **kwargs)
self.parent = parent
root.geometry('1280x720')
root.update_idletasks()
#GUI
x = 1
f = Figure(figsize=(5,5), dpi=100)
ax = f.add_subplot(111)
line = ax.plot(x, np.sin(x))
label = tk.Label(root,text="Temperature / Humidity").pack(side="top", fill="both", expand=True)
canvas = FigureCanvasTkAgg(f, master=root)
canvas.get_tk_widget().pack(side="left", fill="both", expand=True)
def animate(i):
print("hello")
# Open Database
conn = sqlite3.connect('Sensor_Data.db')
c = conn.cursor()
# Create some fake Sensor Data
NowIs = datetime.now()
Temperature = randint(0, 100)
Humidity = randint(0, 100)
# Add Data to the Database
c = conn.cursor()
# Insert a row of data
c.execute("insert into Sensor_Stream_1 (Date, Temperature, Humidity) values (?, ?, ?)",
(NowIs, Temperature, Humidity))
# Save (commit) the changes
conn.commit()
# Select Data from the Database
c.execute("SELECT Temperature FROM Sensor_Stream_1 LIMIT 10 OFFSET (SELECT COUNT(*) FROM Sensor_Stream_1)-10")
# Gives a list of all temperature values
x = 1
Temperatures = []
for record in c.fetchall():
Temperatures.append(str(x)+','+str(record[0]))
x+=1
#
# Setting up the Plot with X and Y Values
xList = []
yList = []
for eachLine in Temperatures:
if len(eachLine) > 1:
x, y = eachLine.split(',')
xList.append(int(x))
yList.append(int(y))
ax.clear()
ax.plot(xList, yList)
ax.set_ylim(0,100)
ax.set_xlim(1,10)
ax.grid(b=None, which='major', axis='both', **kwargs)
canvas.draw()
root.after(1000, animate, 1000)
e = futures.ThreadPoolExecutor(max_workers=1)
e.submit(animate, 1000)
def on_closing():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
root.destroy()
if __name__ == "__main__":
root = tk.Tk()
MainApplication(root).pack(side="top", fill="both", expand=True)
root.protocol("WM_DELETE_WINDOW", on_closing)
root.mainloop()
解决方案
推荐阅读
- vbscript - VBScript 仅将空 (265K) PST 从网络文件夹复制到网络文件夹
- c# - 由于 ModalPopupExtender 和 ASP:Panel,LinkButton On_Command 事件无法正常工作
- keras - 用于分析长一维序列的卷积自动编码器
- neo4j - Neo4J Desktop 1.1.8 安装错误(社区版)
- mysql - 在 MySQL 中使用 Group by 和 Order by
- android - Android:ACCESS_COARSE_LOCATION 权限来源
- java - JAVA SWING:默认表模型中使用的向量无法通过 for 循环添加 addElement()
- python - 使用 tf.while_loop 对张量进行切片
- innodb - 如何克服 Google-Cloud MySQL5.7 第二代上的 Row size too large (> 8126) 错误
- python - 我可以使用 sublime Text 构建系统在 docker 容器中执行 manage.py 命令吗?