Program structure and broadview skeleton

Our first goal is to build the broad modular structure for the program. As usual, we will keep the data structure, audio-related logic, and the presentation logic in three separate files. Therefore, we will create three separate files named model.pyplayer.py, and view.py (see code 5.01).

Let's create an empty Model class and an empty Player class in their respective files. The following is the code for 5.01model.py:

class Model:
def __init__(self):
pass

Here's the code for 5.01player.py:

import pyglet
class Player():
def __init__(self):
pass

Next, let's create the View class. We will leave the Model and Player classes empty for now. However, we will complete this iteration by coding the majority of the view elements for the player.

Let's begin by importing the required modules in the View class, as follows:

import tkinter as tk
import tkinter.filedialog
import tkinter.messagebox
import tkinter.ttk

Also, import the blank Model and Player classes in the View namespace (see code 5.01view.py):

import model
import player

However, since we do not want to mix the logic with its representation, we do not import View in the Model class. In short, the Model class knows nothing about how its data will be presented to the frontend user.

Note that we are not using the Controller class in this program. We saw how to use controllers in Chapter 4, Game of Chess. While controllers are a great way to avoid direct coupling between the Model and View classes, they can be an overkill for small programs like this one.

Now, let's create the top-level window. Also, we'll create instances of the Model and Player classes and pass them as arguments to the View class, as follows (see code 5.01view.py):

if __name__ == '__main__':
root = Tk()
root.resizable(width=False, height=False)
player = player.Player()
model = model.Model()
app = View(root, model, player)
root.mainloop()

Now that the boilerplate code is written, let's start coding the actual View class, as follows (see code 5.01view.py):

 class View:
def __init__(self,root, model, player):
self.root = root
self.model = model
self.player = player
self.create_gui()

def create_gui(self):
self.root.title(AUDIO_PLAYER_NAME)
self.create_top_display()
self.create_button_frame()
self.create_list_box()
self.create_bottom_frame()
self.create_context_menu()

The __init__ method should look familiar to you by now. The final line of the __init__ calls a method called create_gui, which is responsible for the creation of the entire GUI. The create_gui method in turn simply calls five different methods, where each method is responsible for the creation of different sections of the GUI.

We also made the root window nonresizable by adding root.resizable(width=False, height=False) to the code.

We will not reproduce the entire code that creates the GUI, since we have coded similar widgets in the past. But all of these five methods, when combined, create the GUI shown in the following screenshot:

For the sake of separation, we have also marked the four sections differently in the preceding screenshot. The fifth method creates the right-click context menu and is not visible here.

The code used to create all of these GUI elements should be familiar to you by now. However, note a few things about the code (see code 5.01view.py):

  • All the images used in the preceding code have been stored in a separate folder named icons.
  • We have used the grid geometry manager to place all the elements on the top-level window.
  • The Top Display section creates a Canvas widget and places an overlay image using the canvas.create_image() method. The currently playing text and the timer displayed in the top display have been created by using the canvas.create_text() method. The coordinates used to place these elements have been decided on a trial-and-error basis. As a reminder, the canvas coordinates are measured from the top-left corner.
  • The Button Frame section simply creates buttons and uses images instead of text, using the following code:
    button=tk.Button(parent, image=previous_track_icon)
  • The Button Frame section also uses a ttk Scale widget, which can be used as a volume slider. This has been created by using the following code:
    self.volume_scale = tkinter.ttk.Scale(frame, from_=0.0, to=1.0, command=self.on_volume_scale_changed)
  • The from and to values for the Scale widget have been chosen as 0.0 and 1.0 because these are the numbers that the pyglet library uses to denote the minimum and maximum volume, which will be seen in the following section.
  • The Listbox section creates a playlist by using the Tkinter Listbox widget, which uses the following code:
    self.list_box = tk.Listbox(frame, activestyle='none', cursor='hand2', bg='#1C3D7D', fg='#A0B9E9', selectmode=tk.EXTENDED, height=10)
  • The select mode=EXTENDED option in the preceding code means that this list box will allow multiple list items to be selected at once. If this line is omitted, the default behavior of the Listbox widget is to allow only a single selection at a time.
  • The activestyle='none' option means that we do not want to underline the selected item.
  • The Listbox section is attached to the Scrollbar widget, which is similar to what we have done in the earlier chapters.
  • The Bottom Frame section adds a few image buttons as we did earlier. It also creates three Radiobutton widgets using a for loop.
  • Finally, note that we have completely skipped the creation of the seek bar, as it is a custom widget that is not natively defined in Tkinter. This is something that we will create in a dedicated section of its own.
The Listbox widget offers the following four selection modes via the selectmode option:
  • SINGLE: This allows only a single row to be selected at a time
  • BROWSE (the default mode): This is similar to SINGLE, but it allows you to move a selection by dragging the mouse
  • MULTIPLE: This allows for multiple selections by clicking on items one at a time
  • EXTENDED: This allows for the selection of a multiple range of items using the Shift and Ctrl keys

In addition to creating all of these widgets, we have also added a command callback to most of these widgets. These command callbacks currently point to the following empty, nonfunctional methods (see code 5.01view.py):

 on_previous_track_button_clicked()
on_rewind_button_clicked()
on_play_stop_button_clicked()
on_pause_unpause_button_clicked()
on_mute_unmute_button_clicked()
on_fast_forward_button_clicked()
on_next_track_button_clicked()
on_volume_scale_changed(, value)
on_add_file_button_clicked()
on_remove_selected_button_clicked()
on_add_directory_button_clicked()
on_empty_play_list_button_clicked()
on_remove_selected_context_menu_clicked()
on_play_list_double_clicked(event=None)

None of these methods are functional now. We will end the iteration here, as there are a few other things that we need to do before we can think of making the widgets functional.

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

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