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?
Bezier curve control
-
- Super wx Problem Solver
- Posts: 469
- Joined: Tue Jun 20, 2006 6:47 pm
- Contact:
Re: Bezier curve control
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.
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.
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);
Re: Bezier curve control
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.
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.