Python 无法解释小部件打包和未打包时的行为差异

Python 无法解释小部件打包和未打包时的行为差异,python,tkinter,Python,Tkinter,我正在做一个可视化声音的小应用程序,但控件的行为并不一致。 当我启用(打包)输入字段时,程序将按预期工作。然而,如果我把它们注释掉,情节就不再显示,我只听到声音。真的很困惑 (在Ubuntu 18.04上运行python 3.7.4) 以下工作: import threading import numpy as np import tkinter as tk from tkinter import Label, Button, Entry, TOP, BOTH from matplotlib.b

我正在做一个可视化声音的小应用程序,但控件的行为并不一致。 当我启用(打包)输入字段时,程序将按预期工作。然而,如果我把它们注释掉,情节就不再显示,我只听到声音。真的很困惑

(在Ubuntu 18.04上运行python 3.7.4)

以下工作:

import threading
import numpy as np
import tkinter as tk
from tkinter import Label, Button, Entry, TOP, BOTH
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
from matplotlib import pyplot as plt
from matplotlib.animation import FuncAnimation
import pyaudio

DEFAULT_FREQUENCY = 420  # frequency in Hz
DEFAULT_DURATION = 3.0   # length of sound stream in seconds
VOLUME = 0.1             # must < 1
INTERVAL = 100           # plot interval in millisecond
PACKAGE_LENGTH = 1024    # number of samples in sound package
FS = 2**12               # sampling frequency sound, normal is 44100


class SoundVisualiser:

    def __init__(self, root):
        self.root = root
        self.root.title("Sound Visualiser")

        label = tk.Label(self.root, text="Sound Visualiser")
        label.pack()

        self.fig, self.ax = plt.subplots(figsize=(5, 5))
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.ax.set_xlim(1000 * PACKAGE_LENGTH / FS, 0)

        freq_label = tk.Label(self.root, text='Frequency')
        self.frequency_entry = Entry(self.root)
        self.frequency_entry.insert(0, DEFAULT_FREQUENCY)

        durat_label = tk.Label(self.root, text='Duration')
        self.duration_entry = Entry(self.root)
        self.duration_entry.insert(0, DEFAULT_DURATION)

        freq_label.pack(side='left')
        self.frequency_entry.pack(side='left')
        durat_label.pack(side='left')
        self.duration_entry.pack(side='left')

        self.quit_button = Button(
            self.root, text='Quit', command=self.quit)
        self.quit_button.pack(side='right')

        self.control_button = Button(
            self.root, text='Start')
        self.control_button.bind('<Button-1>', self.start_visualisation)
        self.control_button.pack(side='right')

        self.duration = DEFAULT_DURATION
        self.xdata = np.linspace(0, 1000 * PACKAGE_LENGTH / FS, PACKAGE_LENGTH)

        self.audio = pyaudio.PyAudio()

    def quit(self):
        self.audio.terminate()
        self.root.quit()

    def generate_sound_stream(self):
        self.sound_stream = (
            (0.5 * np.sin(2 * np.pi * 325 / FS *
                    np.arange(FS * self.duration))) +
            (0.1 * np.sin(2 * np.pi * 330 / FS *
                    np.arange(FS * self.duration))) +
            (0.5 * np.sin(2 * np.pi * 340 / FS *
                    np.arange(FS * self.duration))) + 0
        ).astype(np.float32)

        self.ax.set_ylim(1.1 * np.min(self.sound_stream), 1.1 * np.max(self.sound_stream))

    def callback(self, in_data, frame_count, time_info, status):
        out = self.sound_stream[:frame_count]
        self.out_plot = out[:]
        self.sound_stream = self.sound_stream[frame_count:]
        return (out*VOLUME, pyaudio.paContinue)

    def play_sound(self):
        stream = self.audio.open(format=pyaudio.paFloat32,
                                 channels=1,
                                 rate=FS,
                                 output=True,
                                 stream_callback=self.callback)

        stream.start_stream()
        while stream.is_active():
            pass

        stream.stop_stream()
        stream.close()

        self.visualisation = None
        self.control_button.config(text='Start')

    def update_frame(self, frame):
        samples = len(self.out_plot)
        if samples == PACKAGE_LENGTH:
            self.line.set_data(self.xdata, self.out_plot)

        else:
            xdata = np.linspace(0, 1000 * samples / FS, samples)
            self.line.set_data(xdata, self.out_plot)

        return self.line,

    def start_visualisation(self, event):
        self.duration = float(self.duration_entry.get())
        self.generate_sound_stream()

        self.line, = self.ax.plot([], [], lw=3)

        self.control_button.config(text='run')
        duration_range = np.arange(0, self.duration, INTERVAL / 1000)
        self.visualisation = FuncAnimation(self.fig,
                                           self.update_frame,
                                           frames=duration_range,
                                           interval=INTERVAL,
                                           repeat=False)

        # start audio in a seperate thread as otherwise audio and
        # plot will not be at the same time
        self.play_sound_thread = threading.Thread(target=self.play_sound)
        self.play_sound_thread.start()

def main():
    root = tk.Tk()
    sound_visualiser = SoundVisualiser(root)
    root.mainloop()

if __name__ == '__main__':
    main()
导入线程
将numpy作为np导入
将tkinter作为tk导入
从tkinter导入标签、按钮、条目、顶部、两者
从matplotlib.backends.backend_tkagg导入图CAVASTKAGG
从matplotlib.figure导入图形
从matplotlib导入pyplot作为plt
从matplotlib.animation导入FuncAnimation
导入pyaudio
默认频率=420#频率,单位为Hz
默认_持续时间=3.0#音流长度(秒)
体积=0.1#必须小于1
间隔=100#以毫秒为单位的绘图间隔
包装长度=1024#声音包装中的样本数量
FS=2**12#采样频率声音,正常值为44100
类声音可视化器:
定义初始化(自,根):
self.root=根
self.root.title(“声音可视化器”)
label=tk.label(self.root,text=“声音可视化器”)
label.pack()
self.fig,self.ax=plt.子批次(figsize=(5,5))
self.canvas=FigureCanvasTkAgg(self.fig,master=self.root)
self.canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)
self.ax.set\u xlim(1000*封装长度/FS,0)
freq_label=tk.label(self.root,text='Frequency')
self.frequency\u entry=entry(self.root)
self.frequency\u entry.insert(0,默认频率)
durat_label=tk.label(self.root,text='Duration')
self.duration\u entry=条目(self.root)
self.duration\u entry.insert(0,默认\u duration)
频率标签包(侧边为左)
自我频率_entry.pack(side='left')
durat_标签包装(侧边='left')
self.duration\u entry.pack(side='left')
self.quit_按钮=按钮(
self.root,text='Quit',command=self.Quit)
self.quit_按钮.pack(side='right')
self.control_按钮=按钮(
self.root,text='Start')
自我控制按钮绑定(“”,自我启动可视化)
自我控制按钮包(侧/右)
self.duration=默认持续时间
self.xdata=np.linspace(0,1000*包长度/FS,包长度)
self.audio=pyaudio.pyaudio()
def退出(自我):
self.audio.terminate()
self.root.quit()
def生成声音流(自身):
self.sound\u流=(
(0.5*np.sin(2*np.pi*325/FS*
np.arange(FS*自我持续时间)+
(0.1*np.sin(2*np.pi*330/FS*
np.arange(FS*自我持续时间)+
(0.5*np.sin(2*np.pi*340/FS*
np.arange(FS*自我持续时间))+0
).astype(np.32)
self.ax.set_ylim(1.1*np.min(self.sound_流),1.1*np.max(self.sound_流))
def回调(自身、输入数据、帧计数、时间信息、状态):
out=自身声音流[:帧计数]
self.out_plot=out[:]
self.sound\u stream=self.sound\u stream[帧计数:]
返回(out*VOLUME,pyaudio.paccontinue)
def播放声音(自):
stream=self.audio.open(格式=pyaudio.paFloat32,
通道=1,
速率=FS,
输出=真,
stream_callback=self.callback)
stream.start_stream()
当stream.u处于活动状态时()
通过
stream.stop_stream()
stream.close()
自我形象化=无
self.control\u button.config(text='Start')
def更新_帧(自身,帧):
样本=长度(自输出图)
如果样本==包装长度:
self.line.set_数据(self.xdata、self.out_绘图)
其他:
扩展数据=np.linspace(0,1000*个样本/FS,样本)
self.line.set_数据(扩展数据、self.out_绘图)
返回自助线路,
def启动可视化(自身、事件):
self.duration=float(self.duration\u entry.get())
self.generate_sound_stream()
self.line,=self.ax.plot([],[],lw=3)
self.control\u button.config(text='run')
持续时间范围=np.arange(0,自持续时间,间隔/1000)
self.visualization=FuncAnimation(self.fig,
self.update_框架,
帧=持续时间\u范围,
间隔=间隔,
重复(错误)
#在单独的线程中启动音频,否则音频和
#绘图将不会同时进行
self.play\u sound\u thread=threading.thread(target=self.play\u sound)
self.play\u sound\u thread.start()
def main():
root=tk.tk()
声音可视化程序=声音可视化程序(根)
root.mainloop()
如果uuuu name uuuuuu='\uuuuuuu main\uuuuuuu':
main()
注释掉输入字段将停止显示绘图

    def __init__(self, root):
        self.root = root
        self.root.title("Sound Visualiser")

        label = tk.Label(self.root, text="Sound Visualiser")
        label.pack()

        self.fig, self.ax = plt.subplots(figsize=(5, 5))
        self.canvas = FigureCanvasTkAgg(self.fig, master=self.root)
        self.canvas.get_tk_widget().pack(side=TOP, fill=BOTH, expand=1)
        self.ax.set_xlim(1000 * PACKAGE_LENGTH / FS, 0)

        freq_label = tk.Label(self.root, text='Frequency')
        self.frequency_entry = Entry(self.root)
        self.frequency_entry.insert(0, DEFAULT_FREQUENCY)

        durat_label = tk.Label(self.root, text='Duration')
        self.duration_entry = Entry(self.root)
        self.duration_entry.insert(0, DEFAULT_DURATION)

        # freq_label.pack(side='left')
        # self.frequency_entry.pack(side='left')
        # durat_label.pack(side='left')
        # self.duration_entry.pack(side='left')

        self.quit_button = Button(
            self.root, text='Quit', command=self.quit)
        self.quit_button.pack(side='right')

        self.control_button = Button(
            self.root, text='Start')
        self.control_button.bind('<Button-1>', self.start_visualisation)
        self.control_button.pack(side='right')

        self.duration = DEFAULT_DURATION
        self.xdata = np.linspace(0, 1000 * PACKAGE_LENGTH / FS, PACKAGE_LENGTH)

        self.audio = pyaudio.PyAudio()
def\uuuu init\uuuu(self,root):
self.root=根
self.root.title(“声音可视化器”)
label=tk.label(self.root,text=“声音可视化器”)
label.pack()
self.fig,self.ax=plt.子批次(figsize=(5,5))
self.canvas=FigureCanvasTkAgg(self.fig,master=self.root)
self.canvas.get_tk_widget().pack(side=TOP,fill=BOTH,expand=1)
self.ax.set\u xlim(1000*封装长度/FS,0)
freq_label=tk.label(self.root,text='Frequency')
self.frequency\u entry=entry(self.root)
self.frequency\u entry.insert(0,默认频率)
durat_label=tk.label(self.root,text='Duration')
self.duration\u entry=条目(self.root)
self.duration\u entry.insert(0,默认\u duration)
#freq_label.pa