Pull to refresh

Картографические возможности Samsung Bada

Reading time10 min
Views1.3K

Предварительные замечания


Здравствуйте. Речь пойдет о том, как для мобильной платформы Samsung Bada создать простое приложение, позволяющее отобразить на экране смартфона карту, выполнять с ней манипуляции и решать несложные задачи. Начало разработки для Bada описано мной здесь.



Предварительные действия


Провайдером картографических данных для смартфонов с Bada является не… Google. (Для меня после мира Android это было некоторым потрясением, и я ощутил некий дискомфорт и сразу подумал — как легко мы привыкаем к мелочам и какую силу имеют виртуальные вещи (вспомнился топик на Хабре о возмущении пользователей, что Google убрал ссылку своего ридера с главной страницы). Впрочем, я отвлекся…

Статья построена таким образом. Сначала решается общая задача показа карты с минимумом функционала, чтобы дать представление о самой логике разработчиков SDK, а уже потом добавится маленькая, но полезная возможность. Такой подход вызван тем, что я провел немало часов, прежде чем среди дебрей хитро-премудрого С++ в примерах и документации вычленить собственно ряд тех действий, которые надо предпринять для «начального знакомства», а уже потом двигаться дальше.

Итак, перед программированием нам потребуется выполнить ряд дополнительных действий. Прежде всего, зарегистрироваться на сайте провайдера картографических данных для Samsung Bada deCarta (ссылка указывает не на главную страницу, а сразу на DevZone). Сайт, надо сказать, необычный — при входе с Chrome я обнаружил, что пароль в форму вводится без привычных звездочек, а собственно реакцию на цель регистрации — получение логина и пароля для работы с их картами — приходится недоуменно дожидаться по email без какого-либо намека на это. Вообщем, после регистрации (есть возможность прямо указать, что вы намерены работать именно для Bada) у меня прошло около около 10 минут, после чего пришло письмо, в котором был указан логин и пароль, которые мы и будем использовать в дальнейшем.

Предварительные действия с приложением


Создав при помощи BADA IDE form-based проект, я сразу удалил любезно добавленную на форму кнопку и код её инициализации, который находится в методе класса формы
result
SimpleMapForm::OnInitializing(void)
(я назвал форму SimpleMapForm), поскольку область формы будет занимать карта и кнопка, по сути, ни к чему. Тем не менее, чтобы располагать элементами управления для приложения, я, после щелчка на форме, открыл вкладку Properties и указал, что хочу видеть на форме две «Soft Key»-клавиши с надписями Zoom In и Zoom Out, изменив соответственно свойства Show Softkey0, SoftKey0 Text, Show Softkey1, Softkey1 Text. То, что получилось, выглядит так (надписи видно не полностью, но в работающем приложении этой проблемы нет):



Одной из типичных задач при работе с картой на мобильных устройствах является её масштабирование, панорамирование и т.д. Для того, чтобы иметь возможность отслеживать касания пользователя к экрану и интерпретировать их в карте, для класса формы я добавил ссылку на «слушатель» (я не люблю английские кальки слов, поэтому уж простите за такую доморощенную терминологию) этих действий
 public Osp::Locations::Controls::IMapEventListener 
в заголовочном файле формы. «Слушатель» объявлен в заголовочном файле <FLocations.h>, которого по умолчанию нет и его надо не забыть добавить. В целом, эта часть кода выглядит следующим образом:


#include <FBase.h>
#include <FGraphics.h>
#include <FUiControls.h>
#include <FApp.h>
#include <FLocations.h>


class SimpleMapForm :
	public Osp::Ui::Controls::Form,
	public Osp::Locations::Controls::IMapEventListener,
	public Osp::Ui::IActionEventListener
{

// Construction
public:
	SimpleMapForm(void);
	virtual ~SimpleMapForm(void);


Для добавленного «слушателя» надо определить обработчики тех событий, которые могут быть вызваны в ответ на различные манипуляции пользователя с картой. Пока мы не будем выполнять их реализацию, а просто добавим их в public-секцию класса формы:


	//обработчики карты
	void OnMapMovingStarted(const Osp::Locations::Controls::Map& source){}
	void OnMapMovingEnded(const Osp::Locations::Controls::Map& source){}
	void OnMapZoomingStarted(const Osp::Locations::Controls::Map& source, const bool zoomIn){}
	void OnMapZoomingEnded(const Osp::Locations::Controls::Map& source, const bool zoomIn){}
	void OnMapDrawCompleted(const Osp::Locations::Controls::Map& source){}

	//обработчики информационных окошек
	void OnClosingEnded(const Osp::Locations::Controls::IMapInfoWindow& source){}
	void OnInfoWindowClicked(const Osp::Locations::Controls::IMapInfoWindow& source){}
	void OnMapClicked(const Osp::Locations::Controls::Map& source,
					  const Osp::Graphics::Point& point, const Osp::Locations::Coordinates& coordinates){}
void OnInfoWindowDoublePressed(const Osp::Locations::Controls::IMapInfoWindow& source){}

	


Как такового GUI-компонента Map в IDE нет, поэтому его придется добавить «в коде».

Объявим провайдера карт и саму карту в приложении. Для этого вернемся в заголовочный файл класса формы и в секции private (так рекомендуют разработчики, но вот внятного объяснения к чему такая детальная спецификация я не нашел, честно сказать) добавим объявление:


 protected:
private:
	Osp::Locations::Services::IMapServiceProvider*	__pMapSvcProvider;
	Osp::Locations::Controls::Map*				__pMap;


Теперь в cpp-файле класса формы добавим пространства имен:


using namespace Osp::Locations;
using namespace Osp::Graphics;
using namespace Osp::Locations::Services;
using namespace Osp::Locations::Controls;


и начальную инициализацию провайдера карты и самой карты в конструкторе класса формы



SimpleMapForm::SimpleMapForm(void):
		__pMapSvcProvider(null),
		__pMap(null)
{
}



Теперь здесь же теперь можно найти метод инициализации формы
result SimpleMapForm::OnInitializing(void)
и добавить в него создание провайдера и карты:


const String providerName = L"deCarta";
	const String extraInfo = L"ClientName=***;ClientPassword=***;HostUrl=http://developer.kr.dz.decarta.com:80/openls/openls";
	const String prefProperty = L"global-mobile";

	Coordinates center;
	Rectangle clientRect = GetClientAreaBounds();

	__pMapSvcProvider = static_cast<IMapServiceProvider*>(ProviderManager::ConnectToServiceProviderN(providerName, LOC_SVC_PROVIDER_TYPE_MAP, extraInfo));
	__pMap = new Map();
	__pMap->Construct(Rectangle(0,0, clientRect.width, clientRect.height), *__pMapSvcProvider);

	 center.Set(48,37.8, 200);

	__pMap->SetCenter(center, false);
	__pMap->SetZoomLevel(12.0, false);


	__pMap->AddMapEventListener(*this);
	

	AddControl(*__pMap);


В коде объявлены константы с довольно прозрачными названиями, единственный момент следующий — в extraInfo в строке в секциях ClientName и ClientPassword надо указать полученные вами от deCarta соответственно логин и пароль.

Далее мы в clientRect возвращаем размеры клиентской области формы (то есть, без заголовка), создаем провайдера карт и саму карту, устанавливая её размеры равными размерами формы. (Чуть не забыл, для Rectangle надо добавить пространство Osp::Graphics). Затем, задав широту, долготу и высоту центра карты, передаем её в метод SetCenter. Его второй параметр, отвечающий за анимационные эффекты при работе с картой, я установил в false, потому как даже без всякой анимации скорость работы симулятора смартфона, мягко сказать, «не фонтан». Затем в SetZoomLevel устанавливаем желаемый масштаб карты (второй параметр здесь тоже в ответе за анимацию), быстро добавляем «слушатели» к карте и добавляем её к форме.

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

У меня симулятор с запущенным приложением выглядит таким образом:



В принципе, довольно симпатично и довольно детально для мобильной карты (мы использовали const «global-mobile» уровень детализации). Хотя, конечно, вопрос сравнения этого с картами от Google или Yandex остается открытым, и, кажется, это будет тема следующего топика.

Хотя это приложение уже обладает некоторой функциональностью — карту можно перетаскивать, допустим, — оно пока смысла особого не имеет и к нему надо какие-то полезности.

Позволим пользователю масштабировать карту — именно для этого мы добавили к приложению две Soft-клавиши (трудно подобрать соответствующий русский термин).

Для этого обоим клавишам следует назначить идентификатор события, который будет передаваться в обработчик и «слушатель» этого события. Выполним это программно в коде метода
SimpleMapForm::OnInitializing(void)
класса формы. Добавим в него следующее:


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

    SetSoftkeyActionId(SOFTKEY_0,ID_ZOOM_IN);
    AddSoftkeyActionListener(SOFTKEY_0,*this);

    SetSoftkeyActionId(SOFTKEY_1,ID_ZOOM_OUT);
    AddSoftkeyActionListener(SOFTKEY_1,*this);

    SetOptionkeyActionId(ID_OPTION_MENU);
    AddOptionkeyActionListener(*this);



Предварительно надо вернуться в заголовочный файл класса формы и добавить в него две константы ID_ZOOM_IN и ID_ZOOM_OUT, которые будут идентифицировать события касания на кнопки.


protected:


  // идентификаторы действий для кнопок масштабирования
  static const int ID_ZOOM_IN = 701;
  static const int ID_ZOOM_OUT = 702;




Располагая этим, мы уже можем обрабатывать нажатия на Zoom In и Zoom Out кнопки. Для этого в cpp-файле класса формы найдем метод,
SimpleMapForm::OnActionPerformed(constOsp::Ui::Control& source, int actionId)

который призван обрабатывать на все события, возникающие в приложении путем анализа параметра actionId.
Добавим в него следующий код:


switch (actionId) {
		case ID_ZOOM_IN:
			{
		// увеличение масштаба карты
                                                  
						float curZoomLevel = __pMap->GetZoomLevel();

						if (curZoomLevel == __pMap->GetMaxZoomLevel())
						{
							return;
						}

						++curZoomLevel;
						if (curZoomLevel > __pMap->GetMaxZoomLevel())
						{
							curZoomLevel = __pMap->GetMaxZoomLevel();
						}
						__pMap->SetZoomLevel(curZoomLevel, true);
						RequestRedraw(true);
               // -----------------------------
		}

			break;
		case ID_ZOOM_OUT:{
	// уменьшение масштаба карты
			            float curZoomLevel = __pMap->GetZoomLevel();

						if (curZoomLevel == 1.0)
						{
							return;
						}

						--curZoomLevel;

						if (curZoomLevel < 1.0)
						{
							curZoomLevel = 1.0;
						}
						__pMap->SetZoomLevel(curZoomLevel, true);
						RequestRedraw(true);
	    //-----------------------------
		}
		break;
default:
			break;
	}


Смысл следующий — пользователь нажимает на кнопку, допустим, Zoom In; за этим следит назначенный «слушатель» и назначенную нами этому событию константу ID_ZOOM_IN передает в OnActionPerformed, где мы анализируем actionId; тогда actionId будет иметь значение ID_ZOOM_IN и выполнится соответству.щий case-блок. Сам код, я так думаю, понятен и едва ли требует пояснений, так как названия методов имеют прозрачные названия. Единственный момент — после изменения масштаба SetZoomLevel мы просим форму «перерисоваться»:)

Выглядит на симуляторе это так:

1. Исходный масштаб сразу после запуска:

2. После Zoom In:

3. И почти максимальный Zoom:


Рассматривая последний снимок симулятора, можно легко заметить, что номеров домов просто нет (первый раз я некоторое время сидел в надежде, что они подгрузятся) в отличие от Google Maps или Yandex Карт, причем это улица — практически центр Донецка, хотя банки и даже банкоматы заботливо отмечены.

И теперь практически финал — дадим пользователю возможность увидеть некое место на карте по неким координатам.

В Bada есть всплывающие окна Popup, очень похожие на MessageBox (как выглядит последний, можно посмотреть у меня в первой статье), но на них можно располагать элементы управления, что представляется довольно удобным — не нужно создавать целую форму ради пары полей ввода и кнопки. Мы этим и воспользуемся.

Создадим Popup, перейдя в IDE в окошко ресурсов Resources и на узле дерева Popups. Щелкнем правой кнопкой мыши и выберем Open Insert Wizard. Для нужного разрешения экрана выберите Popup и нажмите Finish — в Resources появится нечто вроде IDP_Popup1. Щелкните по «этому» левой кнопкой мыши и увидите как откроется визуальный строитель интерфейсов, на который как и на форму можно перетаскивать элементы управления. Я создал следующий Popup:



Теперь добавим возможность на что-то нажать, чтобы это Popup появилось. Вернемся к форме и добавим к форме опциональное меню, установив в True свойство Show OptionKey. Получим на форме что-то такое:



Для OptionKey добавим идентификатор события и его «слушатель» в методе
SimpleMapForm::OnInitializing(void)
прямо после подобного кода для Zoom In и ZoomOut, создадим его и добавим один пункт «Change place»:


SetOptionkeyActionId(ID_OPTION_MENU);
AddOptionkeyActionListener(*this);

    // создание опционального меню
     __pOptionMenu = new OptionMenu();
     __pOptionMenu->Construct();
     __pOptionMenu->AddActionEventListener(*this);

     __pOptionMenu->AddItem(L"Change place",ID_OPTION_MENU_ACTION1);


Обратите внимание, SetOptionkeyActionId(ID_OPTION_MENU) — установка идентификатора для ПОКАЗА OptionKey, а __pOptionMenu->AddActionEventListener(*this) и __pOptionMenu->AddItem(L«Change place»,ID_OPTION_MENU_ACTION1) установка «слушателя»и идентификатора именно для обработчика НАЖАТИЯ на самом пункте OptionKey. Конечно, ID_OPTION_MENU и ID_OPTION_MENU_ACTION1 надо добавить в заголовочный файл класса формы.

Чуть ниже создадим Popup и проделаем с ним уже типичные действия:

 
        __pPopup = new Popup();
	__pPopup->Construct(L"IDP_POPUP_SET_NEW_PLACE");
	__pPopup->SetName(L"CommonPopup");


	__popupX = static_cast<EditField *>(__pPopup->GetControl(L"IDC_EDITFIELD1"));
	__popupY = static_cast<EditField *>(__pPopup->GetControl(L"IDC_EDITFIELD2"));

        __popupButtonOK = static_cast<Button *>(__pPopup->GetControl(L"IDC_BUTTON1"));

	__popupButtonOK->SetActionId(BUTTON_OK_POPUP);
	__popupButtonOK->AddActionEventListener(*this);


При этом к private секции класса формы я добавил объявления всех используемых идентификаторов — она теперь выглядит так:



private:
	Osp::Locations::Services::IMapServiceProvider*	 __pMapSvcProvider;
	Osp::Locations::Controls::Map*		         __pMap;
  
	Osp::Ui::Controls::OptionMenu*                   __pOptionMenu;
	Osp::Ui::Controls::Popup*                        __pPopup;

// идентификаторы элементов управления на Popup

	Osp::Ui::Controls::Label*      __popupLabelTitle;
	Osp::Ui::Controls::Label*      __popupLabelX;
	Osp::Ui::Controls::Label*      __popupLabelY;
	Osp::Ui::Controls::EditField*  __popupX;
	Osp::Ui::Controls::EditField*  __popupY;
	Osp::Ui::Controls::Button*     __popupButtonOK;


Вот… Теперь обработаем в ActionPerformed показ Popup и реакцию на его закрытие — соответственно проанализируем actionID на значения ID_OPTION_MENU, ID_OPTION_MENU_ACTION1 и BUTTON_OK_POPUP.

Я сделал это так:


case ID_OPTION_MENU:{

	// вызов опционального меню

              __pOptionMenu->SetShowState(true);
              __pOptionMenu->Show();
              RequestRedraw(true);

       //-------------------------
		}
		break;

		case ID_OPTION_MENU_ACTION1:{

     // обработка пункта 1 опциональго меню - показ Popup

            __pPopup->SetShowState(true);
            __pPopup->Show();
           RequestRedraw(true);

     // ---------------------
		}
		break;
		
		case BUTTON_OK_POPUP:{

    // смена текущих координат центра карты

			Coordinates newCenter;

			String newXStr(__popupX->GetText());
			String newYStr(__popupY->GetText());

			double newX;
			double newY;

			result r1=Double::Parse(newXStr,newX);
			result r2=Double::Parse(newYStr,newY);

			newCenter.Set(newX, newY, 200);

			__pMap->SetCenter(newCenter, false);

			__pPopup->SetShowState(false);
                        __pPopup->Show();
                       RequestRedraw(true);
  //------------------
		}


Что-то с отступами:(

Вот, в итоге получим следующее:

1. Щелчок по OptionKey:

2. Щелчок по кнопке OptionKey, появление Popup и ввод в него координат (на фон текста можно не обращать внимание, это поправляется выбором цвета фона):

3. И финал — вид симулятора с картой, загруженной по новым координатам:


Выводы

Программировать для Bada трудно — мое субъективное мнение после мира Android и WP7 (моя задача глобальнее той, которую я описал выше). Скорость работы симулятора не фонтан. Документация — скорее для демонстрации возможностей, для реальной работы приходится углубляться в примеры. Львиная доля форума разработчиков — на корейском языке, хотя, признаться честно, в англоязычной ветке ответили мне быстро. Но… работает!!! Причем работает достаточно стабильно и с картами, и с SQLite и даже с тем фактом, что С++ я изучал сам:)))

Удачи в программировании для Bada!
В силу своих скромных способностей постараюсь ответить на вопросы, если такие возникнут.
Спасибо большое за внимание.
Tags:
Hubs:
+3
Comments5

Articles

Change theme settings