Media Player Built Entirely with PowerBuilder and Ultimate Suite for PowerBuilder

The next release of Ultimate Suite is going to include a new Circle Progress control. The best way to make sure that a new control covers all the needs of the developer is to use it in a real world application. Doing this allows you to identify deficiencies in the design or behavior. The best way I could think of to do this was to use the Circle Progress control within a media player. It can be used to start or pause playback and display the video's elapsed time. Using the Ultimate Suite caption-less window, some toolbars, the circle progress control and the Windows Media Player Active-X control, we get the following:

PowerBuilder Media Player

To create this, first inherit a new window from w_pbus_spa_captionless. Add a logo, static text for the application label, two toolbars for the play back options, and the circle progress control. Next, add an OLE control and select Windows Media Player.


In the open event of the window, add the following code:

//Use a custom color for the window background color
THIS.of_UseCustomColors(RGB(255,255,255), 0)

//Set the circle progress control to use the same color as the window
uo_play.BackColor = THIS.BackColor

//Set the URL for the video to play in the media player
ole_media.Object.URL = "<your video file>"

//We have two toolbars for play back options. Don't display borders
uo_toolbarleft.of_DisplayBorder(FALSE)
uo_toolbarright.of_DisplayBorder(FALSE)

//Set the icon size to large
uo_toolbarleft.of_SetSize(uo_toolbarleft.LARGE)
uo_toolbarright.of_SetSize(uo_toolbarleft.LARGE)

//Add buttons to the left toolbar
uo_toolbarleft.of_AddItem("Replay", "c:\dev\replay.png", uo_toolbarleft.RIGHT)
uo_toolbarleft.of_AddItem("Rewind", "c:\dev\rewind.png", uo_toolbarleft.RIGHT)
uo_toolbarleft.of_AddItem("Skip Backwards", "c:\dev\skipback.png", uo_toolbarleft.RIGHT)

//Add buttons to the right toolbar
uo_toolbarright.of_AddItem("Stop", "c:\dev\stop3.png")
uo_toolbarright.of_AddItem("Fast Forward", "c:\dev\fast_forward.png")
uo_toolbarright.of_AddItem("Skip Forwards", "c:\dev\skipforward.png")

In the resize event, we'll size the video play and snap the controls at the bottom of the screen:

SetRedraw(FALSE)
ole_media.Resize(NewWidth - (ole_media.X * 2), NewHeight - 316 - ole_media.Y)
uo_play.Move((NewWidth - uo_play.Width) / 2, ole_media.Y + ole_media.Height + 16)

uo_toolbarleft.Move(uo_play.X - 32 - uo_toolbarleft.Width,uo_play.Y + 52)
uo_toolbarright.Move(uo_play.X + uo_play.Width + 32,uo_play.Y + 52)
SetRedraw(TRUE)

There doesn't seem to be a working event in the Media Player control to track video progress so we'll setup a timer on the window. When the video plays, we'll trigger the windows timer event every half second by default.

In the timer event, we'll set progress:

Long ll_pos

//Get the current position of the video
ll_pos = Double(ole_media.Object.Controls.CurrentPosition)

//il_duration is set when the video starts and it contains the duration, in seconds, of the video
//We'll calculate a percentage complete and update the Circle Progress control with it

uo_play.of_SetProgress(ll_pos / il_duration * 100.00)

Lastly, in the close event of the window we'll make sure the media is not playing:

ole_media.Object.Controls.Stop( )

Now we can add some code to the Media Player control to change our UI depending on the Play State of the video.

Add the following code to the PlayStateChanged event of the media control:

CONSTANT INT Undefined = 0
CONSTANT INT Stopped = 1
CONSTANT INT Paused = 2
CONSTANT INT Playing = 3
CONSTANT INT ScanForward = 4
CONSTANT INT ScanReverse = 5
CONSTANT INT Buffering = 6
CONSTANT INT Waiting = 7
CONSTANT INT MediaEnded = 8
CONSTANT INT Transitioning = 9
CONSTANT INT Ready = 10
CONSTANT INT Reconnecting = 11

IF newstate = Playing THEN

//This is where we get the video duration, we'll later use this in the timer event to
    
    //calculate the percentage complete
        il_duration = Double(ole_media.Object.Controls.CurrentItem.Duration)
        uo_play.of_SetImage("c:\dev\pause3.png")

//We will use the ii_advanceposition variable to indicate that the user has clicked on the 
        //Circle Progress control to change the video position
        IF ii_advanceposition > 0 THEN

//Calculate a new position based on where the user clicked in the Circle Progress control
                ole_media.Object.Controls.CurrentPosition = il_duration * (ii_advanceposition / 100)
                ii_advanceposition = 0

END IF

//Start the timer
        Timer(id_timer)

END IF

IF newstate = MediaEnded OR newstate = Stopped  OR newstate = Paused THEN

//Video stopped so we can also stop the timer
        Timer(0)
        //We also need to re-display the play button. While playing, the button should be a pause button
        uo_play.of_SetImage("c:\dev\play3.png")

END IF

//If we're fast forwarding or fast reversing, we need to display a play button to indicate
//to the user that they will use that button to play the video normally
IF newstate = ScanForward OR newstate = ScanReverse THEN

uo_play.of_SetImage("c:\dev\play3.png")

END IF

//Finally, if the video is stopped, we'll clear out the progress.
IF newstate = Stopped THEN

uo_play.of_SetProgress(0)

END IF

There are two events in the Circle Progress control that we'll use to control play back; CenterClicked and OutlineClicked. CenterClicked is triggered when the user clicks anywhere within the circle. The OutlineClicked event is triggered when the user clicked on the the actual circle outline.

In the CenterClicked event, add the following code to Play or Pause the video:

CHOOSE CASE ole_media.Object.PlayState
    CASE 3 //Playing
        ole_media.Object.Controls.Pause( )
    CASE ELSE
        ole_media.Object.Controls.Play( )
END CHOOSE

In the OutlineClicked event, add the following code to Advance playback:

//If the current state is not Playing, then set the advance and start playing
IF ole_media.Object.PlayState <> 3 THEN
ii_advanceposition = percentage
ole_media.Object.Controls.Play( )
of_SetProgress(percentage)
ELSE
ole_media.Object.Controls.CurrentPosition = il_duration * (percentage / 100)
of_SetProgress(percentage)
END IF

That covers most of the functionality. There are other commands for stopping, skipping and fast forwarding, etc. Here they are for your information:

ole_media.Object.Controls.Stop( )
ole_media.Object.Controls.FastForward( )
ole_media.Object.Controls.FastReverse( )


At the beginning of this post I talked about finding deficiencies in the design or behavior. This was a very good example to help find these deficiencies. While developing this application I realized I needed to add the following:

1) The ability to change the image in the center of the control
2) Give the ability to know when the center is clicked and when the outline is clicked.
3) I had to add way better precision. Progress use to be tracked as an Integer, now it's a Double.

After this exercise we now have a better Circle Progress control and a totally useless Media Player. 😀

For more information about Ultimate Suite for PowerBuilder, visit PBUltimateSuite.com

Comments

Popular posts from this blog

Develop a web browser in PowerBuilder.

PowerBuilder Code Beautifier / Formatter

PowerSchedule - A New Scheduling and Calendar Control for PowerBuilder Applications