简体   繁体   中英

How to use python threading which needs user defined function that requires input using tkinter button value?

I am trying to make a model of piano with actual piano sounds and Tkinter GUI interface, but I am not able to use threading to use a particular function that requires input from the user.

When I tried to initiate threading in the init () method of the piano class it asks for 1 positional argument which I want to pass after the user inputs through Tkinter button, but cannot write the threading function in the proper way. Kindly provide me a solution, that would be a great help.

I am linking my code and screenshot along with this for reference.

# importing necessary libraries
from tkinter import *
import playsound
import threading
import os

# folder path declaration
folder_path = r'E:\\Programming\\python_practice\\music_notes'

# Music note declaration
noteList = [] # empty list to store music notes as list elements

def listDir(dir): # get notes from the path and put into the list
    fileNames = os.listdir(dir)
    for fileName in fileNames:
        noteList.append(fileName)

listDir(folder_path)

# Creating the temporary tkinter windows which will later be replaced with RbPi button interface
root = Tk()
root.title("Python Piano")

# Creating empty file-list
files =[]

# Adding note to empty file-list
for i in range(len(noteList)):
    files.append(str(i))

# Creating empty button-list
btns = []

# Creating Piano Class
class Piano:
    
    def __init__(self,master):

        # Declaring frame an creating a Frame 
        global myFrame

        myFrame = Frame(master)
        myFrame.pack()

        # Creating a thread for asynchronous playing of same or individual notes
        # -------- C O D E ---------
                
    # Create Buttons and assing individual notes to each button
    def buttonGenerator(self):
        for i in range(len(files)):
            btns.append(Button(myFrame, text=files[i], padx=20, pady=60, command = lambda t = i:self.playNotes(t)))
            btns[i].grid(column=[i], row=0)

    # Play notes of each button
    def playNotes(self,note):
        playsound.playsound(folder_path + "\\" + noteList[note])

# Creating an instance of Piano class
myPiano = Piano(root)
# Calling inner method of the Piano class
myPiano.buttonGenerator()

# Looping through the program
root.mainloop()

Screenshot

Here's the basic concept. I haven't tested this, because I don't have your sounds, but I made several changes.

  1. I made the Piano class a subclass of the Tkinter Frame. That makes things a bit cleaner, and eliminates the need for the ugly globals you were using.
  2. I create a queue in the constructor, then launch a thread.
  3. The thread is in an infinite loop, pulling tasks from the queue. Note that you can force the thread to exit by sending it the string "exit".
  4. The button press just pushes a note onto the queue.

Eventually, you will not want to play sound files to do this. That's too slow. You will probably want to use MIDI to send notes to your system's synthesizer.

# importing necessary libraries
import os
from tkinter import *
import playsound
import threading
import queue

# folder path declaration
folder_path = r'E:\\Programming\\python_practice\\music_notes'

# Music note declaration

def listDir(dir): # get notes from the path and put into the list
    return os.listdir(dir)

noteList = listDir(folder_path)

# Creating the temporary tkinter windows which will later be replaced with RbPi button interface

root = Tk()
root.title("Python Piano")

# Creating Piano Class
class Piano(Frame):
    def __init__(self,master):
        super().__init__(master)
        self.pack()
        self.queue = queue.Queue()
        self.btns = []

        # Creating a thread for asynchronous playing of same or individual notes
        # -------- C O D E ---------
        threading.Thread( target = self.playNotes ).start()
                
    # Create Buttons and assing individual notes to each button
    def buttonGenerator(self):
        for i in range(len(files)):
            self.btns.append(Button(self, text=str(i), padx=20, pady=60, command = lambda t = i:self.playNote(t)))
            self.btns[-1].grid(column=[i], row=0)

    def playNote(self,n):
        self.queue.put( n )

    # Play notes of each button
    def playNotes(self):
        while True:
            item = self.queue.get()
            if item == 'exit':
                return
            playsound.playsound(folder_path + "\\" + noteList[item])

# Creating an instance of Piano class
myPiano = Piano(root)
# Calling inner method of the Piano class
myPiano.buttonGenerator()

# Looping through the program
root.mainloop()

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM