Adding the top display console

In this iteration, we will add a display console at the top of our player. This console will display the time counter for our music player. It will also display the currently played track.

We will also code a progress bar, which will show the progress of the current track being played.

At the end of this iteration, the top frame of our player will look like the following screenshot:

Adding the top display console

Prepare for Lift Off

We need to precisely place our timer clock text and the currently playing track text on the top of an image.

Recall that the Canvas widget allows for a deep nested placement of other widgets inside it with precise coordinate-based control. This is all that we want to display the console. We will, therefore, use the Canvas widget as the container for our console.

Engage Thrusters

Step 1 – creating the top console and progress bar

We accordingly define a new method named create_console_frame in our GUI class, which holds our image, clock text, and currently playing text for creating the top console and progress bar as follows(see code 5.04 GUI.py):

def create_console_frame(self):
   consoleframe = Frame(self.root)
   self.canvas = Canvas(consoleframe, width=370, height=90)
   self.canvas.grid(row=1)
   photo = PhotoImage(file='../icons/glassframe.gif')
   self.canvas.image = photo
   self.console = self.canvas.create_image(0, 10, anchor=NW, image=photo)
   self.clock = self.canvas.create_text(32, 34, anchor=W, fill='#CBE4F6', font="DS-Digital 20", text="00:00")
   self.songname = self.canvas.create_text(115, 37, anchor=W, fill='#9CEDAC', font="Verdana 10", text='"Currently playing: none [00.00] "')
   self.progressBar = ttk.Progressbar(consoleframe, length =1, mode="determinate")
   self.progressBar.grid(row=2, columnspan=10, sticky='ew', padx=5)
   consoleframe.grid(row=1, pady=1, padx=0)

The description of the code is listed as follows:

  • The code defines a new frame, consoleframe, and adds a Canvas widget of desired height and width to the frame.
  • We use canvas.create_image to add the background image. The background image is provided in the icons folder.
  • We use canvas.create_text to add one text for displaying the clock and another text to display the currently playing track. The desired location of each of these texts is specified using x, y coordinates.
  • We also specify a special font for displaying our clock. If this font is installed on a computer, the text is displayed in the specified font. If the font is not installed, display occurs in the default font.
  • Finally, we display a ttkProgressbar widget, which shall be used to display the progress of track as it plays. We use the determinate mode of the progress bar, because we want to display the completion of track relative to its overall length. For now, the overall length of track is initialized to 1. It will be updated as the song starts to play.

Note

A ttkProgressbar widget displays the status of progress of an operation. The progress bar can run in two modes:

Determinate: This mode shows the amount of work completed relative to the total amount of work.

Indeterminate: This provides an animated show of the progress, but does not show the relative amount of work completed.

Step 2 – getting the total duration of a track

The contents of the display panel and the progress on the progress bar need to be updated every time a new song starts playing. In our current code, a new song starts playing when a user clicks on the Play button or double-clicks on a particular track, or when the Next or Previous button is clicked.

Before we update the clock or the progress bar, we need to know two things:

  • Total length of current track
  • Duration for which a current track has been played

Fortunately, pyglet provides API calls to determine both these things. As per its documentation, the total length of a song currently playing can be obtained from the code: source.duration.

Similarly, the current duration of play can be obtained using myplayer.time.

Let's, therefore, define two new methods in our Player class to get the value of these two variables, as follows (code 5.04player.py):

def song_len(self):
   try:
     self.song_length = self.source.duration
   except:
     self.song_length = 0
   return self.song_length
def current_time(self):
   try:
     current_time = self.myplayer.time
   except:
     current_time = 0
   return current_time

Now, we slightly modify our start_play_thread method to call our song_len method so that our song_length attribute is updated with the value of the song length.

def start_play_thread(self):
   player_thread = Thread(target=self.play_media)
   player_thread.start()
   time.sleep(1)
   self.song_len()

Notice that we made the method to sleep for one second, so as to enable to length metadata to populate. If we do not make it sleep for a second, the code would execute so fast that it would end even before the song_length variable is updated by pyglet.


Now, we have access to the total length and current duration of play. We now want to update the current track every time a new track is played.

Step 3 – updating console at launch of play

A new track is played when a user hits the Play button, or when he or she double-clicks a particular song, or when he or she clicks the Next or Previous button.

If you look at the code from previous iteration (code 5.03 GUI.py), all these methods call the self.player.start_play_thread()functionality to start the playback. However, now we need to update the console display every time a new player thread is started.

We, therefore, need to refactor our code. For one, we will route all calls to player.start_play_thread()through a single method, which will update the display as the player thread starts.

Step 4 – updating timer clock and progress bar at regular intervals

We, therefore, define a new method named launch_play, and replace all instances of player.start_play_thread()from previous code to now call our launch_play method, as follows (see Code 5.04.py main-gui.py):

def launch_play(self):
   try:
     self.player.pause()
   except:
     pass
   self.player.start_play_thread()
   song_lenminute = str(int(self.player.song_length/60))
   song_lenseconds = str (int(self.player.song_length%60))
   filename = self.currentTrack.split('/')[-1] + '
 ['+ song_lenminute+':'+song_lenseconds+']'
   self.canvas.itemconfig(self.songname, text=filename)
   self.progressBar["maximum"]=self.player.song_length
   self.update_clock_and_progressbar()

The description of the code is listed as follows:

  • The code first tries to stop any other track that might be playing at that time, because we don't want multiple tracks playing at a given time.
  • It then starts to play the next track in a separate thread. The thread method automatically updates the song length, and now we have access to the song length in the variable self.player.song_len.
  • The next two lines break the song length into equivalent minutes and seconds.
  • The next line breaks the file name and gets hold of the song name from the complete path. It then appends the time calculated in minutes and seconds to the file name.
  • We set the maximum value for our progress bar, which is a floating point number specifying the maximum value of the progress bar. For viewing all configurable options for ttk Progressbar, enter the following into your Python interactive console:
    >>> import ttk
    >>> help(ttk.Progressbar)
    
  • The next line uses canvas.itemconfig to update the song name and song length in the display console.

    Note

    Just like we use config to change value of widget related options, the Canvas widget uses itemconfig to change the options for individual items within the canvas.

    The format for itemconfig is as follows: itemconfig(itemid, **options).

In this step, we will learn to update timer clock and progress bar at regular intervals. Although song name and song length are to be updated just once for a given song, the play duration and progress bar need to be updated at small intervals. We, therefore, handle it in a separate method named update_clock_and_progressbar().

We want to display time in the format you normally find in a digital clock. We accordingly define a string format named timepattern, as follows:

timepattern = '{0:02d}:{1:02d}'.

Now, let us turn our attention to updating the display clock and the progress bar. We have already made a call to update_clock_and_progressbar()which is supposed to take care of this work. Let's now code this method, as follows(see Code 5.04.py main-gui.py):

def update_clock_and_progressbar(self):
   current_time = self.player.current_time()
   song_len = (self.player.song_len())
   currtimeminutes = int(current_time/60)
   currtimeseconds = int(current_time%60)
   currtimestrng = self.timepattern.format(currtimeminutes, currtimeseconds)
   self.canvas.itemconfig(self.clock, text= currtimestrng)
   self.progressBar["value"] = current_time
   self.root.update()
   if current_time == song_len: #track is over
     self.canvas.itemconfig(self.clock, text= '00:00')
     self.timer=[0,0]
     self.progressBar["value"] = 0
   else:
     self.canvas.after(1000, self.update_clock_and_progressbar)

This code runs itself every 1000 ms, forces a root update, and changes the time and progress bar value. To keep running regularly, it calls back itself after every 1000 ms.

When a track is over, it resets the values of clock and progress bar to zero, and exits out of the update loop.

Note

We used the canvas.after method to call the same method at intervals of one second. Thus, this method would get to be called at one second interval throughout playing of the current track. We also kept a condition to break out of the loop when the current track ended playing.

Objective Complete – Mini Debriefing

This completes this iteration. In this iteration, we built a functional display console and a progress bar to display time and information about the current track.

We started by creating a blank canvas in the top area of our root window. We then added an image that resembles a display console. We then used canvas.create_text to precisely position the timer clock, name of currently playing track, and the total track length in the console.

We also created a ttk progress bar.

We then calculated the track length using the pyglet API. Next, we made all calls to play the track to be routed through an intermediate method which updated the console with information about the currently playing track.

We also added a method to update the clock and progress bar at regular intervals.

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

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