Разработчики OpenNETCF выпустили новую версию библиотеки Smart Device Framework, которая содержит множество полезных классов, значительно упрощающих разработку приложений для Windows Mobile на платформе .NET. Есть бесплатная версия Smart Device Framework. По большому счету из недостатков бесплатной версии по сравнению с платными можно назвать отсутствие интеграции с Visual Studio и дизайнером форм.

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

Previous ArticleNext Article
Технический директор IT-Dimension, компании-разработчика кросс-платформенного программного обеспечения

Leave a Reply

Your email address will not be published. Required fields are marked *

Р.

Рисуем градиентные кнопки

Несколько дней назад наткнулся на пост How to draw gradient buttons в блоге Native Mobile. На вид неплохо, но использование функции GradientFill() показалось мне не очень удобным, т.к. для ее использования приходится заполнять кучу полей в структурах TRIVERTEX.

Существует возможность создать подобные кнопки намного проще с использованием библиотеки wxWidgets.


wxBufferedPaintDC dc(this);

wxRect clientRect = GetClientRect();
wxRect gradientRect = clientRect;
gradientRect.SetHeight(gradientRect.GetHeight()/2);
dc.GradientFillLinear(gradientRect,
wxColour(132,125,132), wxColour(74,69,74), wxSOUTH);
gradientRect.Offset(0, gradientRect.GetHeight());
dc.GradientFillLinear(gradientRect,
wxColour(0,0,0), wxColour(57,56,57), wxSOUTH);

dc.SetPen(wxPen(GetBackgroundColour()));
dc.SetBrush(*wxTRANSPARENT_BRUSH);
dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
dc.SetFont(GetFont());
dc.SetTextForeground(GetForegroundColour());
dc.DrawLabel(m_Label, clientRect,
wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);

После нескольких несложных экспериментов я решил написать простенький компонент, представляющий собой кнопку с градиентом. Код компонента приведен ниже:

wxGradientButton.h

/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.h
// Purpose:     
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by: 
// Created:     01/08/2008 20:25:42
// RCS-ID:      
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:     
/////////////////////////////////////////////////////////////////////////////

#ifndef _WXGRADIENTBUTTON_H_
#define _WXGRADIENTBUTTON_H_


/*!
 * Includes
 */

////@begin includes
////@end includes

/*!
 * Forward declarations
 */

////@begin forward declarations
class wxGradientButton;
////@end forward declarations

/*!
 * Control identifiers
 */

////@begin control identifiers
#define ID_WXGRADIENTBUTTON 10003
#define SYMBOL_WXGRADIENTBUTTON_STYLE wxSIMPLE_BORDER|wxFULL_REPAINT_ON_RESIZE
#define SYMBOL_WXGRADIENTBUTTON_IDNAME ID_WXGRADIENTBUTTON
#define SYMBOL_WXGRADIENTBUTTON_SIZE wxSize(100, 100)
#define SYMBOL_WXGRADIENTBUTTON_POSITION wxDefaultPosition
////@end control identifiers


/*!
 * wxGradientButton class declaration
 */

class wxGradientButton: public wxWindow
{    
    DECLARE_DYNAMIC_CLASS( wxGradientButton )
    DECLARE_EVENT_TABLE()

	wxSize DoGetBestSize() const;
public:
    /// Constructors
    wxGradientButton();
    wxGradientButton(wxWindow* parent, wxWindowID id = ID_WXGRADIENTBUTTON, const wxString & label = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(100, 100), long style = wxSIMPLE_BORDER);

    /// Creation
    bool Create(wxWindow* parent, wxWindowID id = ID_WXGRADIENTBUTTON, const wxString & label = wxEmptyString, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize(100, 100), long style = wxSIMPLE_BORDER);

    /// Destructor
    ~wxGradientButton();

    /// Initialises member variables
    void Init();

    /// Creates the controls and sizers
    void CreateControls();

////@begin wxGradientButton event handler declarations

    /// wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
    void OnSize( wxSizeEvent& event );

    /// wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
    void OnPaint( wxPaintEvent& event );

    /// wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
    void OnEraseBackground( wxEraseEvent& event );

    /// wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
    void OnLeftDown( wxMouseEvent& event );

    /// wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
    void OnLeftUp( wxMouseEvent& event );

////@end wxGradientButton event handler declarations

////@begin wxGradientButton member function declarations

    wxString GetLabel() const { return m_Label ; }
    void SetLabel(wxString value) { m_Label = value ; }

    wxColour GetGradientTopStartColour() const { return m_GradientTopStartColour ; }
    void SetGradientTopStartColour(wxColour value) { m_GradientTopStartColour = value ; }

    wxColour GetGradientTopEndColour() const { return m_GradientTopEndColour ; }
    void SetGradientTopEndColour(wxColour value) { m_GradientTopEndColour = value ; }

    wxColour GetGradientBottomStartColour() const { return m_GradientBottomStartColour ; }
    void SetGradientBottomStartColour(wxColour value) { m_GradientBottomStartColour = value ; }

    wxColour GetGradientBottomEndColour() const { return m_GradientBottomEndColour ; }
    void SetGradientBottomEndColour(wxColour value) { m_GradientBottomEndColour = value ; }

    wxColour GetPressedColourTop() const { return m_PressedColourTop ; }
    void SetPressedColourTop(wxColour value) { m_PressedColourTop = value ; }

    wxColour GetPressedColourBottom() const { return m_PressedColourBottom ; }
    void SetPressedColourBottom(wxColour value) { m_PressedColourBottom = value ; }

    /// Retrieves bitmap resources
    wxBitmap GetBitmapResource( const wxString& name );

    /// Retrieves icon resources
    wxIcon GetIconResource( const wxString& name );
////@end wxGradientButton member function declarations

    /// Should we show tooltips?
    static bool ShowToolTips();

////@begin wxGradientButton member variables
    wxString m_Label;
    wxColour m_GradientTopStartColour;
    wxColour m_GradientTopEndColour;
    wxColour m_GradientBottomStartColour;
    wxColour m_GradientBottomEndColour;
    wxColour m_PressedColourTop;
    wxColour m_PressedColourBottom;
////@end wxGradientButton member variables
};

#endif
    // _WXGRADIENTBUTTON_H_

wxGradientButton.cpp

/////////////////////////////////////////////////////////////////////////////
// Name:        wxGradientButton.cpp
// Purpose:     
// Author:      Volodymir (T-Rex) Tryapichko
// Modified by: 
// Created:     01/08/2008 20:25:42
// RCS-ID:      
// Copyright:   Volodymir (T-Rex) Tryapichko, 2008
// Licence:     
/////////////////////////////////////////////////////////////////////////////

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

#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif

////@begin includes
////@end includes

#include "wxGradientButton.h"
#include <wx/dcbuffer.h>

////@begin XPM images
////@end XPM images


/*!
 * wxGradientButton type definition
 */

IMPLEMENT_DYNAMIC_CLASS( wxGradientButton, wxWindow )


/*!
 * wxGradientButton event table definition
 */

BEGIN_EVENT_TABLE( wxGradientButton, wxWindow )

////@begin wxGradientButton event table entries
    EVT_SIZE( wxGradientButton::OnSize )
    EVT_PAINT( wxGradientButton::OnPaint )
    EVT_ERASE_BACKGROUND( wxGradientButton::OnEraseBackground )
    EVT_LEFT_DOWN( wxGradientButton::OnLeftDown )
    EVT_LEFT_UP( wxGradientButton::OnLeftUp )

////@end wxGradientButton event table entries

END_EVENT_TABLE()


/*!
 * wxGradientButton constructors
 */

wxGradientButton::wxGradientButton()
{
    Init();
}

wxGradientButton::wxGradientButton(wxWindow* parent, wxWindowID id, const wxString & label, const wxPoint& pos, const wxSize& size, long style)
{
    Init();
    Create(parent, id, label, pos, size, style);
}


/*!
 * wxGradientButton creator
 */

bool wxGradientButton::Create(wxWindow* parent, wxWindowID id, const wxString & label, const wxPoint& pos, const wxSize& size, long style)
{
////@begin wxGradientButton creation
    wxWindow::Create(parent, id, pos, size, style);
    CreateControls();
////@end wxGradientButton creation
    m_Label = label;
    return true;
}


/*!
 * wxGradientButton destructor
 */

wxGradientButton::~wxGradientButton()
{
////@begin wxGradientButton destruction
////@end wxGradientButton destruction
}


/*!
 * Member initialisation
 */

void wxGradientButton::Init()
{
////@begin wxGradientButton member initialisation
    m_GradientTopStartColour = wxColour(132,125,132);
    m_GradientTopEndColour = wxColour(74,69,74);
    m_GradientBottomStartColour = wxColour(0,0,0);
    m_GradientBottomEndColour = wxColour(57,56,57);
    m_PressedColourTop = wxColour(57,56,57);
    m_PressedColourBottom = wxColour(0,0,0);
////@end wxGradientButton member initialisation
}


/*!
 * Control creation for wxGradientButton
 */

void wxGradientButton::CreateControls()
{    
////@begin wxGradientButton content construction
    this->SetForegroundColour(wxColour(255, 255, 255));
    this->SetBackgroundColour(wxColour(0, 0, 0));
    this->SetFont(wxFont(8, wxSWISS, wxNORMAL, wxBOLD, false, wxT("Tahoma")));
////@end wxGradientButton content construction
}


/*!
 * Should we show tooltips?
 */

bool wxGradientButton::ShowToolTips()
{
    return true;
}

/*!
 * Get bitmap resources
 */

wxBitmap wxGradientButton::GetBitmapResource( const wxString& name )
{
    // Bitmap retrieval
////@begin wxGradientButton bitmap retrieval
    wxUnusedVar(name);
    return wxNullBitmap;
////@end wxGradientButton bitmap retrieval
}

/*!
 * Get icon resources
 */

wxIcon wxGradientButton::GetIconResource( const wxString& name )
{
    // Icon retrieval
////@begin wxGradientButton icon retrieval
    wxUnusedVar(name);
    return wxNullIcon;
////@end wxGradientButton icon retrieval
}

wxSize wxGradientButton::DoGetBestSize() const
{
	wxSize labelSize = wxDefaultSize;
	GetTextExtent(m_Label, &labelSize.x, &labelSize.y);
	return wxSize(wxMax(40, labelSize.x + 20), wxMax(20, labelSize.y + 10));
}


/*!
 * wxEVT_PAINT event handler for ID_WXGRADIENTBUTTON
 */

void wxGradientButton::OnPaint( wxPaintEvent& event )
{
    // Before editing this code, remove the block markers.
    wxBufferedPaintDC dc(this);

	wxRect clientRect = GetClientRect();
	wxRect gradientRect = clientRect;
	gradientRect.SetHeight(gradientRect.GetHeight()/2 + ((GetCapture() == this) ? 1 : 0));
	if(GetCapture() != this)
	{
		dc.GradientFillLinear(gradientRect, 
			m_GradientTopStartColour, m_GradientTopEndColour, wxSOUTH);
	}
	else
	{
		dc.SetPen(wxPen(m_PressedColourTop));
		dc.SetBrush(wxBrush(m_PressedColourTop));
		dc.DrawRectangle(gradientRect);
	}

	gradientRect.Offset(0, gradientRect.GetHeight());

	if(GetCapture() != this)
	{
		dc.GradientFillLinear(gradientRect, 
			m_GradientBottomStartColour, m_GradientBottomEndColour, wxSOUTH);
	}
	else
	{
		dc.SetPen(wxPen(m_PressedColourBottom));
		dc.SetBrush(wxBrush(m_PressedColourBottom));
		dc.DrawRectangle(gradientRect);
	}
	dc.SetPen(wxPen(GetBackgroundColour()));
	dc.SetBrush(*wxTRANSPARENT_BRUSH);
	dc.DrawRectangle(0, 0, clientRect.GetWidth(), clientRect.GetHeight());
	dc.SetFont(GetFont());
	dc.SetTextForeground(GetForegroundColour());
	if(GetCapture() == this)
	{
		clientRect.Offset(1, 1);
	}
	dc.DrawLabel(m_Label, clientRect, wxALIGN_CENTER_HORIZONTAL|wxALIGN_CENTER_VERTICAL);
}


/*!
 * wxEVT_LEFT_DOWN event handler for ID_WXGRADIENTBUTTON
 */

void wxGradientButton::OnLeftDown( wxMouseEvent& event )
{
	if(GetCapture() != this)
	{
		CaptureMouse();
		Refresh();
	}
}


/*!
 * wxEVT_LEFT_UP event handler for ID_WXGRADIENTBUTTON
 */

void wxGradientButton::OnLeftUp( wxMouseEvent& event )
{
	if(GetCapture() == this)
	{
		ReleaseMouse();
		Refresh();
		if(GetClientRect().Contains(event.GetPosition()))
		{
			wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, GetId());
			GetEventHandler()->AddPendingEvent(evt);
		}
	}
}


/*!
 * wxEVT_ERASE_BACKGROUND event handler for ID_WXGRADIENTBUTTON
 */

void wxGradientButton::OnEraseBackground( wxEraseEvent& event )
{
}


/*!
 * wxEVT_SIZE event handler for ID_WXGRADIENTBUTTON
 */

void wxGradientButton::OnSize( wxSizeEvent& event )
{
	Refresh();
}

Под Windows Mobile 6 все это выглядит как-то так:

Градиентные кнопки на C++ с использованием библиотеки wxWidgets
Градиентные кнопки на C++ с использованием библиотеки wxWidgets
К.

Как получить изображение с камеры в Windows Mobile

Итак, камера… Windows Mobile версии 5 и выше предоставляет API для работы с камерой мобильного телефона. Что значит “для работы”? А значит это то, что кроме возможности получения изображения, которая будет рассмотрена в этом посте, предоставляемое API позволяет, также, осуществить захват видео любого формата, поддерживаемого Windows Media Player. Все эти радости жизни доступны посредством функции

HRESULT SHCameraCapture (PSHCAMERACAPTURE pshcc);


Документация по функции SHCameraCapture доступна в MSDN здесь, а описание структуры SHCAMERACAPTURE, которая передается в параметр функции, доступно здесь.
А сейчас мы рассмотрим небольшой пример использования выше указанной функции для получения изображения в формате JPG с камеры мобильного устройства. Ниже представлен код функции, которая отображает диалог для работы с камерой, который позволяет сохранить изображение с камеры в файл. После успешного заврешения работы диалога параметр result будет содержать путь к файлу с изображением.

static bool DoCaptureImage(LPCTSTR captureDir, LPCTSTR defaultFileName, 
						   LPTSTR result, DWORD resultSize, HWND parent)
{
	do
	{
		HRESULT         hResult;
		SHCAMERACAPTURE shcc;

		// Заполняем поля структуры SHCAMERACAPTURE.
		ZeroMemory(&shcc, sizeof(shcc));
		shcc.cbSize				= sizeof(shcc);
		shcc.hwndOwner			= parent;
		shcc.pszInitialDir		= captureDir;
		shcc.pszDefaultFileName	= defaultFileName;
		shcc.pszTitle			= TEXT("Capture Image");
		shcc.nResolutionWidth	= 0;
		shcc.nResolutionHeight	= 0;
		shcc.nVideoTimeLimit	= 0;
		shcc.Mode				= CAMERACAPTURE_MODE_STILL;
		shcc.StillQuality		= CAMERACAPTURE_STILLQUALITY_HIGH;

		// Отображаем диалог для работы с камерой
		hResult = SHCameraCapture(&shcc);
		if(hResult != S_OK) break;
		StringCchCopy(result, resultSize, shcc.szFile);
		return true;
	}
	while(false);
	return false;
}

Идем дальше… Теперь рассмотрим, как все описанное выше можно поиспользовать с wxWidgets и получить изображение в виде переменной wxImage:

static wxImage CaptureImage(WXWidget parent = NULL)
{
	do
	{
		// Создаем временное имя файла
		wxString tempFileName = wxFileName::CreateTempFileName(wxT("capture_"));
		// Т.к. wxWidgets по умолчанию добавляет расширение .tmp, 
		// а нам надо бы .jpg, то добавляем расширение руками
		tempFileName += wxT(".jpg");

		// Копируем путь к каталогу с временным файлом в буфер 
		TCHAR captureDir[MAX_PATH];
		StringCchCopy(captureDir, MAX_PATH, wxPathOnly(tempFileName).GetData());

		// Копируем имя файла в буфер
		TCHAR defaultFileName[MAX_PATH];
		StringCchCopy(defaultFileName, MAX_PATH, wxFileName(tempFileName).GetFullName());

		TCHAR fileNameBuffer[MAX_PATH];

		// Если ошибка то выходим...
		if (!DoCaptureImage(captureDir, defaultFileName, 
			fileNameBuffer, MAX_PATH, (HWND)parent)) break;
		// Получаем имя файла в переменную wxString
		wxString resultFileName(fileNameBuffer);
		// Загружаем отснятое изображение
		wxImage result(resultFileName, wxBITMAP_TYPE_ANY);
		// Удаляем временный файл
		if(wxFileExists(resultFileName)) wxRemoveFile(resultFileName);
		// Если изображение было загружено неудачно, то возвращаем false
		if(!result.IsOk()) break;
		// Если все нормально, то возвращаем true
		return result;
	}
	while(false);
	return wxNullImage;
}

Вот, такой нехитрый финт ушами позволяет нам получить изображение в виде переменной wxImage, которую можно использовать в GUI-приложении, например как-то так:

void wxCameraTestWMMainFrame::OnOPENClick( wxCommandEvent& event )
{
	wxImage capturedImage = 
		wxWMCameraCapture::CaptureImage(GetHandle());
	if(capturedImage.IsOk())
	{
		double controlScale = 
			(double)m_StaticBitmap->GetClientSize().GetHeight()/
			(double)m_StaticBitmap->GetClientSize().GetWidth();
		double imageScale = 
			(double)capturedImage.GetHeight() / 
			(double)capturedImage.GetWidth();
		double zoomLevel(1.0);
		if(imageScale > controlScale)
		{
			zoomLevel = (double)m_StaticBitmap->GetSize().GetHeight() / (double)capturedImage.GetHeight();
		}
		else
		{
			zoomLevel = (double)m_StaticBitmap->GetSize().GetWidth() / (double)capturedImage.GetWidth();
		}
		wxImage scaledImage = capturedImage.Scale(capturedImage.GetWidth() * zoomLevel,
			capturedImage.GetHeight() * zoomLevel);
		m_StaticBitmap->SetBitmap(wxBitmap(scaledImage));
	}
}

The конец.

Исходный код примера и проект для Visual Studio 2008 можно скачать здесь:
Пример получения изображения с камеры под Windows Mobile