Customize Consent Preferences

We use cookies to help you navigate efficiently and perform certain functions. You will find detailed information about all cookies under each consent category below.

The cookies that are categorized as "Necessary" are stored on your browser as they are essential for enabling the basic functionalities of the site. ... 

Always Active

Necessary cookies are required to enable the basic features of this site, such as providing secure log-in or adjusting your consent preferences. These cookies do not store any personally identifiable data.

No cookies to display.

Functional cookies help perform certain functionalities like sharing the content of the website on social media platforms, collecting feedback, and other third-party features.

No cookies to display.

Analytical cookies are used to understand how visitors interact with the website. These cookies help provide information on metrics such as the number of visitors, bounce rate, traffic source, etc.

No cookies to display.

Performance cookies are used to understand and analyze the key performance indexes of the website which helps in delivering a better user experience for the visitors.

No cookies to display.

Advertisement cookies are used to provide visitors with customized advertisements based on the pages you visited previously and to analyze the effectiveness of the ad campaigns.

No cookies to display.

Skip to content Skip to footer

Разработка собственных компонентов – Захват мыши

В продолжение темы о создании собственных компонентов wxWidgets решил написать эту заметку. Касается наш сегодняшний разговор обработки событий от мыши, а точнее, захвату мыши компонентом при нажатии. Что есть захват мыши? Это когда наш компонент продолжает обрабатывать события, поступающие при передвижении курсора мыши, даже когда сам курсор находится вне компонента.
Для начала создадим простенький компонент и хост-приложение для него:

MouseCaptureTestCtrl.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#ifndef _MOUSE_CAPTURE_TEST_CONTROL_H
#define _MOUSE_CAPTURE_TEST_CONTROL_H
 
#include <wx/wx.h>
 
class MouseCaptureTestControl : public wxControl
{
public:
    MouseCaptureTestControl(wxWindow * parent,
        wxWindowID id = wxID_ANY,
        const wxPoint & pos = wxDefaultPosition,
        const wxSize & size = wxDefaultSize,
        long style = wxNO_BORDER);
    DECLARE_EVENT_TABLE()
    void OnPaint(wxPaintEvent & event);
    void OnEraseBackground(wxEraseEvent & event);
    void OnMouseMove(wxMouseEvent & event);
};
 
#endif

MouseCaptureTestCtrl.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "MouseCaptureTestControl.h"
#include <wx/dcbuffer.h>
 
BEGIN_EVENT_TABLE(MouseCaptureTestControl, wxControl)
EVT_PAINT(MouseCaptureTestControl::OnPaint)
EVT_ERASE_BACKGROUND(MouseCaptureTestControl::OnEraseBackground)
EVT_MOTION(MouseCaptureTestControl::OnMouseMove)
END_EVENT_TABLE()
 
MouseCaptureTestControl::MouseCaptureTestControl(wxWindow * parent,
    wxWindowID id, const wxPoint & pos, const wxSize & size, long style)
    : wxControl(parent, id, pos, size, style)
{
}
 
void MouseCaptureTestControl::OnPaint(wxPaintEvent & event)
{
    wxBufferedPaintDC dc(this);
    dc.SetBackground(wxBrush(GetBackgroundColour()));
    dc.Clear();
    wxPoint pos = ScreenToClient(wxGetMousePosition());
    dc.SetFont(GetFont());
    dc.SetTextForeground(GetForegroundColour());
    dc.DrawLabel(wxString::Format(wxT("%i,%i"), pos.x, pos.y), wxNullBitmap,
        GetClientRect(), wxALIGN_CENTER);
}
 
void MouseCaptureTestControl::OnEraseBackground(wxEraseEvent & event)
{
}
 
void MouseCaptureTestControl::OnMouseMove(wxMouseEvent & event)
{
    Refresh();
}

wxTest.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
#include <wx/wx.h>
#include "MouseCaptureTestControl.h"
 
class MyApp : public wxApp
{
    virtual bool OnInit();
};
 
DECLARE_APP(MyApp);
 
class MyFrame : public wxFrame
{
    void CreateControls();
public:
    bool Create(wxWindow * parent)
    {
        bool res = wxFrame::Create(parent, wxID_ANY, wxT("Da, Yo!"),
            wxDefaultPosition, wxSize(400, 300));
        if(res)
        {
            CreateControls();
        }
        return res;
    }
    MyFrame()
    {
        Create(NULL);
    }
    DECLARE_EVENT_TABLE()
    void OnExit(wxCommandEvent & event)
    {
        Close();
    }
};
 
BEGIN_EVENT_TABLE(MyFrame, wxFrame)
EVT_MENU(wxID_EXIT, MyFrame::OnExit)
END_EVENT_TABLE()
 
 
void MyFrame::CreateControls()
{
    wxMenuBar * menuBar = new wxMenuBar;
    SetMenuBar(menuBar);
 
    wxMenu * fileMenu = new wxMenu;
    fileMenu->Append(wxID_EXIT, _("Exit\tAlt+F4"));
    menuBar->Append(fileMenu, _("File"));
 
    wxBoxSizer * sizer = new wxBoxSizer(wxVERTICAL);
    SetSizer(sizer);
 
    MouseCaptureTestControl * control = new MouseCaptureTestControl(this, wxID_ANY);
    sizer->Add(control, 1, wxEXPAND);
 
    CreateStatusBar();
}
 
bool MyApp::OnInit()
{
    MyFrame * frame = new MyFrame;
    SetTopWindow(frame);
    frame->Centre();
    frame->Show();
    return true;
}
 
IMPLEMENT_APP(MyApp);

Итак, что же у нас получилось. У нас получился новый компонент, который при перемещении над ним курсора мыши отображает координаты мыши.

Для того чтобы наш компонент продолжал обрабатывать событие wxEVT_MOTION даже когда курсор находится вне компонента нам необходимо добавить пару обработчиков – обработчики нажатия и отжатия левой кнопки мыши.

MouseCaptureTestCtrl.h

1
2
3
4
5
6
7
8
9
...
class MouseCaptureTestControl : public wxControl
{
    DECLARE_EVENT_TABLE()
    ...
    void OnLeftMouseDown(wxMouseEvent & event);
    void OnLeftMouseUp(wxMouseEvent & event);
};
...

MouseCaptureTestCtrl.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
...
BEGIN_EVENT_TABLE(MouseCaptureTestControl, wxControl)
...
EVT_LEFT_DOWN(MouseCaptureTestControl::OnLeftMouseDown)
EVT_LEFT_UP(MouseCaptureTestControl::OnLeftMouseUp)
END_EVENT_TABLE()
...
void MouseCaptureTestControl::OnLeftMouseDown(wxMouseEvent & event)
{
    CaptureMouse();
}
 
void MouseCaptureTestControl::OnLeftMouseUp(wxMouseEvent & event)
{
    ReleaseMouse();
}

Когда пользователь нажимает левой кнопкой мыши на компоненте, происходит захват мыши, и пока кнопка не будет отжата, компонент будет отрисовывать новые значения координат мыши при перемещении курсора. Такой функционал может быть востребован при разработке, например, графических редакторов, когда курсор мыши может выходить за пределы области рисования. Вот это мы сейчас и рассмотрим на простеньком примере.

MouseCaptureTestCtrl.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
#include <wx/dynarray.h>
 
class MyLine
{
    wxPoint start;
    wxPoint end;
    MyLine(wxPoint s, wxPoint e) : start(s), end(e) {}
    void Draw(wxDC & dc)
    {
        dc.DrawLine(start, end);
    }
};
 
WX_DECLARE_OBJARRAY(MyLine, MyLineArray);
 
class MouseCaptureTestControl : public wxControl
{
    wxPoint m_LineStart;
    MyLineArray m_Lines;
...
};
...

MouseCaptureTestCtrl.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
...
#include <wx/arrimpl.cpp>
 
WX_DEFINE_OBJARRAY(MyLineArray)
 
...
void MouseCaptureTestControl::OnPaint(wxPaintEvent & event)
{
    wxBufferedPaintDC dc(this);
    dc.SetBackground(wxBrush(GetBackgroundColour()));
    dc.Clear();
    wxPoint pos = ScreenToClient(wxGetMousePosition());
    dc.SetFont(GetFont());
    dc.SetTextForeground(GetForegroundColour());
    dc.DrawLabel(wxString::Format(wxT("%i,%i"), pos.x, pos.y), wxNullBitmap,
        GetClientRect(), wxALIGN_CENTER);
    for(size_t i = 0; i < m_Lines.Count(); i++)
    {
        m_Lines&#91;i&#93;.Draw(dc);
    }
}
...
void MouseCaptureTestControl::OnLeftMouseDown(wxMouseEvent & event)
{
    CaptureMouse();
    m_LineStart = event.GetPosition();
}
 
void MouseCaptureTestControl::OnLeftMouseUp(wxMouseEvent & event)
{
    if(GetCapture() == this)
    {
        m_Lines.Add(MyLine(m_LineStart, event.GetPosition()));
    }
    ReleaseMouse();
    Refresh();
}
&#91;/sourcecode&#93;
Итак, что у нас получилось. Мы создали новый класс <code>MyLine</code> и добавили в наш компонент массив объектов этого класса. При нажатии кнопки мыши мы запоминаем координату, где было произведено нажатие, а пи отжатии добавляем в массив новую линию, концы которой соответствуют точке нажатия и отжатия кнопки мыши. Ну и сам компонент отрисовывает все линии в обработчике события <code>wxEVT_PAINT</code>.
 
Все это чудесно, но чего-то не хватает. А не хватает у нас отрисовки создаваемой линии в процессе перемещения курсора при нажатой левой кнопке.  Для того чтобы добавить эту отрисовку нужно дописать несколько строк:
 
<b>MouseCaptureTestCtrl.cpp</b>
[sourcecode language="cpp"]
...
void MouseCaptureTestControl::OnPaint(wxPaintEvent & event)
{
    ...
    if(GetCapture() == this)
    {
        MyLine(m_LineStart, pos).Draw(dc);
    }
}
...

Ну вот, как видно, линия продолжает отрисовываться даже когда курсор находится за пределами компонента, что, собственно, и нужно было продемонстрировать.

Скачать исходный код примера.

Leave a comment

0.0/5