Making the piano keyboard

Let's now build the piano keyboard. All keys on the keyboard will be made using the Label widget. We will superimpose the label widget with an image of black and white keys using Tkinter's PhotoImage class.

The PhotoImage class is used to display images in label, text, button, and canvas widgets. We used it in Chapter 2, Making a Text Editor to add icons to buttons.  Since this class can only handle .gif or .bpm format images, we add four .gif images to a folder named pictures. These four images are black_key.gif, white_key.gif,  black_key_pressed.gif, and white_key_pressed.gif.

Since we will refer to these images over and over again,  we add their reference to 7.02 constants.py

WHITE_KEY_IMAGE = '../pictures/white_key.gif'
WHITE_KEY_PRESSED_IMAGE = '../pictures/white_key_pressed.gif'
BLACK_KEY_IMAGE = '../pictures/black_key.gif'
BLACK_KEY_PRESSED_IMAGE = '../pictures/black_key_pressed.gif'
The symbol ../  used previously is a way to specify a file path relative to the current working directory. A single ../ means—go back one directory, a set of two ../../ means go back two directories, and so on.  This system is generally honored by most modern operating systems. However, some very old operating systems might not support it. So a better but a more verbose way is to use the os module of Python to traverse directories.

Next, we will define a method named create_key that creates a piano key for us at a given x location:

 def create_key(self, img, key_name, x_coordinate):
key_image = PhotoImage(file=img)
label = Label(self.keyboard_frame, image=key_image, border=0)
label.image = key_image
label.place(x=x_coordinate, y=0)
label.name = key_name
label.bind('<Button-1>', self.on_key_pressed)
label.bind('<ButtonRelease-1>', self.on_key_released)
self.keys.append(label)
return label

Here's a brief code description:

  • Note that since we want to place keys at a specific x coordinate we use the place geometry manager.  We briefly touched upon the place geometry manager in Chapter 1, Meet Tkinter. Now is a good place to see this rarely used geometry in action.
  • This method also takes an image location as its input and creates a PhotoImage class, which is then attached to the label widget using the image=key_image option in the previous example. 
  • A third parameter, key_nameis attached to the created label widget by using the command widget.name = key_name. This is needed to later identify which particular key was pressed. For example, to create the first key C1, we attach the name C1 to the label widget and then later this string value can be accessed by calling widget.name
  • We bind the label to two events, '<Button-1>' and '<ButtonRelease-1>', to handle mouse press events.
  • Finally, we add a reference to the newly created widget into an attribute newly defined here as self.keys. We keep this reference as we will need to change the image of these widgets to highlight the keys.

Now that we have attached events to two callbacks, let's define them next:

def on_key_pressed(self, event):
print(event.widget.name + ' pressed')
self.change_image_to_pressed(event)

def on_key_released(self, event):
print(event.widget.name + ' released' )
self.change_image_to_unpressed(event)

For now, the previous methods print the name of the key pressed and then call another two methods that change the image of the pressed label to a different colored image on button press and release:

def change_image_to_pressed(self, event):
if len(event.widget.name) == 2:
img = WHITE_KEY_PRESSED_IMAGE
elif len(event.widget.name) == 3:
img = BLACK_KEY_PRESSED_IMAGE
key_img = PhotoImage(file=img)
event.widget.configure(image=key_img)
event.widget.image = key_img

def change_image_to_unpressed(self, event):
if len(event.widget.name) == 2:
img = WHITE_KEY_IMAGE
elif len(event.widget.name) == 3:
img = BLACK_KEY_IMAGE
key_img = PhotoImage(file=img)
event.widget.configure(image=key_img)
event.widget.image = key_img

The white key widget will have a name of length 2 (for example, C1, D2, G1), while a black key will have an image length of 3 (for example, C#1, D#1). We utilize this fact to decide if to use a black key image or a white key image. The rest of the preceding code should be self-explanatory.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.141.31.125