Implementing a progress bar class
Asked Answered
K

1

6

I am learning c++ using the book Programming Principles and Practice Using C++. Chapter 16 covers techniques using the gui part of FLTK library via an interface library.

One of the exercises in this chapter is to animate movement of a picture, controlled by a start and stop button implemented in a class. For timing I found that use of FLTKs Fl::add_timeout and Fl::repeat_timeout is a better solution than going in to an infinite loop and use Sleep(), blocking other callbacks.

I did not succeed in implementing a working solution using Fl::add_timeout and Fl::repeat_timeout, but found an example here using a progress bar with a start and stop button:

#include <FL/Fl.H> 
#include <FL/Fl_Double_Window.H> 
#include <FL/Fl_Progress.H> 
#include <FL/Fl_Button.H> 

Fl_Progress* progBar; 

void runcount(void*) 
{ 
    if (progBar->value() == progBar->maximum()) 
    { 
        Fl::remove_timeout(runcount); 
        progBar->value(0); 
    } 
    else 
    { 
        Fl::repeat_timeout(1, runcount); 
        progBar->value(progBar->value() + 1); 
    } 
} 

void cb_startb(void) 
{ 
    Fl::add_timeout(1, runcount); 
} 

void cb_stopb(void) 
{ 
    Fl::remove_timeout(runcount); 
} 

int main (int argc, char *argv[]) 
{ 
    Fl_Double_Window window(200,70,"ProgressBar Test"); 
    progBar = new Fl_Progress(5, 10, window.w()-10, 20); 
    progBar->box(FL_SHADOW_BOX); 
    progBar->selection_color((Fl_Color)4); 
    progBar->minimum(0); 
    progBar->maximum(10); 

    Fl_Button* start_button = new Fl_Button(10, 40, 80, 20, "START"); 
    start_button->box(FL_SHADOW_BOX); 
    start_button->callback((Fl_Callback*)cb_startb,(void*)"start"); 

    Fl_Button* stop_button = new Fl_Button(110, 40, 80, 20, "STOP"); 
    stop_button->box(FL_SHADOW_BOX);
    stop_button->callback((Fl_Callback*)cb_stopb,(void*)"stop"); 

    window.end(); 
    window.show(argc, argv); 

    return Fl::run(); 
}

This example compiles and works fine.

I then tried to put the progress bar example together in a class, and this is where I am stuck.

#include <FL/Fl.H> 
#include <FL/Fl_Double_Window.H> 
#include <FL/Fl_Progress.H> 
#include <FL/Fl_Button.H> 
#include <string>

class ProgressBar : public Fl_Double_Window {
public:
    ProgressBar(int w, int h, const std::string label)
        : Fl_Double_Window{ w,h,label.c_str() }
    {
        progBar = new Fl_Progress(5, 10, 10, 20);
        progBar->box(FL_SHADOW_BOX);
        progBar->selection_color((Fl_Color)4);
        progBar->minimum(0); // set range: 0-10
        progBar->maximum(10);

        start_button = new Fl_Button(10, 40, 80, 20, "START");
        start_button->box(FL_SHADOW_BOX);
        start_button->callback((Fl_Callback*)cb_startb, (void*)"start"); //compile error: 'type-cast':cannot convert 
        //from 'overloaded-function'..

        stop_button = new Fl_Button(110, 40, 80, 20, "STOP");
        stop_button->box(FL_SHADOW_BOX);
        stop_button->callback(static_cast<Fl_Callback*>(cb_stopb), (void*)"stop");//(Fl_Callback*)cb_stopb
        //compile error: 'type-cast':cannot convert from 'overloaded-function'..
    }

    ~ProgressBar()
    {
        delete progBar;
        delete start_button;
        delete stop_button;
    }

private:
    void runcount(void*)
    {
        if (progBar->value() == progBar->maximum())
        // max reached, stop timer and reset pregress bar to 0
        {
            Fl::remove_timeout(runcount); // non-standard syntax, use & to create a pointer to member
            progBar->value(0);
        }
        else
        // timer running, recursive calling this function - increase progress bar by 1.
        {
            Fl::repeat_timeout(0.1, runcount);  ///compile error: non-standard syntax, use & to create a pointer to member
            progBar->value(progBar->value() + 1);
        }
    }

    void cb_startb(void)
    {
        Fl::add_timeout(1, runcount);///compile error: non-standard syntax, use & to create a pointer to member
    }

    void cb_stopb(void)
    {
        Fl::remove_timeout(runcount);///compile error: non-standard syntax, use & to create a pointer to member
    }

    Fl_Button* start_button;
    Fl_Button* stop_button;
    Fl_Progress* progBar;
};


int main()
{
    ProgressBar* progBar = new ProgressBar{200, 700,"Progress bar" };

    progBar->end();
    progBar->show();

    return Fl::run();
    delete progBar;
}

I cannot find out how to implement the callback functions. I get the compile errors as written in the comments.

If I make the runcount() function static, the compile error on the 4 calls to runcount() disappears, but it doesn’t make sense to me to make this function static. I get new errors on the progBar calls.

How can I implement this class, to use a start and stop function?

I am probably missing some knowledge on how callback function works and the use of pointers, which is why I am trying to work this out.

Kerley answered 25/2, 2017 at 13:24 Comment(0)
R
1

The callback has the signature

void xxx(Fl_Widget*, void*)

The ProgressBar callbacks have the signature

void ProgressBar::xxx(void*)

A simple solution to get around this problem is to create a static function, which, in turn calls the member function. Using cb_startb as an example

// Where you are getting the compilation error
start_button->callback(_cb_startb, this);
...

// Create a static version of your function
static void _cb_startb(Fl_Widget*, void* self)
{
    reinterpret_cast<ProgressBar*>(self)->cb_startb();
}

// This is the member function
void cb_startb()
{
    // do the same thing for runcount
    Fl::add_timeout(1, _runcount, this);
}

If you apply this model to runcount, cb_startb and cb_stopb, it should get rid of most of your compile errors. Wherever you are using runcount as a parameter, pass in the static version, using this as the void* parameter.

Minor note: change the label in the constructor to a const std::string& .

Rattlebox answered 25/2, 2017 at 18:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.