После долгого перерыва решил снова заняться разработкой для Windows Mobile – доработать программу-переводчик, использующую Google Translate. В программе используется wxChoice cо списком языков. Так как поддерживаемых языков довольно много, то общая высота списка wxChoice получается много больше чем высота экрана КПК. В результате получаем что-то подобное:

Ошибка в вычислении размера dropdown-окна в wxComboBox/wxChoice

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

Перепробовав разные комбинации SetSize()/SetInitialSize()/SetMinSize()/SetMaxSize() нашел вот какое решение:

Если установить размер клиентской области для wxChoice после появления окна, то изменения применяются и получаем нормальный размер выпадающего списка. Если это делать при создании формы, то изменения не применяются.

bool wxGoogleTranslateClientApp::OnInit()
{    
	wxGoogleTranslateClientMainFrame* mainWindow = new wxGoogleTranslateClientMainFrame( NULL );
	mainWindow->Show(true);
	// Очень плохое решение, но только оно и работает
	mainWindow->m_SourceLanguageChoice->SetClientSize(
		mainWindow->m_SourceLanguageChoice->GetClientSize().GetWidth(), 120);
	mainWindow->m_ResultLanguageChoice->SetClientSize(
		mainWindow->m_ResultLanguageChoice->GetClientSize().GetWidth(), 120);
    return true;
}

В результате получаем вот такой результат:
wxComboBox/wxChoice Dropdown Size Problem Fixed

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

This post has 1 Comment

1
  1. Да. С этой проблемой я тоже сталкивался. Дело в том, что параметр height в WM используется для определения высоты dropdown’а, а высота самого контрола всегда остаться неизменной. Проблемму решил корректировкой исходного кода wxChoice.

    P.S. Также заметил: если использовать сайзеры, wxComboBox всегда находиться в верхнем левом углу экрана, т.е. координаты всегда равны нулю. Возможно эта проблема есть только в моей версии wxWidgets 2.8.10. Другие версии я пока не пробывал.

Leave a Reply

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

К.

Как программно сменить имя устройства в Windows Mobile

Имя устройства в Windows Mobile хранится в реестре. Это параметр Name ключа HKEY_LOCAL_MACHINE\Ident. Имя устройства используется для отображения устройства при синхронизации с настольным компьютером и, например, при обзоре Wi-Fi или Bluetooth устройств.

В этом посте я расскажу как получить и изменить имя устройства с помощью Native API и с помощью .NET Compact Framework.

Change Mobile Device Name

На имена устройств накладываются определенные ограничения:

  • имя должно содержать от 1 до 15 символов.
  • Первый символ должен быть из диапазона ‘a’-‘z’ или ‘A’-‘Z.’
  • Остальные символы ‘a’-‘z’, ‘A’-‘Z’, ‘0’-‘9’, или ‘-.’

Более подробно об именовании мобильных устройств можно узнать в MSDN.

А вот и примеры:

Native API (C++)

int _tmain(int argc, _TCHAR* argv[])
{
	HKEY hKey = NULL;
	DWORD dataSize(0);
	BYTE * data = NULL;
	do
	{
		if(RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Ident"), 0,  KEY_READ, &hKey)
			!= ERROR_SUCCESS) break;
		
		if(RegQueryValueEx(hKey, _T("Name"), NULL, NULL, NULL, &dataSize)
			!= ERROR_SUCCESS) break;

		int allocatedSize = max((int)(dataSize+1), (int)256);
		data = new BYTE[allocatedSize];
		ZeroMemory(data, allocatedSize);
		if(RegQueryValueEx(hKey, _T("Name"), NULL, NULL, data, &dataSize)
			!= ERROR_SUCCESS) break;
		MessageBox(0, (LPCTSTR)data, _T("Device Name"), MB_OK);
#if defined _UNICODE
		wsprintf((LPTSTR)data, _T("SampleName"));
#else
		sprintf((LPTSTR)data, _T("SampleName"));
#endif
		if(RegSetValueEx(hKey, _T("Name"), NULL, REG_SZ, data, 
#if defined _UNICODE
			wcslen((wchar_t*)data)*sizeof(wchar_t)
#else
			strlen((char*)data)
#endif
			)
			!= ERROR_SUCCESS) break;
	}
	while(false);
	if(data) delete [] data;
	if(hKey) RegCloseKey(hKey);
	return 0;
}

Указанный выше способ работает как для ANSI так и для UNICODE-сборки проекта.

wxWidgets (wxWinCE)

bool MobileDeviceNameMainFrame::SetDeviceName(const wxString & newDeviceName)
{
	do
	{
		if(newDeviceName.IsEmpty())
		{
			wxLogError(_("Device name can't be empty"));
			break;
		}
		wxRegKey key(wxRegKey::HKLM, wxT("Ident"));
		if(!key.Open())
		{
			wxLogError(_("Unable to open registry key"));
			break;
		}
		key.SetValue(wxT("Name"), newDeviceName);
		key.Close();
		return true;
	}
	while(false);
	return false;
}

wxString MobileDeviceNameMainFrame::GetDeviceName()
{
	do 
	{
		wxRegKey key(wxRegKey::HKLM, wxT("Ident"));
		if(!key.Open())
		{
			wxLogError(_("Unable to open registry key"));
			break;
		}
		wxString result;
		if(!key.QueryValue(wxT("Name"), result)) break;
		return result;
	} 
	while (false);
	return wxEmptyString;
}

.NET Compact Framework

public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Ident", true))
            {
                deviceNameTextCtrl.Text = key.GetValue("Name").ToString();
            }
        }

        private void btnChangeDeviceName_Click(object sender, EventArgs e)
        {
            using (RegistryKey key = Registry.LocalMachine.OpenSubKey("Ident", true))
            {
                key.SetValue("Name", deviceNameTextCtrl.Text);
            }
        }
    }

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

С.

Собираем wxWinCE, C++ библиотеку для разработки GUI приложений под PocketPC!

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

Сегодня мы поговорим о том, как собрать библиотеку wxWidgets, а точнее ее порт wxWinCE, который используется для разработки приложений, работающих под управлением Windows Mobile и значительно упрощает процесс разработки GUI-приложений для карманных компьютеров и смартфонов под упралвением этой ОС. Для того чтобы собрать wxWinCE мы будем использовать Visual Studio 2008.

Итак, для начала нам необходимо загрузить исходный код wxWidgets с официального сайта. Сделать это можно здесь. На странице доступны различные версии дистрибутива wxWidgets, а также пакеты для различных ОС. На данный момент последней версией является 2.8.8. Лучше всего будет загрузить пакет wxALL (пакет, содержащий исходный код wxWidgets для всех поддерживаемых платформ и операционных систем).

После того как исходный код библиотеки загружен, распаковываем его и переходим в папку wxWidgets-2.8.8/build/wince. Здесь находятся файлы проектов для wxWinCE.

Открываем файл проекта wx_mono.vcp. При открытии Visual Studio предложит преобразовать файл проекта к новому формату.

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

В этом посте для примера будет использована платформа Pocket PC 2003 и Windows Mobile 6 Professional. Почему выбраны именно эти платформы? Pocket PC 2003 выбрана как самая старая. Приложения, собранные под эту платформу будут также работать под управлением более поздних версий Windows Mobile. Windows Mobile 6 Professional выбрана как самая новая.

Итак, открываем окно свойств проекта и переходим в раздел Configuration Properties -> General. В этом разделе в свойстве Output Directory устанавливаем значения:

  • Для платформы Pocket PC 2003 – “..\..\lib\evc_armv4_lib”
  • Для платформы Windows Mobile 6 Professional – “..\..\lib\evc_armv4t_lib”

Сделать это нужно для обеих конфигураций, Debug и Release.

Переходим в раздел Librarian -> General и в свойстве Output File устанавливаем значение $(OutDir)\$(ProjectName).lib для Release конфигурации и $(OutDir)\$(ProjectName)d.lib для Debug конфигурации.

Для платформы Windows Mobile 6 Professional переходим в раздел C/C++ -> Advanced и в свойстве Compile for Architecture устанавливаем значение ARM4T (QRarch4t).

Идем в раздел C/C++ -> Code Generation и в свойстве Enable C++ Exceptions устанавливаем значение No. Необходимо помнить, что сделать это нужно для обеих конфигураций и для обеих платформ.

Пытаемся собрать библиотеку, жмем Build. И что мы видим? Ошибки!!! Первое с чем прийдется столкнуться, это ошибка вида

—— Build started: Project: wx_mono, Configuration: Debug Pocket PC 2003 (ARMV4) ——
Creating ..\..\lib\evc_armv4_lib\winced\wx\msw\rcdefs.h
“clarm.exe” не является внутренней или внешней
командой, исполняемой программой или пакетным файлом.
Project : error PRJ0019: A tool returned an error code from “Creating ..\..\lib\evc_armv4_lib\winced\wx\msw\rcdefs.h”
Build log was saved at “file://e:\wxWidgets-2.8.8\build\wince\Pocket PC 2003 (ARMV4)\Debug\BuildLog.htm”
wx_mono – 1 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

Лечится она просто, необходимо повторно запустить сборку проекта.

Смотрим дальше, ошибка вида

e:\wxWidgets-2.8.8\include\wx/aui/floatpane.h(33) : error C2504: ‘wxMiniFrame’ : base class undefined
..\..\src\aui\framemanager.cpp(2453) : error C2039: ‘SetTransparent’ : is not a member of ‘wxAuiFloatingFrame’
e:\wxWidgets-2.8.8\include\wx/aui/floatpane.h(32) : see declaration of ‘wxAuiFloatingFrame’

Лечится она тоже довольно просто, открываем файл floatpane.h и меняем декларацию макроса wxAuiFloatingFrameBaseClass чтобы оно выглядел так:

#if defined( __WXMSW__ ) || defined( __WXMAC__ ) ||  defined( __WXGTK__ )
#include "wx/minifram.h"
#define wxAuiFloatingFrameBaseClass wxFrame
#else
#define wxAuiFloatingFrameBaseClass wxFrame
#endif

Следующее, ошибка вида

..\..\src\msw\window.cpp(5965) : error C3861: ‘VkKeyScan’: identifier not found

лечится добавлением функции-заглушки


unsigned int VkKeyScan(int)
{
return 0;
}

Хотелось бы отметить что в версии 2.8.7 библиотеки этой ошибки нет и если уж совсем не хочется что-то править в исходниках wxWidgets, то можно воспользоваться версией 2.8.7.

Ну вот, теперь можно собирать библиотеку. Собираем Debug и Release конфигурацию для обеих платформ.

Дальше, для удобства использования wxWinCE в проектах, нам необходимо добавить переменную окружения WXWIN и присвоить ей в качестве значения путь папке с исходным кодом wxWidgets.

Ну вот, со сборкой библиотеки мы закончили, теперь можно приступать к созданию нашего первого приложения, но об этом в следующий раз 😉