Cross-Platform Programming with wxWidgets
Just Make It Cross-Platform
Subscribe to Feed
  • Home
  • Projects
  • Links

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

Uncategorized Add comments |

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

MouseCaptureTestCtrl.h

#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

#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

#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

...
class MouseCaptureTestControl : public wxControl
{
	DECLARE_EVENT_TABLE()
	...
	void OnLeftMouseDown(wxMouseEvent & event);
	void OnLeftMouseUp(wxMouseEvent & event);
};
...

MouseCaptureTestCtrl.cpp

...
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

...
#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

...
#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[i].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();
}

Итак, что у нас получилось. Мы создали новый класс MyLine и добавили в наш компонент массив объектов этого класса. При нажатии кнопки мыши мы запоминаем координату, где было произведено нажатие, а пи отжатии добавляем в массив новую линию, концы которой соответствуют точке нажатия и отжатия кнопки мыши. Ну и сам компонент отрисовывает все линии в обработчике события wxEVT_PAINT.


Все это чудесно, но чего-то не хватает. А не хватает у нас отрисовки создаваемой линии в процессе перемещения курсора при нажатой левой кнопке. Для того чтобы добавить эту отрисовку нужно дописать несколько строк:

MouseCaptureTestCtrl.cpp

...
void MouseCaptureTestControl::OnPaint(wxPaintEvent & event)
{
	...
	if(GetCapture() == this)
	{
		MyLine(m_LineStart, pos).Draw(dc);
	}
}
...

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

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


December 3rd, 2007 |

Tags: wxWidgets, Статьи

Related Posts

  • Перевод книги Julian’а Smart’а – Глава II – Начало
  • Разработка собственных компонентов – Оптимизация отрисовки графики
  • Перевод книги Julian’а Smart’а – Глава III – Обработка сообщений
  • Кросс-платформенная справочная система для кросс-платформенных приложений – Часть II
  • Кросс-платформенная справочная система для кросс-платформенных приложений – Часть I

Leave a Reply

  • This blog is about…

    Библиотека Книги Статьи Articles Code::Blocks Components Controls Database DatabaseLayer Document/View Eclipse Localization NetBeans Networking News Printing Reports SQLite Tutorilas Video Visual Studio wxAUI wxButton wxDev-CPP wxGrid wxHelpController wxJavaScript wxJSON wxLocale wxLog wxPaintDC wxPropertyGrid wxRuby wxSQLite3 wxThread wxValidator wxWidgets wxWinCE wxZipInputStream wxZipOutputStream XML
  • Showcase

    Visit wxToolBox Homepage

    Buy wxToolBox (with source code)

  • Archives

    • November 2009
    • September 2009
    • August 2009
    • May 2009
    • April 2009
    • March 2009
    • February 2009
    • January 2009
    • December 2008
    • September 2008
    • August 2008
    • July 2008
    • June 2008
    • May 2008
    • April 2008
    • March 2008
    • February 2008
    • January 2008
    • December 2007
    • June 2007
    • May 2007
    • January 2007
  • Recent Comments

    • T-Rex on Сделайте мне красиво – Часть II – wxAUI в Multi-View приложений
    • Vanya on Сделайте мне красиво – Часть II – wxAUI в Multi-View приложений
    • Sash on wxWidgets-2.8 and Code::Blocks (Windows)
    • T-Rex on Быстрый способ упаковки содержимого папки в ZIP-архив
    • Gerald on Быстрый способ упаковки содержимого папки в ZIP-архив
  • Buttons

    Locations of visitors to this page

    Rambler's Top100
    Рейтинг@Mail.ru

Copyright © 2010 Cross-Platform Programming with wxWidgets All Rights Reserved
RSS Log in