Update Progressbar

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Post Reply
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Update Progressbar

Post by Lena »

Hi.
I try update value on FMX project but no effect. How is it correct?
Thanks.

Code: Select all

progress := 0;
    repeat
      len := BASS_StreamGetFilePosition(str, BASS_FILEPOS_END);
      if (len = DW_Error) then
        break; //something's gone wrong! (eg. BASS_Free called)
      progress := BASS_StreamGetFilePosition(str, BASS_FILEPOS_BUFFER) * 100 div len;
      ProgressBar1.Value := progress;
      //Application.ProcessMessages(); //no effect
      //ProgressBar1.Repaint(); //no effect
     until
      (progress > 75) or (BASS_StreamGetFilePosition(str, BASS_FILEPOS_CONNECTED) = 0); // over 75% full (or end of download)

     //test
     ShowMessage(IntToStr(Trunc(ProgressBar1.Value))); //75 OК!

HsiaLin
BCBJ Master
BCBJ Master
Posts: 333
Joined: Sun Jul 08, 2007 6:29 pm

Re: Update Progressbar

Post by HsiaLin »

try
ProgressBar1.Update();
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

HsiaLin wrote: Wed Oct 21, 2020 4:07 am try
ProgressBar1.Update();
Hi.
In FMX no method Update for ProgressBar.
rlebeau
BCBJ Author
BCBJ Author
Posts: 1726
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Update Progressbar

Post by rlebeau »

Using Repaint() should have worked. That being said, your loop probably should be in a separate worker thread instead, not in the main UI thread. Then that worker thread can post updates to the UI as needed, and let the main UI thread handle painting updates normally.
Remy Lebeau (TeamB)
Lebeau Software
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

rlebeau wrote: Thu Oct 22, 2020 2:16 pm your loop probably should be in a separate worker thread instead, not in the main UI thread. Then that worker thread can post updates to the UI as needed, and let the main UI thread handle painting updates normally.
Can you show the structure of the code how it should look?

P.S.
Maybe so?

Code: Select all

var
 aTask: ITask;
begin
 aTask := TTask.Create(
   procedure
   begin
     //here my loop with progress
     TThread.Synchronize(TThread.Current,
       procedure
       begin
         ProgressBar1.Value := progress;
       end);
   end);
   aTask.Start;
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

I tried to use the indicator but I can't see it.

Code: Select all

procedure TForm1.Button1Click(Sender: TObject);//Play Button usually loading audio stream 2-10 seconds

var
  check :boolean;
  Len, progress: DWORD;
Begin
   AniIndicator1.Enabled := True;//no effect
   AniIndicator1.Visible := True;
   AniIndicator1.Repaint;

   progress := 0;
   BASS_StreamFree(str);
   //****************other code*******************
   
   
   AniIndicator1.Enabled := FALSE;
   AniIndicator1.Visible := FALSE;
rlebeau
BCBJ Author
BCBJ Author
Posts: 1726
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Update Progressbar

Post by rlebeau »

Lena wrote: Sat Oct 24, 2020 3:43 am I tried to use the indicator but I can't see it.
What is in your "other code" exactly? If you are doing everything in the OnClick handler, blocking the main UI message loop, then it makes sense why the Indicator doesn't show anything. DO NOT block the main UI thread!
Remy Lebeau (TeamB)
Lebeau Software
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

What is in your "other code" exactly?

Code: Select all

AniIndicator1.Enabled := True;
   AniIndicator1.Visible := True;
   AniIndicator1.Repaint();

   BASS_StreamFree(str);
   str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);

   If BASS_ErrorGetCode = 40 Then
   ShowMessage('...');
   exit;
    End;

  If BASS_ErrorGetCode = 0 Then
  Begin

      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      Viewport3D1.Visible := True;
      FloatAnimation1.Enabled := True;
      AniIndicator1.Enabled := FALSE;
      AniIndicator1.Visible := FALSE;
 

   End;
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

I try this:

Code: Select all

var
ercode: DWORD;
//***
ercode := 100;

TThread.CreateAnonymousThread(procedure ()
    begin
      TThread.Synchronize (nil, 
      procedure ()
      begin
       
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end);

      BASS_StreamFree(str);
      str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
      ercode := BASS_ErrorGetCode;

      If BASS_ErrorGetCode = 40 Then
              Begin
               ShowMessage('Sorry maintenance work on the music server.');
               BASS_SampleFree (smp);
               exit;
              End;

       If BASS_ErrorGetCode = 0 Then
              Begin
               BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
               BASS_ChannelPlay(str, FALSE);

              End;


       TThread.Synchronize(nil,
             procedure ()
                begin
                if ercode = 0 Then Begin
                   Viewport3D1.Visible := True;
                  FloatAnimation1.Enabled := True;
                  AniIndicator1.Enabled := FALSE;
                  AniIndicator1.Visible := FALSE;
                 end;

                end);

  end).Start;

If the Internet connection is good, I see the indicator for a couple of seconds and the music starts playing.
If the Internet connection is bad, then the indicator appears after five to seven seconds and the music starts playing.
How to see the indicator when the internet connection is bad?
rlebeau
BCBJ Author
BCBJ Author
Posts: 1726
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Update Progressbar

Post by rlebeau »

Lena wrote: Sat Nov 07, 2020 8:33 am How to see the indicator when the internet connection is bad?
Since you are creating the stream outside of the main UI thread, the display of the Indicator should not be affected by the speed of the API. That makes me think maybe you are still doing other things in the main UI thread while the thread is running.

That being said, I would suggest something more like the following for the thread, at least:

Code: Select all

TThread.CreateAnonymousThread(
  procedure
  var
    ercode: Integer;
    ermsg: string;
  begin
    TThread.Queue(nil, 
      procedure
      begin
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end
    );

    BASS_StreamFree(str);
    str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
    ercode := BASS_ErrorGetCode;

    if ercode = BASS_OK then
    begin
      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          Viewport3D1.Visible := True;
          FloatAnimation1.Enabled := True;
        end
      );
    end else
    begin
      BASS_SampleFree (smp);
      if ercode = BASS_ERROR_TIMEOUT then
        ermsg := 'Sorry maintenance work on the music server.'
      else
        ermsg := Format('Unable to create music stream. Error %d', [ercode]);
      TThread.Queue(nil,
        procedure
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage(ermsg);
        end
      );
    end;
  end
).Start;
The thread should not be blocked while the UI is updating, hence the use of TThread.Queue() instead of TThread.Synchronize(). And ShowMessage() is not thread-safe, so it needs to be synced as well. And you should turn off the Indicator regardless of whether the stream succeeds or fails, but you were turning it off only if the stream succeeds.
Remy Lebeau (TeamB)
Lebeau Software
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

Thank you very much rlebeau!
Everything looks right now. I also discovered my mistake. Before using CreateAnonymousThread, I was checking the Internet using my custom function. This is a mistake that did not allow to see AniIndicator1 when internet connection bad. I removed my function of checking the Internet connection. Now I want use BASS for chek Internet connection.
If there is no internet connection, I get error number 2 from BASS.
I gave up my internet check connection function. How to correctly insert this my new code internet connection into your Pascal code?

Code: Select all

if (ercode = BASS_ERROR_FILEOPEN) or (ercode = BASS_ERROR_NONET)  then
    begin
        TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage('No internet connection.' + sLineBreak + 'Нет интернет соединения.');
          exit;
        end
      );
    end;
I spent the whole day but I cannot correctly insert my new code because I am confused in if begin end
Pascal language is not very clear to me. :)
For example, I don't understand why your code works without a semicolon ";":
ermsg := 'Sorry maintenance work on the music server.'
:o
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

Also I use this code from BASS for stop music:

Code: Select all

var
  Form1: TForm1;

  smp: HSAMPLE;
  str: HSTREAM;
 //**************
 
 procedure TForm1.Button2Click(Sender: TObject);
begin
 BASS_ChannelStop(str);
 BASS_SampleFree (smp);
end;
 
But I am not initializing anywhere smp! Why does it work and how is it correct for HSAMPLE initializing?
rlebeau
BCBJ Author
BCBJ Author
Posts: 1726
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Update Progressbar

Post by rlebeau »

Lena wrote: Tue Nov 10, 2020 10:02 am If there is no internet connection, I get error number 2 from BASS.
Error 2 is BASS_ERROR_FILEOPEN, but the documentation says that 32 (BASS_ERROR_NONET) should be reported if there is no Internet connection. Sounds like a bug in the BASS library.
Lena wrote: Tue Nov 10, 2020 10:02 am How to correctly insert this my new code internet connection into your Pascal code?
You already know how - handle the BASS_ERROR_NONET error. I would not treat BASS_ERROR_FILEOPEN as an Internet connection error. It could just be a wrong URL, or maybe the URL is temporarily offline because the server is down for maintenance at that moment, etc.

Since you are now handling multiple errors, I would suggest a slightly different approach:

Code: Select all

TThread.CreateAnonymousThread(
  procedure
  var
    ercode: Integer;
    ermsg: string;
  begin
    TThread.Queue(nil, 
      procedure
      begin
        AniIndicator1.Enabled := True;
        AniIndicator1.Visible := True;
      end
    );

    BASS_StreamFree(str);
    str := BASS_StreamCreateURL(PChar('http://91.199.194.34:8000'), 0, BASS_UNICODE, nil, nil);
    ercode := BASS_ErrorGetCode;

    if ercode = BASS_OK then
    begin
      BASS_ChannelSetSync(str, BASS_SYNC_META, 0, @MetaSync, nil);
      BASS_ChannelPlay(str, FALSE);
      TThread.Queue(nil,
        procedure
        begin
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          Viewport3D1.Visible := True;
          FloatAnimation1.Enabled := True;
        end
      );
    end else
    begin
      BASS_SampleFree (smp);
      case ercode of
        BASS_ERROR_TIMEOUT: ermsg := 'Sorry maintenance work on the music server.';
        BASS_ERROR_FILEOPEN: ermsg := 'Sorry can't open the music file. Check the URL.';
        BASS_ERROR_NONET: ermsg := 'No internet connection.';
        // other error codes as needed..
      else
        ermsg := Format('Unable to create music stream. Error %d', [ercode]);
      end;
      TThread.Queue(nil,
        procedure
          AniIndicator1.Enabled := False;
          AniIndicator1.Visible := false;
          ShowMessage(ermsg);
        end
      );
    end;
  end
).Start;
Lena wrote: Tue Nov 10, 2020 10:02 am I spent the whole day but I cannot correctly insert my new code because I am confused in if begin end
Pascal language is not very clear to me. :)
Really? 'begin ... end' is just Pascal's equivalent to C/C++'s '{}' curly braces.
Lena wrote: Tue Nov 10, 2020 10:02 am For example, I don't understand why your code works without a semicolon ";":
That, on the other hand, can be tricky for Pascal beginners.

In Pascal, semicolon is a statement *separator*, not a statement *terminator*, like it is in C/C++. There is a difference. There are places in Pascal syntax where an explicit terminator is not needed, because the compiler knows there is a separation of statements, so the semicolon is optional in those places. Using a semicolon in those places just creates empty statements.

A semicolon is commonly used as a *terminator* in places it is not strictly needed, for consistency and portability between languages, and when beginners just don't know any better :-)
Lena wrote: Tue Nov 10, 2020 10:22 am But I am not initializing anywhere smp!
Well, then that is on you. You have a bug in your code that you need to fix. Stop trying to free something that you don't create. Or else create it properly.

Or, maybe you simply meant to call BASS_StreamFree(str) instead of BASS_SampleFree(smp)? That would make more sense, given the code you have shown so far. I haven't seen any code in your snippets that tries to free the HSTREAM returned by BASS_CreateStreamURL().
Lena wrote: Tue Nov 10, 2020 10:22 am Why does it work
BASS_SampleFree() fails if you give it an invalid handle. But you are not checking for that failure.
Lena wrote: Tue Nov 10, 2020 10:22 am how is it correct for HSAMPLE initializing?
I don't know. I don't use BASS. What are you trying to use the HSAMPLE for in the first place?
Remy Lebeau (TeamB)
Lebeau Software
Lena
BCBJ Master
BCBJ Master
Posts: 706
Joined: Sun Feb 06, 2011 1:28 pm

Re: Update Progressbar

Post by Lena »

Thanks a lot for the detailed explanation!
I removed from the code BASS_SampleFree.
My code contains three buttons PLAY, STOP, CLOSE

Code: Select all

//STOP play
procedure TForm1.Button2Click(Sender: TObject);
begin

 BASS_ChannelStop(str);
 //BASS_StreamFree(str);
 //BASS_SampleFree (smp);
 Text1.Text := ''; //title song
 FloatAnimation1.Enabled := False;
 Viewport3D1.Visible := False;
end;

//CLOSE app and remove service icon from tray
procedure TForm1.Image3Click(Sender: TObject);
begin
 BASS_ChannelStop(str);
 BASS_StreamFree(str);
 MainActivity.finish;
end;

procedure TForm1.FormCreate(Sender: TObject);
Begin

 if not BASS_Init(-1, 44100, 0, nil, nil) Then Begin
	   ShowMessage('Failed to initialize audio!' + sLineBreak + 'Не удалось инициализировать audio!');
     Exit;
     end;

 if FService = Nil Then Begin
  FService := TLocalServiceConnection.Create;
  FService.StartService('serPublic');
  end;
end;
  
//PLAY button contain your TThread.CreateAnonymousThread  
Now everything works as it should. Thanks!
One feature is not very good in BASS. Sometimes when the Internet is bad and I press the Play button, the stream is loaded without errors, but there is no sound.
rlebeau
BCBJ Author
BCBJ Author
Posts: 1726
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Update Progressbar

Post by rlebeau »

Lena wrote: Wed Nov 11, 2020 1:02 am One feature is not very good in BASS. Sometimes when the Internet is bad and I press the Play button, the stream is loaded without errors, but there is no sound.
You are going to have to take that up with BASS's author, or the BASS community.
Remy Lebeau (TeamB)
Lebeau Software
Post Reply