Skip to main content

UI: Custom Control – własna kontrolka

Każdy programista prędzej czy później dojdzie do takiego momentu, w którym zacznie mu brakować dodatkowych wyspecjalizowanych kontrolek, których Framework bada nie oferuje w standardzie.

Jeszcze inni programiści posiadający doświadczenie w pracy z innymi środowiskami RAD (ang. Rapid Application Development – „szybkie tworzenie aplikacji”) – np. Delphi – postanowią przepisać część kontrolek, do których zdążyli się już przyzwyczaić i które znacznie ułatwiają im pracę.

To co determinuje potrzebę tworzenia kontrolek, to przede wszystkim wygoda ich stosowania i możliwość wykorzystania w wielu projektach.

Niestety środowisko programistyczne bada IDE oparte o Eclipse nie pozwala na dodawanie kontrolek użytkownika do kontenera ToolBox, skąd moglibyśmy je wybierać jak każdą inną dostarczaną przez Samsunga, co uważam za znaczącą niedogodność (mogę się mylić).

Ten artykuł będzie opisywał sposób tworzenia kontrolki użytkownika odpowiedzialnej za wyświetlenie obrazka z dysku lokalnego urządzenia, o którą wielu programistów pyta, a której standardowo nie znajdziemy w bada (można wykorzystać inne kontrolki, które umożliwiają ustawienie tła).

Funkcjonalność kontrolki

Nasza kontrolka będzie nazywała się: BDImage i będzie dostępna w przestrzeni nazw BadaDev. Jej odpowiednikami w rożnych środowiskach programistycznych są:

  • PictureBox w C#,
  • TImage w Delphi.

Kontrolka będzie potrafiła czytać obrazki z następujących źródeł:

  • lokalny dysk.

Dodatkową funkcjonalnością będzie:

  • możliwość ustawienia wewnętrznego obramowania (szerokość, kolor),
  • zmiana koloru obramowania po naciśnięciu kontrolki (na stałe zielony).

Lista metod, które zaimplementujemy

bool LoadFromFile(const String& fileName);
void SetBorder(int width, const Osp::Graphics::Color& color);
virtual void ~Image(void);

Lista zdarzeń, które także obsłużymy

virtual void OnTouchPressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
virtual void OnTouchReleased(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);

Dodatkowa funkcjonalność, którą możesz zaimplementować

  • położenie obrazka względem ramki,
  • automatyczne skalowanie,
  • pobieranie obrazka z Internetu.

Grupy uprawnień

  • IMAGE

Implementacja

Wyprowadzamy nową klasę pochodną od Osp::Ui::CustomControlBase i implementujemy wcześniej opisane metody.
Metodą rysującą kontrolkę jest OnDraw(), którą należy przesłonić.

/*
 * BDImage.h
 *
 *  Created on: 05-12-2011
 *      Author: markac
 */

#ifndef BDIMAGE_H_
#define BDIMAGE_H_

#include <FBase.h>
#include <FUi.h>
#include <FMedia.h>
#include <FIo.h>

using namespace Osp::Base;
using namespace Osp::Media;
using namespace Osp::Graphics;
using namespace Osp::Ui;
using namespace Osp::Io;

namespace BadaDev {

class BDImage :
	public CustomControlBase,
	public ITouchEventListener
{
protected:
	int __borderWidth;
	Osp::Graphics::Color __borderColor;
	Bitmap* __pBitmap;
	bool __touched;
public:
	BDImage();
	result Construct(const Rectangle& rect);
	virtual ~BDImage();

	void SetBorder(int width, const Color& color);
	result LoadFromFile(const String& filePath);
	virtual result OnDraw();

	// ITouchEventListener
	virtual void OnTouchDoublePressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchFocusIn(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchFocusOut(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchLongPressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchMoved(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchPressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
	virtual void OnTouchReleased(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo);
};

}

#endif /* BDIMAGE_H_ */
/*
 * BDImage.cpp
 *
 *  Created on: 05-12-2011
 *      Author: markac
 */

#include "BDImage.h"

namespace BadaDev {

BDImage::BDImage() :
  __borderWidth(1),
  __borderColor(Color::COLOR_WHITE),
  __pBitmap(null),
  __touched(false)
{

}

BDImage::~BDImage()
{
	if (__pBitmap != null)
		delete __pBitmap;
}

result BDImage::Construct(const Rectangle& rect)
{
	result res = CustomControlBase::Construct(rect);
	if (!IsFailed(res))
		SetDefaultTouchEventListener(this);
	return res;
}

void BDImage::SetBorder(int width, const Color& color)
{
	__borderWidth = width;
	__borderColor = color;
}

result BDImage::LoadFromFile(const String& filePath)
{
	if (__pBitmap != null)
		delete __pBitmap;

	if (File::IsFileExist(filePath))
	{
		Image image;
		result res = image.Construct();

		if (IsFailed(res))
		{
			return res;
		}
		else
		{
			__pBitmap = image.DecodeN(filePath, BITMAP_PIXEL_FORMAT_RGB565);
			if (__pBitmap == null)
			{
				return GetLastResult();
			}
		}
	}
	else
	{
		return E_FILE_NOT_FOUND;
	}

	return E_SUCCESS;
}

result BDImage::OnDraw()
{
	Canvas* canvas = GetCanvasN();
	if (canvas != null)
	{
		canvas->SetLineWidth(__borderWidth);

		if (__pBitmap != null)
		{
			canvas->DrawBitmap(Rectangle(0, 0, GetWidth(), GetHeight()), *__pBitmap);
		}

		if (__borderWidth > 0)
		{
			if (__touched)
			{
				// kolor ramki dla obrazka przyciśniętego
				canvas->SetForegroundColor(Color::COLOR_GREEN);
			}
			else
			{
				// kolor normalnej ramki
				canvas->SetForegroundColor(__borderColor);
			}

			canvas->DrawRectangle(Rectangle(0, 0, GetWidth(), GetHeight()));
		}

		delete canvas;
	}

	return E_SUCCESS;
}

void BDImage::OnTouchDoublePressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo) {}
void BDImage::OnTouchFocusIn(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo) {}
void BDImage::OnTouchFocusOut(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo) {}
void BDImage::OnTouchLongPressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo) {}
void BDImage::OnTouchMoved(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo) {}

void BDImage::OnTouchPressed(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo)
{
	__touched = true;
	Draw();
	Show();
}

void  BDImage::OnTouchReleased(const Osp::Ui::Control &source, const Osp::Graphics::Point &tPosition, const Osp::Ui::TouchEventInfo &touchInfo)
{
	__touched = false;
	Draw();
	Show();
}

}

Przykład wykorzystania

result Form1::OnInitializing(void)
{
	result r = E_SUCCESS;

	// __imageControl - wskaźnik do prywatnej zmiennej typu BadaDev::BDImage w klasie formularza
__imageControl = new BadaDev::BDImage(); __imageControl->Construct(Rectangle(50, 50, 90, 90)); __imageControl->SetBorder(1, Osp::Graphics::Color::COLOR_WHITE); AddControl(*__imageControl); String filePath(L"/Home/badadev.png"); __imageControl->LoadFromFile(filePath); return r; }

Efekt końcowy

[yframe url=’http://www.youtube.com/watch?v=XfIvp5XC7dM’]

markac

Full-stack Web Developer