c++fltk

FLTK: Clearing a graph when drawing another


I wrote a simple FLTK program to draw a circle when clicking on the "Draw Circle" button and to draw a line when clicking on the "Draw Line" button. I supposed to have only one graph. But I got two graphs in the panel. I want only one showing and the other disappearing. The following is the code:

#include <FL/Fl.H>
#include <FL/Fl_Button.H>
#include <FL/Fl_Double_Window.H>
#include <FL/fl_draw.H>
#include <FL/Fl_Box.H>

using namespace std;

int flag = 0;
class Drawing : public Fl_Box {
    void draw() {
        fl_color(255, 0, 0);
        int x, y, x1, y1;
        if (flag == 1) {
            
            double radius = 100;
            x = (int)(w() / 2);
            y = (int)(h() / 2);
            fl_circle(x, y, radius);
        }
        else if (flag == -1) {
            
            x = (int)(w() / 4);
            y = (int)(h() / 4);
            x1 = (int)(w() *3/ 4);
            y1 = (int)(h() *3/ 4);
            fl_line(x, y, x1, y1);
        }
    }
public:
    Drawing(int X, int Y, int W, int H) : Fl_Box(X, Y, W, H) {}
};

Drawing* d;

void circle_cb(Fl_Widget*, void*) {
    flag = 1;
    fl_overlay_clear();
    d->redraw();
} // end sumbit_cb

void line_cb(Fl_Widget*, void*) {
    flag = -1;
    fl_overlay_clear();
    d->redraw();
} // end clear_cb

int main(int argc, char** argv) {
    Fl_Window* window = new Fl_Window(600, 550); // create a window, originally(400,400)

    Drawing dr(0, 0, 600, 600);
    d = &dr;

    Fl_Button *b, *c;

    b = new Fl_Button(150, 80, 100, 25, "&Draw Circle");
    b->callback(circle_cb);

    c = new Fl_Button(350, 80, 100, 25, "&Draw Line");
    c->callback(line_cb);

    window->end(); //show the window 
    window->show(argc, argv);
    return Fl::run();
}

I have used fl_overlay_clear() to clear graph. However it is not working. Any help will be appreciated.


Solution

  • There are several issues that need to be fixed in your program, but first of all using the draw() method as you did is basically correct. However, using fl_overlay_clear(); is useless, you can remove it.

    My solution: your widget doesn't have a solid background (boxtype), i.e. your draw method draws over the background over and over again w/o clearing it. There are several ways to solve this, but if you want to learn what happens, try this first: add window->resizable(window); before window->show(argc, argv);, run the program again and resize the window. You'll notice that the previous drawing disappears and only one drawing stays. That's because the background is cleared when you resize the widget.

    Next step: add a solid boxtype:

      d = &dr;
      d->box(FL_DOWN_BOX);
    

    and add Fl_Box::draw(); right at the beginning of your draw() method.

    If you do that you may notice that your button(s) disappear when you click one of them - because your buttons are inside the area of your Drawing. The last thing(s) I fixed was to correct the coordinates of buttons and to enlarge the window (it was too small anyway to cover the entire Drawing). Here's my complete result:

    #include <FL/Fl.H>
    #include <FL/Fl_Button.H>
    #include <FL/Fl_Double_Window.H>
    #include <FL/fl_draw.H>
    #include <FL/Fl_Box.H>
    
    using namespace std;
    
    int flag = 0;
    class Drawing : public Fl_Box {
      void draw() {
        Fl_Box::draw();
        fl_color(255, 0, 0);
        int x, y, x1, y1;
        if (flag == 1) {
    
          double radius = 100;
          x = (int)(w() / 2);
          y = (int)(h() / 2);
          fl_circle(x, y, radius);
        } else if (flag == -1) {
    
          x = (int)(w() / 4);
          y = (int)(h() / 4);
          x1 = (int)(w() * 3 / 4);
          y1 = (int)(h() * 3 / 4);
          fl_line(x, y, x1, y1);
        }
      }
    
    public:
      Drawing(int X, int Y, int W, int H)
        : Fl_Box(X, Y, W, H) {}
    };
    
    Drawing *d;
    
    void circle_cb(Fl_Widget *, void *) {
      flag = 1;
      // fl_overlay_clear();                       // not useful
      d->redraw();
    } // end sumbit_cb
    
    void line_cb(Fl_Widget *, void *) {
      flag = -1;
      // fl_overlay_clear();                       // not useful
      d->redraw();
    } // end clear_cb
    
    int main(int argc, char **argv) {
      Fl_Window *window = new Fl_Window(600, 660); // create a window, originally(400,400)
    
      Drawing dr(0, 60, 600, 600);                        // FIXED
      d = &dr;
      d->box(FL_DOWN_BOX);                                // ADDED
    
      Fl_Button *b, *c;
    
      b = new Fl_Button(150, 20, 100, 25, "&Draw Circle"); // FIXED
      b->callback(circle_cb);
    
      c = new Fl_Button(350, 20, 100, 25, "&Draw Line");   // FIXED
      c->callback(line_cb);
    
      window->end(); // show the window
      window->resizable(window);              // ADDED
      window->show(argc, argv);
      return Fl::run();
    }
    

    I believe this does what you want.

    PS: the official FLTK support forum can be found on our website https://www.fltk.org/ and the direct link to the user forum (Google Groups) is https://groups.google.com/g/fltkgeneral