zhiar
zhiar

Reputation: 113

C++ FLTK, creating a rounded box

The problem says: Draw a box with rounded corners. Define a class Box, consisting of four lines and four arcs. So I wrote the below code for that exercise:

#include <Simple_window.h>
Simple_window win(Point(100,100), 600,400, "semi-ellipse");

struct Box: Shape{

    Box(Point p, int ww, int hh): w(ww), h(hh) 
        { add(Point(p.x-ww,p.y-hh));  }

    void d_l() const        //creating 4 lines
     {
        Line hrz1 (Point(150,100), Point(400,100));
        Line hrz2 (Point(150,300), Point(400,300));
        Line ver1 (Point(507,150), Point(507,250));
        Line ver2 (Point(41,150), Point(41,250));

        win.attach(hrz1);
        win.attach(hrz2);
        win.attach(ver1);
        win.attach(ver2);
     }

    void draw_lines() const      //creating 4 arcs
    {
        fl_arc(point(0).x,point(0).y,w,h,30,90);
        fl_arc(point(0).x,point(0).y,w,h,270,330);
        fl_arc(point(0).x,point(0).y,w,h,90,150);
        fl_arc(point(0).x,point(0).y,w,h,210,270);
    }

private:
    int w;
    int h;
};

int main()
{
    using namespace Graph_lib; 

    Box b(Point(100,100),100,50);
    win.attach(b);
    win.wait_for_button();
}

When I ran it I faced this exception:

Unhandled exception at 0x757FE9D7 (ole32.dll) in test.exe: 0xC0000005: Access violation reading location 0x00000004.

I know this refers to declaring Simple_window win(Point(100,100), 600,400, "semi-ellipse"); in global state. But I did that because I had to do it. The problem is that how to attach lines and also object (here b) to Simple_window win in either parts (main() function and also Box struct).

Upvotes: 2

Views: 1064

Answers (3)

Ziezi
Ziezi

Reputation: 6467

Your lines are hard coded and independent of the constructor parameters. They could be drawn using directly the FLTK library, similarly with the arcs and placed inside the inherited from class Shape and overriden function void draw_lines() const. Then you don't need the window object to be pointer.

A possible implementation is:

Box::Box(Point p, int w, int h)
    : width(w), height(h)
{ 
    add(Point(p.x - w, p.y - h));
}

void Box::draw_lines() const
{
    // draw lines with reduced length to adapt for the arcs
    if (color().visibility())
    {
        // upper horizontal
        fl_line(point(0).x + width/4, point(0).y, point(0).x + (3./4.) * width, point(0).y);
        // lower horizontal
        fl_line(point(0).x + width/4, point(0).y + height, point(0).x + (3./4.) * width, point(0).y + height);
        // left vertical 
        fl_line(point(0).x, point(0).y + height/4, point(0).x, point(0).y + (3./4.)*height);
        // right vertical 
        fl_line(point(0).x + width, point(0).y + height/4, point(0).x + width, point(0).y + (3./4.) * height);
    }

    // draw arcs
    if(color().visibility())
    { 
        fl_color(fill_color().as_int());
        // upper left arc
        fl_arc(point(0).x, point(0).y, width/2, height/2, 90, 180); 
        // upper right arc
        fl_arc(point(0).x + width/2, point(0).y, width/2, height/2, 0, 90);
        // down right arc
        fl_arc(point(0).x + width/2, point(0).y + height/2, width/2, height/2, 270, 0); 
        // down left arc
        fl_arc(point(0).x , point(0).y + height/2, width/2, height/2, 180, 270); 
    }
}

Upvotes: 0

user3353819
user3353819

Reputation: 939

You don't need to put anything in global space at all. You want to be passing information to the classes that need them as opposed to needing everything declared in global scope before you do anything with it.

What I write here modifies your Box class so that it also has a private member variable which is a pointer to a Simple_window class. The constructor is modified so that when you construct Box b you have to send it a pointer to the Simple_window in which it will be drawn. When you do this the pointer is assigned the pointer to the then declared Simple_Window win.

#include <Simple_window.h>


struct Box: Shape{

private:
    int w;
    int h;
    Simple_window* window;
public:

    Box(Point p, int ww, int hh,Simple_window* win_): w(ww), h(hh),window(win_)
    { add(Point(p.x-ww,p.y-hh));  }

    void d_l() const        //creating 4 lines
    {
        Line hrz1 (Point(150,100), Point(400,100));
        Line hrz2 (Point(150,300), Point(400,300));
        Line ver1 (Point(507,150), Point(507,250));
        Line ver2 (Point(41,150), Point(41,250));

        window->attach(hrz1);
        window->attach(hrz2);
        window->attach(ver1);
        window->attach(ver2);
    }

    void draw_lines() const      //creating 4 arcs
    {
        fl_arc(point(0).x,point(0).y,w,h,30,90);
        fl_arc(point(0).x,point(0).y,w,h,270,330);
        fl_arc(point(0).x,point(0).y,w,h,90,150);
        fl_arc(point(0).x,point(0).y,w,h,210,270);
    }


};

int main()
{
    using namespace Graph_lib;
    Simple_window* win = new Simple_window(Point(100,100), 600,400, "semi-ellipse");
    Box b(Point(100,100),100,50,win);
    win->attach(b);
    win->wait_for_button();
}

Upvotes: 1

cup
cup

Reputation: 8257

Looks like it is caused by the global creation of win. I have never run an FLTK program where anything graphical is created before main but I'm guessing that sometimes the graphics libs require some things to be in place so it is best to use them after main.

What can you do about it? If win is declared as a pointer and created inside main instead of outside main, then you won't get a crash.

...
Simple_window* win;
struct Box: Shape
{
  ...
   win->...
   ...
}


int main()
{
    win = new Simple_window(Point(100, 100), 600, 400, "semi-ellipse");
    Box b ...
    win->attach ...
    win->wait ...
    delete win;
}

Upvotes: 1

Related Questions