Bezier curve control

Are you writing your own components and need help with how to set them up or have questions about the components you are deriving from ? Ask them here.
Post Reply
NoeMurr
Knows some wx things
Knows some wx things
Posts: 32
Joined: Sat Mar 31, 2018 2:26 pm

Bezier curve control

Post by NoeMurr »

Hi all,
I'm writing an application that needs to print a Bezier curve on a panel. That curves needs to be clickable, movable, etc. so I need it to be a "control", but wxControl has a rectangular shape and my curve, of course, cannot be wrapped in a rectangle.

Is there a way to have a custom control that does not have rectangular shape?
New Pagodi
Super wx Problem Solver
Super wx Problem Solver
Posts: 466
Joined: Tue Jun 20, 2006 6:47 pm
Contact:

Re: Bezier curve control

Post by New Pagodi »

Here's one approach for drawing a dragable curve on a panel. The idea is to keep track of the points in a vector and handle the mouse events for adding or dragging points.

Code: Select all

// For compilers that support precompilation, includes "wx/wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

// for all others, include the necessary headers (this file is usually all you
// need because it includes almost all "standard" wxWidgets headers)
#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif

class myFrame : public wxFrame
{
    public:
        myFrame( wxWindow* parent, int id = wxID_ANY, wxString title = "Demo"
                , wxPoint pos = wxDefaultPosition, wxSize size = wxDefaultSize
                , int style = wxDEFAULT_FRAME_STYLE|wxTAB_TRAVERSAL );
    private:
        void OnLeftDown( wxMouseEvent& event );
        void OnLeftUp( wxMouseEvent& event );
        void OnMotion( wxMouseEvent& event );
        void OnPaint( wxPaintEvent& event );

        std::vector<wxPoint> m_points;
        std::vector<wxPoint>::iterator m_selection;
        wxPanel* m_panel;
};


myFrame::myFrame( wxWindow* parent, int id, wxString title, wxPoint pos
                 , wxSize size, int style )
        :wxFrame( parent, id, title, pos, size, style )
{
    m_selection=m_points.end();
    m_panel = new wxPanel(this);

    m_panel->Bind( wxEVT_LEFT_DOWN, &myFrame::OnLeftDown, this );
    m_panel->Bind( wxEVT_LEFT_UP, &myFrame::OnLeftUp, this );
    m_panel->Bind( wxEVT_MOTION, &myFrame::OnMotion, this );
    m_panel->Bind( wxEVT_PAINT, &myFrame::OnPaint, this );
}

void myFrame::OnLeftDown( wxMouseEvent& event )
{
    wxPoint p = event.GetPosition();

    for (std::vector<wxPoint>::iterator it=m_points.begin();it!=m_points.end();++it)
    {
        if ( std::abs(it->x-p.x) + std::abs(it->y-p.y) < 8 )
        {
            m_selection=it;
            m_selection->x=p.x;
            m_selection->y=p.y;
        }
    }

    if (m_selection==m_points.end())
    {
        m_points.push_back(p);
        m_selection = m_points.end();
        --m_selection;
    }
    m_panel->Refresh();
}

void myFrame::OnLeftUp( wxMouseEvent& event )
{
    m_selection=m_points.end();
    m_panel->Refresh();
}

void myFrame::OnMotion( wxMouseEvent& event )
{
    if (event.LeftIsDown() && m_selection!=m_points.end())
    {
        wxPoint p = event.GetPosition();
        m_selection->x=p.x;
        m_selection->y=p.y;
        m_panel->Refresh();
    }
}

void myFrame::OnPaint( wxPaintEvent& event )
{
    wxPaintDC dc(m_panel);
    dc.Clear();

    dc.SetPen(*wxBLACK_PEN);
    dc.SetBrush(*wxWHITE_BRUSH);

    if (m_points.size()>2)
    {
        dc.DrawSpline(m_points.size(),&(m_points[0]));
    }

    for (std::vector<wxPoint>::iterator it=m_points.begin();it!=m_points.end();++it)
    {
        dc.DrawCircle(*it, 4);
    }

    if ( m_selection!=m_points.end() )
    {
        dc.SetPen(*wxRED_PEN);
        dc.SetBrush(*wxRED_BRUSH);
        dc.DrawCircle(*m_selection, 4);
    }
}

class myApp : public wxApp
{
    public:
        virtual bool OnInit()
        {
            myFrame* frame = new myFrame(NULL);
            frame->Show();
            return true;
        }
};

wxIMPLEMENT_APP(myApp);
bez.png
bez.png (2.31 KiB) Viewed 11973 times
This obviously isn't complete. I know the above code will have problems when the mouse leaves the window. To fix this, either the mouse should be captured in the left down event or an event handler for the wxEVT_LEAVE_WINDOW event should be added. There may be other problems as well.
ONEEYEMAN
Part Of The Furniture
Part Of The Furniture
Posts: 7459
Joined: Sat Apr 16, 2005 7:22 am
Location: USA, Ukraine

Re: Bezier curve control

Post by ONEEYEMAN »

Hi,
The best way is to use a pre-written library for such stuff.

For wxWidgets, there are wxArt2D, wxShapeFramework and wxWorkspaceView (ref. https://wiki.wxwidgets.org/WxFAQ#How_ca ... d_nodes.3F).

Thank you.
Post Reply