-1

How can I make the play button work as many times as possible but also being able to use the rest of the GUI and not having it freeze up.

I'd like to be able to use the play button more than once but it keeps saying

TypeError: can't pickle _tkinter.tkapp objects

and when I use threads it will say runTime Error:

Threads can only be started once

from tkinter import *
from tkinter import filedialog
import os
import winsound
import threading
import time
import multiprocessing

audio_list = []

class Main(Frame):

    def __init__(self, master):
        Frame.__init__(self, master, bg="white")
        self.audio_dictionary=audio_list
        self.gui()
        self.refresh()
        Thread_1 = multiprocessing.Process(target=self.gui, args=(self,))
        Thread_1.start()

    def gui(self):
        self.Thread_2 = multiprocessing.Process(target=self.play, args=(self,))
        self.play_button= Button(text='Play', command=self.play)
        self.play_button.grid(column=0, row=1, sticky='W')

        stop_button= Button(text="Stop", command=self.stop)
        stop_button.grid(row=1, column=0, columnspan=2, sticky='E')

        self.display_songs = Listbox(bd=5, relief=GROOVE)
        self.display_songs.grid(row=0, column=0, columnspan=2)

        import_button = Button(text="Import", command=self.import_files)
        import_button.grid(row=1, column=2, sticky='E')

        self.status_window = Listbox(bd=5, relief=GROOVE)
        self.status_window.grid(row=0, column=2)


    def import_files(self):
        self.selected_songs=filedialog.askopenfilenames(filetypes = [("wav file", "*")], title='Select wav files')
        counter=0
        for y in self.selected_songs:
            x=os.path.basename(y)
            self.audio_dictionary.append((x,y))
            print(x)
            self.display_songs.insert(counter, x)
            counter+=1
        for p in self.audio_dictionary:
            print(p)

    def play(self):
        if self.Thread_2.is_alive() is True:
            selection = self.display_songs.curselection()

            for item in selection:
                song=self.display_songs.get(item)

            for c in self.audio_dictionary:
                s=c[0]
            if song==s:
               direct=c[1]
            else:
                pass

            print(direct)
            winsound.PlaySound(direct, winsound.SND_FILENAME)
        else:
            pass

    def refresh(self):
        window.update()
        window.after(100, self.refresh)

    def stop(self):
        print("Stopped Music")
        winsound.PlaySound(None, winsound.SND_FILENAME)


window = Tk()
app = Main(window)
window.mainloop()
toti08
  • 2,448
  • 5
  • 24
  • 36
  • Could you post the complete traceback related to the posted code? – toti08 Nov 13 '18 at 08:50
  • However I think you should link your button to the Thread, and not to the function itself. I mean, you want the button to start the Thread...Also I don't see where you start Thread2. – toti08 Nov 13 '18 at 09:28
  • Possible duplicate of [Tkinter: How to use threads to preventing main event loop from "freezing"](https://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing) – stovfl Nov 13 '18 at 09:35

1 Answers1

0

You should avoid using threads. Specifically don't make calls to Tkinter GUI methods from worker threads. But in this example you don't need any threads as the winsound function supports playing sounds asynchronously for you already:

winsound.PlaySound(filename, winsound.SND_FILENAME | winsound.SND_ASYNC)

As documented, if you want to stop the currently playing sound then pass None as the first argument.

patthoyts
  • 32,320
  • 3
  • 62
  • 93
  • THank you so miuch, i just found it tough doing this kind of stuff as it's my first real project/program. thank you – TazzyBoy_ Nov 14 '18 at 06:36