使用c ++中的wxwidget,使用可拖动的矩形从图像中选择一个区域

时间:2016-06-21 07:20:33

标签: c++ wxwidgets

我使用wxwidgets在c ++中编写了一个程序。我在图像上放置了一个矩形,并希望选择矩形覆盖的图像部分,矩形应该是可拖动的。但问题是,当我单击鼠标时,图像消失,唯一的矩形(可以拖动)仍然存在,反之亦然。

`

class BasicDrawPane : public wxPanel
{

public:
    BasicDrawPane();
    BasicDrawPane(wxFrame* parent);

  void paintEvent(wxPaintEvent & evt);

    void render(wxDC& dc);
    void mouseMoved(wxMouseEvent& event);
    void mouseDown(wxMouseEvent& event);
    void mouseWheelMoved(wxMouseEvent& event);
    void mouseReleased(wxMouseEvent& event);
    void rightClick(wxMouseEvent& event);
    void mouseLeftWindow(wxMouseEvent& event);
    DECLARE_EVENT_TABLE()

};
class MyFrame: public wxFrame{
public:
    MyFrame(const wxString& title, const wxPoint& pos, const wxSize& size);
    wxString path;
    BasicDrawPane panel;
private:
    void OnHello(wxCommandEvent& event);
    void OnExit(wxCommandEvent& event);
    void OnAbout(wxCommandEvent& event);
    void OnOpen(wxCommandEvent& event);
    void OnPaint(wxCommandEvent& event);
    void OnRect(wxCommandEvent& event);
    void OnSave(wxCommandEvent& event);

    DECLARE_EVENT_TABLE();

    wxBitmap bmp;
    wxMemoryDC memDC;
};

enum
{
    ID_Hello = 1, ID_PAINT = 2, ID_RECT = 3, ID_SAVE = 4

};
BEGIN_EVENT_TABLE( MyFrame, wxFrame )
    EVT_MENU(ID_Hello,MyFrame::OnHello)
    EVT_MENU(wxID_EXIT,MyFrame::OnExit)
    EVT_MENU(wxID_ABOUT,MyFrame::OnAbout)
    EVT_MENU(wxID_OPEN,MyFrame::OnOpen)
    EVT_MENU(ID_PAINT,MyFrame::OnPaint)
    EVT_MENU(ID_RECT,MyFrame::OnRect)
    EVT_MENU(ID_SAVE,MyFrame::OnSave)

END_EVENT_TABLE()
void MyFrame::OnPaint(wxCommandEvent& event)
{
    //wxPaintDC dc( this );
    //dc.DrawBitmap( m_bitmap, 0, 0, true /* use mask */ );

    //wxStaticBitmap *b1 = new wxStaticBitmap(this, -1, wxBitmap(wxImage(path)));



    bmp.LoadFile((path),wxBITMAP_TYPE_ANY);
//    bmp.LoadFile((path),wxBITMAP_TYPE_PNG);

    memDC.SelectObject( bmp );

   //memDC.SetBackground(*wxWHITE_BRUSH);
    //memDC.Clear();
 /*  memDC.SetPen(*wxGREEN_PEN);
    memDC.SetBrush(*wxTRANSPARENT_BRUSH);
   memDC.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );*/
    //Check();
    memDC.SelectObject(wxNullBitmap);

   // wxSize sz(512,384);
  // wxSize sz(900,600);
   wxStaticBitmap *b1 = new wxStaticBitmap(/*  dynamic_cast<wxFrame*>*/this, -1, bmp, wxDefaultPosition);

   Refresh();

}
class MyApp: public wxApp
{
public:
    virtual bool OnInit();
    //MyFrame *frame;
    BasicDrawPane * drawPane;
  };

IMPLEMENT_APP(MyApp)


bool MyApp::OnInit()
{
  //  wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL);
    //frame = new MyFrame((wxFrame *)NULL, -1,  wxT("Hello wxDC"), wxPoint(50,50), wxSize(800,600));
    MyFrame *frame = new MyFrame( _T("Hello World"), wxPoint(50, 50), wxSize(600, 600) );
 //  drawPane = new BasicDrawPane( (wxFrame*) frame );
  // sizer->Add(drawPane, 1, wxEXPAND);

    //frame->SetSizer(sizer);
 // /* dynamic_cast<wxFrame*>(this)*/ frame-> SetAutoLayout(true);
   /* dynamic_cast<wxFrame*>(this)*/frame -> Show();
    return true;
}

BEGIN_EVENT_TABLE(BasicDrawPane, wxPanel)

EVT_MOTION(BasicDrawPane::mouseMoved)
EVT_LEFT_DOWN(BasicDrawPane::mouseDown)
EVT_LEFT_UP(BasicDrawPane::mouseReleased)
EVT_RIGHT_DOWN(BasicDrawPane::rightClick)
EVT_LEAVE_WINDOW(BasicDrawPane::mouseLeftWindow)
EVT_MOUSEWHEEL(BasicDrawPane::mouseWheelMoved)
EVT_PAINT(BasicDrawPane::paintEvent)
// catch paint events


END_EVENT_TABLE()




void BasicDrawPane::mouseDown(wxMouseEvent& event)
{
   /* if (event.GetPosition().x >= m_x && event.GetPosition().x <= m_x + WIDTH &&
        event.GetPosition().y >= m_y && event.GetPosition().y <= m_y + HEIGHT)
    {
        m_dragging = true;
        m_previous_mouse_x = event.GetPosition().x;
        m_previous_mouse_y = event.GetPosition().y;
    }*/
}
void BasicDrawPane::mouseWheelMoved(wxMouseEvent& event) {}

void BasicDrawPane::mouseReleased(wxMouseEvent& event)
{
    m_dragging = true;
}

void BasicDrawPane::mouseMoved(wxMouseEvent& event)
{
   if (m_dragging && event.Dragging())
    {
       int delta_x = event.GetPosition().x - m_previous_mouse_x;
        int delta_y = event.GetPosition().y - m_previous_mouse_y;

       m_x += delta_x;
        m_y += delta_y;

        m_previous_mouse_x = event.GetPosition().x;
        m_previous_mouse_y = event.GetPosition().y;
        // trigger paint event
        Refresh();

    }
}

void BasicDrawPane::mouseLeftWindow(wxMouseEvent& event)
{
    m_dragging = true;
}

void BasicDrawPane::rightClick(wxMouseEvent& event) {}
BasicDrawPane::BasicDrawPane(wxFrame* parent) :
wxPanel(parent)
{
//    m_dragging = true;
//    m_x = 100;
//    m_y = 100;
}

/*
 * Called by the system of by wxWidgets when the panel needs
 * to be redrawn. You can also trigger this call by
 * calling Refresh()/Update().
 */
void BasicDrawPane::paintEvent(wxPaintEvent & evt)
{
 //wxCommandEvent w1(wxEVT_NULL, ID_PAINT);
    //OnPaint(w1);
  wxPaintDC dc(this);
   render(dc);
}


void BasicDrawPane::render(wxDC& dc)
{
    dc.SetPen(*wxGREEN_PEN);
    dc.SetBrush(*wxTRANSPARENT_BRUSH);
   dc.DrawRectangle( m_x, m_y, WIDTH, HEIGHT );
}

`

1 个答案:

答案 0 :(得分:0)

为了回答这个问题,有几件事需要解释,所以我会一次拿一个。我认为你的基本想法是可以的,所以我不会详细介绍如何进行实际选择等。

首先,我建议使用Connect()Bind()代替事件表。这允许您将子窗口事件连接回父窗口并在一个位置处理它们。

例如,如果您的主框架类名为MainFrame并且您有一个名为wxPanel的{​​{1}}成员,则可以在MainFrame ctor中使用:

m_DrawPanel

注意:我添加了MainFrame::MainFrame(wxWindow* parent) { // Connect mouse event handlers. m_DrawPanel->Connect(wxEVT_LEFT_DOWN, wxMouseEventHandler(MainFrame::OnPanelLDown), NULL, this); m_DrawPanel->Connect(wxEVT_LEFT_UP, wxMouseEventHandler(MainFrame::OnPanelLUp), NULL, this); m_DrawPanel->Connect(wxEVT_MOTION, wxMouseEventHandler(MainFrame::OnPanelMotion), NULL, this); // Connect paint and erase handlers. m_DrawPanel->Connect(wxEVT_PAINT, wxPaintEventHandler(MainFrame::OnPanelPaint), NULL, this); m_DrawPanel->Connect(wxEVT_ERASE_BACKGROUND, wxEraseEventHandler(MainFrame::OnPanelErase), NULL, this); // Load the bitmap and set the mode to 'not currently selecting'. m_Picture.LoadFile ("wxwidgets.png", wxBITMAP_TYPE_PNG); m_SelectionMode = false; } 事件覆盖,因为否则会清除面板导致闪烁(这是一种简单的方法)。

3个鼠标事件处理程序可以实现您的选择逻辑(我认为这基本上就是您想要的):

wxEVT_ERASE_BACKGROUND

如前所述,覆盖面板的void MainFrame::OnPanelLDown(wxMouseEvent& event) { m_SelectionMode = true; m_SelectionRect = wxRect(event.GetPosition(), wxSize(0, 0)); } void MainFrame::OnPanelLUp(wxMouseEvent& event) { m_SelectionMode = false; // ... handle what to do with the selection here // (selected area is defined by m_SelectionRect). // ... // Zero the selection rectangle for neatness (not really required). m_SelectionRect = wxRect (); } void MainFrame::OnPanelMotion(wxMouseEvent& event) { m_SelectionRect = wxRect(m_SelectionRect.GetTopLeft(), event.GetPosition()); // Call Refresh() to trigger a paint event. m_mainPanel->Refresh(); } 事件无所作为:

wxEVT_ERASE_BACKGROUND

最后,我认为这是你在问题中提出的问题(我包括其他人帮你建立一个工作程序):

void MainFrame::OnPanelErase(wxEraseEvent& event)
{
}

这是一个paint事件处理程序,所以首先我们需要创建一个void MainFrame::OnPanelPaint(wxPaintEvent& event) { // Obtain a wxPaintDC. wxPaintDC pdc (m_mainPanel); // Draw our image. pdc.DrawBitmap(m_Picture, wxPoint(0, 0)); // If the user is currently selecting (left mouse button is down) // then draw the selection rectangle. if (m_SelectionMode) { pdc.SetPen(*wxRED_PEN); pdc.SetBrush(*wxTRANSPARENT_BRUSH); pdc.DrawRectangle(m_SelectionRect); } } 上下文。接下来,我们绘制位图,这样可以确保每次刷新并且不会因鼠标移动,调整大小或拖动其他窗口等而损坏。最后,如果用户当前正在按下左键移动鼠标,则绘制选择矩形

还有很多其他方法可以实现同样的目标。其中一些可能更好,或更有效,但这是一个简单的工作方式,直到你更熟悉wxWidgets。