2017-02-25 10 views
6

私は書籍Programming Principles and Practice Using C++を使ってC++を学んでいます。第16章では、インターフェイスライブラリ経由でFLTKライブラリのgui部分を使用するテクニックについて説明します。プログレスバークラスの実装

この章の練習の1つは、クラス内に実装された開始ボタンと停止ボタンによって制御される画像の動きをアニメートすることです。タイミングのためにFLTK Fl::add_timeoutFl::repeat_timeoutの使用が無限ループに入り、Sleep()を使用して他のコールバックをブロックするよりも良い解決策であることがわかりました。

私はFl::add_timeoutFl::repeat_timeoutを使用して実用的なソリューションを実装することに成功したが、スタートでプログレスバーを使用した例hereを発見し、ボタンを停止していない:

#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(); 
} 

この例では、コンパイルし、正常に動作します。

次に、進捗バーの例をクラスにまとめようとしましたが、これは私が立ち往生した場所です。

#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; 
} 

コールバック関数の実装方法がわかりません。私はコメントに書かれているようにコンパイルエラーを取得します。

runcount()関数を静的にすると、runcount()の呼び出しでコンパイルエラーが消えますが、この関数を静的にすることは意味がありません。 progBar呼び出しで新しいエラーが発生します。

このクラスを実装して、開始機能と停止機能を使用するにはどうすればよいですか?

コールバック関数がどのように機能し、ポインタを使用するかに関する知識が不足している可能性があります。そのため、これを解決しようとしています。

答えて

1

コールバックが署名

void xxx(Fl_Widget*, void*) 

は、プログレスバーのコールバックが署名

void ProgressBar::xxx(void*) 

を持っているこの問題を回避するための簡単な解決策は、順番に呼び出して、静的な関数を作成することですメンバ関数です。あなたは、cb_startbとcb_stopbをランカウントするためにこのモデルを適用した場合の例として

// 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); 
} 

をcb_startbを使用して、それはあなたのコンパイル・エラーのほとんどを取り除く必要があります。 runco​​untをパラメータとして使用する場合は、void *パラメータとして使用して静的バージョンを渡します。

マイナーノート:コンストラクタ内のラベルをconst std :: string &に変更してください。