我在Python 3中使用Tkinter编写了一些代码,这些代码在画布上绘制图形。我还做到了这样,当我将鼠标移到画布上时,图形就会向左滚动。
问题是,例如,当我按下空格键时,我希望图形滚动。但是我不希望每次按空格键时都滚动1步,但是我希望它在按一次时无限期地开始滚动,而在再次按时停止其滚动。我希望空格键是播放/暂停键。
我该如何完成?我不想在任何地方使用matplotlib。
现在就输入我的密码:
from tkinter import *
import numpy as np
# The function of the graph
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
# Data for the graph and steps to move to the right
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
# A switch to delete to clear the canvas each iteration before plotting the next frame
self.gate = False
# Setting the Tkinter window and the canvas in place
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws*0.75
hw = self.hs*0.50
self.canvas = Canvas(self.master, width = ww, height = hw, bg = 'black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
# Plot first frame
self.drawData(self.data_x, self.data_y)
# Plot next frames each time I press the space bar
self.canvas.bind('<KeyPress-space>', self.updateData)
def drawData(self, data_x, data_y):
'''This is my function to plot a grpah in a canvas
canvas without embedding any matplotlib figure'''
# Setting the axis limits
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
# Translating data to pixel positions inside the canvas
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
# Deleting previous frame before plotting the next frame (except for the first frame)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
# Plotting
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def updateData(self, event):
# Changing data for the next frame
self.data_x += self.step
self.data_y = f(self.data_x)
# Plot new frame
self.drawData(self.data_x, self.data_y)
root = Tk()
GraphPlot(root)
root.mainloop()
我尝试了一些想法。例如,我使用了一个新函数PlayPause()
,它带有一个while循环和一个新的开关self.go
,但这并没有按预期工作。
我期望工作的代码却没有:
from tkinter import *
import numpy as np
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
self.go = False # The new switch
self.gate = False
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws*0.75
hw = self.hs*0.50
self.canvas = Canvas(self.master, width = ww, height = hw, bg = 'black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
self.drawData(self.data_x, self.data_y)
self.canvas.bind('<KeyPress-space>', self.PlayPause)
def drawData(self, data_x, data_y):
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def updateData(self):
self.data_x += self.step
self.data_y = f(self.data_x)
self.drawData(self.data_x, self.data_y)
def PlayPause(self, event):
if self.go:
self.go = False
else:
self.go = True
while self.go:
self.updateData()
root = Tk()
GraphPlot(root)
root.mainloop()
答案 0 :(得分:1)
您可以向toggle_play_pause
添加一个方法,并将空格键绑定到该方法。按下空格键时,此方法会切换布尔标志pause
,该标志在关闭时将允许调用update
。
update
将继续每10/1000秒调用一次,直到再次按下空格键并将pause
标志设置为True。
import tkinter as tk
import numpy as np
def f(x):
return np.sin(x)+np.sin(3*x-1)+np.sin(0.5*(x+np.pi))+0.3*np.sin(10*x)
class GraphPlot():
def __init__(self, master):
self.master = master
# Data for the graph and steps to move to the right
self.data_x = np.linspace(0, 4*np.pi, 1000)
self.data_y = f(self.data_x)
self.step = 0.1
# A switch to delete to clear the canvas each iteration before plotting the next frame
self.gate = False
# Setting the Tkinter window and the canvas in place
self.ws = master.winfo_screenwidth()
self.hs = master.winfo_screenheight()
ww = self.ws * 0.75
hw = self.hs * 0.50
self.canvas = tk.Canvas(self.master, width=ww, height=hw, bg='black')
self.canvas.grid()
self.master.update()
self.w = self.canvas.winfo_width()
self.h = self.canvas.winfo_height()
self.canvas.focus_set()
# Plot first frame
self.drawData(self.data_x, self.data_y)
# Plot next frames each time I press the space bar
self.canvas.bind('<KeyPress-space>', self.toggle_play_pause)
self.pause = True
self._update_call_handle = None
def drawData(self, data_x, data_y):
'''This is my function to plot a grpah in a canvas
canvas without embedding any matplotlib figure'''
# Setting the axis limits
x_min, x_max = min(data_x), max(data_x)
y_min, y_max = min(data_y), max(data_y)
# Translating data to pixel positions inside the canvas
pixel_x = (data_x-x_min)*self.w/(x_max-x_min)
pixel_y = -(data_y-y_max)*self.h/(y_max-y_min)
points = []
for i in range(len(data_x)):
points.append(pixel_x[i])
points.append(pixel_y[i])
points = tuple(points)
# Deleting previous frame before plotting the next frame (except for the first frame)
if self.gate:
self.canvas.delete('curve')
else:
self.gate = True
# Plotting
self.canvas.create_line(points, fill = 'white', tag = 'curve')
def toggle_play_pause(self, dummy_event):
self.pause = not self.pause
if not self.pause:
self.updateData()
def updateData(self):
# Changing data for the next frame
self.data_x += self.step
self.data_y = f(self.data_x)
# Plot new frame
self.drawData(self.data_x, self.data_y)
if not self.pause:
self._update_call_handle = root.after(10, self.updateData)
else:
root.after_cancel(self._update_call_handle)
self._update_call_handle = None
root = tk.Tk()
GraphPlot(root)
root.mainloop()