【问题标题】:Tkinter `after` strange behaviourTkinter`after`奇怪的行为
【发布时间】:2019-01-08 13:05:01
【问题描述】:

我正在尝试在我的 PC 上编写吉他调音程序。主要目标是创建一个能够使用麦克风捕获音频、进行一些分析并将结果输出给用户的应用程序,以便他们调整乐器。

我在我的一个函数中遇到了一个奇怪的问题。我试图更改标签两次 - 首先是在函数启动时,然后是 3 秒后。但是,标签仅在等待结束时更新一次(实际上只显示* recording... 文本)。我还注意到,我的整个 GUI 冻结一次(我猜)它开始执行 stateL 标签 after

代码片段(pyAudio部分不用管,还没改):

    def gather_input(self):

        self.stateL.configure(text="Starting recording in 3 sec. Prepare!")
        self.stateL.after(3000, self.stateL.configure(text="* recording..."))


#        p = pyaudio.PyAudio()
#
#        stream = p.open(format=self.FORMAT,
#                channels=self.CHANNELS,
#                rate=self.RATE,
#                input=True,
#                frames_per_buffer=self.CHUNK)
#        
#        frames = []
#
#        for i in range(0, int(self.RATE / self.CHUNK * self.RECORD_SECONDS)):
#            data = stream.read(self.CHUNK)
#            frames.append(data)
#
#        stream.stop_stream()
#        stream.close()
#        p.terminate()
#        
#        self.stateL.configure(text="Done recording!")
#        
#        return frames

我的其他功能中的按钮线:

self.recButton = ttk.Button(self.mainLF, text="Start rec.", command=self.gather_input)

等待 3 秒后,我的目标是跟随该功能,保存声音样本并做一些其他事情(例如,在录音结束时再次更改标签,因为这里是 #)。另外,我什至不确定在after 部分使用self.stateL.configure 是否正确,或者我应该以其他方式这样做。

【问题讨论】:

  • 没有“奇怪”的行为。只需添加一个 lambda 表达式。更改:self.stateL.after(3000, self.stateL.configure(text="* recording..."))self.stateL.after(3000, lambda: self.stateL.configure(text="* recording..."))。使用 after 语句,您需要保存对函数调用的引用或使用 lambda。当到达该行时,您现在拥有的内容将立即执行。
  • 当我现在注释掉self.stateL.configure(text="Done recording!") 时,它最后仍然停留在* recording...。如何在pyAudio事情完成后强制标签显示Done recording!?此外,在进入* recording... 文本之前,它不会在标签中显示Starting recording in 3 sec. Prepare!
  • 我认为您不了解after() 的工作原理。它不像sleep() 那样工作。您的其余代码将立即执行,然后 3 秒后您的 after 语句将执行。 sleep() 会让其他一切等待一段时间,after() 语句会在一段时间后执行一些代码。

标签: python tkinter


【解决方案1】:

要回答您问题中的主要问题,您需要使用 lambda 来解决该特定问题。

变化:

self.after(3000, self.stateL.configure(text="* recording..."))

收件人:

self.after(3000, lambda: self.stateL.configure(text="* recording..."))

要解决您在 cmets 中提到的问题,您可能需要尝试以下方法。

您还需要设置一些方法以使事情按照您希望的方式运行。您还需要将一些变量更改为类属性。

试试这个,如果有帮助,请告诉我。

def gather_input(self):
    self.stateL.configure(text="Starting recording in 3 sec. Prepare!")
    self.after(3000, self.start_recording)

def start_recording(self):
    self.stateL.configure(text="* recording...")
    self.p = pyaudio.PyAudio()

    self.stream = self.p.open(format=self.FORMAT,
                              channels=self.CHANNELS,
                              rate=self.RATE,
                              input=True,
                              frames_per_buffer=self.CHUNK)

    self.after(3000, self.stop_recording)

def stop_recording(self):
    self.frames = []

    for i in range(0, int(self.RATE / self.CHUNK * self.RECORD_SECONDS)):
        data = self.stream.read(self.CHUNK)
        self.frames.append(data)

    self.stream.stop_stream()
    self.stream.close()
    self.p.terminate()

    self.stateL.configure(text="Done recording!")

【讨论】:

    猜你喜欢
    • 2017-01-04
    • 1970-01-01
    • 2020-08-29
    • 1970-01-01
    • 1970-01-01
    • 2020-09-14
    • 1970-01-01
    • 1970-01-01
    • 2015-02-09
    相关资源
    最近更新 更多