Используем png для иконок и храним ресурсы в архиве

December 24th, 2008 Begemot

Со временем я пришел к выводу что иконки лучше хранить в PNG, чем в XPM. Несомненый плюс это наличие альфа-канала. К тому же хранение иконок вне exe файла позволяет пользователю заменить используемые иконки на свои, что дает возможность правильно использовать для вашего приложения графику под LGPL лицензией (Где брать бесплатные иконки).

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

Я написал пару врапперов для удобной работы:


// don't forget call wxFileSystem::AddHandler(new wxZipFSHandler); in MyApp::OnInit()
wxImage BegUtils::GetImageFromZipResource(const wxString & path, long type/*=wxBITMAP_TYPE_ANY*/)
{
	scoped_ptr<wxFileSystem> fs(new wxFileSystem);
	scoped_ptr<wxFSFile> file(fs->OpenFile(path));
	if (!file) return wxNullImage;

	wxInputStream* stream = file->GetStream();
	wxImage image(*stream, type);

	return image;
}

// Load a text resource from zip file
// don't forget call wxFileSystem::AddHandler(new wxZipFSHandler); in MyApp::OnInit()
wxString BegUtils::GetUTF8TextFromZipResource(const wxString& path)
{
    scoped_ptr<wxFileSystem> fs(new wxFileSystem);
    scoped_ptr<wxFSFile> file(fs->OpenFile(path));
    if (!file) wxEmptyString;

    wxInputStream* stream = file->GetStream();
    size_t sz = stream->GetSize();
    scoped_array<char> buf(new char[sz]);
    stream->Read((void*) buf.get(), sz);

    wxString text = wxString::FromUTF8(buf.get(), sz);
    if (text[0]==0xFEFF) text.erase(0, 1); // BOM
    return text;
}

 

Использование примерно такое

 


wxString resPath=exePath+wxT("resource.bin#zip:");
...
#define MMB(x) BegUtils::GetImageFromZipResource(resPath+wxT("icons\\")+x+wxT(".png"), wxBITMAP_TYPE_PNG)

  AppendMenuItemWithImage(itemMenu, wxID_HELP, _T("Help\tF1"), _T(""), MMB(wxT("help")));
  AppendMenuItemWithImage(itemMenu, wxID_ABOUT, _T("About\tAlt+F1"), _T(""), MMB(wxT("information")));
....
 m_ToolBar->AddTool(wxID_EXIT, _T(""), MMB(wxT("exit")), wxNullBitmap, wxITEM_NORMAL, _T("Terminate Application (Alt+X)"), wxEmptyString);
....
#undef MMB

AppendMenuItemWithImage можно взять в wxMenu с иконками и обход выделенных атемов в wxListCtrl

Пользуйтесь на здоровье.


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


hex2bin and bin2hex c++ functions

December 11th, 2008 Begemot

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


#include <assert.h>
#include <vector>
using namespace std;

std::vector<unsigned char> hex2bin(const TCHAR * hexstring)
{
	std::vector<unsigned char> v;
	int ind=-1;
	bool first=true;
	TCHAR c, b;
	while(hexstring[++ind])
	{
		c=hexstring[ind];
		if( (c>47) &amp;amp;&amp;amp; (c<58)) c-=48;
		else  if ( (c>64) &amp;amp;&amp;amp; (c<71))  c-=65-10;
		else  if ( (c>96) &amp;amp;&amp;amp; (c<103)) c-=97-10;
		else continue;

		if (first) b=c<<4; else v.push_back(static_cast<unsigned char>(b+c));

		first=!first;
	}
	return v;
}

//bufferlen should be at least len*2+1 or len*3 if separator is set
int bin2hex(unsigned char *data, int len, TCHAR *buffer, int bufferlen, TCHAR separator)
{
	assert( ((separator==0) &amp;amp;&amp;amp; (bufferlen>len*2)) || (separator &amp;amp;&amp;amp; (bufferlen>len*3-1)));
	if (((separator==0) &amp;amp;&amp;amp; (bufferlen<len*2+1)) || (separator &amp;amp;&amp;amp; (bufferlen<len*3)))
	{
		if (bufferlen>0) buffer[0]=0;
		return 0;
	}

	const TCHAR hex[]={_T('0'), _T('1'), _T('2'), _T('3'), _T('4'), _T('5'), _T('6'),
 _T('7'), _T('8'), _T('9'), _T('a'), _T('b'), _T('c'), _T('d'), _T('e'), _T('f')}; 

    int ind=-1;
    while(len>0)
    {
		buffer[++ind] = hex[*data >> 4];
		buffer[++ind] = hex[*data &amp;amp; 0x0F];
		if (separator!=0) buffer[++ind] = separator;
		++data; --len;
    }
	if (separator!=0) --ind;
	buffer[++ind]=0;
	return ind; // count TCHAR without end \0
}

Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Исключаем контрол из tab order’a

November 12th, 2008 Begemot

Минус в том что контрол надо субкласить, плюс в том что это работает:)


h:
	bool SetAllowSetFocusFromKbd(bool allow=true)
	{
		bool t=AllowSetFocusFromKbd;
		AllowSetFocusFromKbd=allow;
		return t;
	};

        bool GetAllowSetFocusFromKbd() const
            {return AllowSetFocusFromKbd;};

	virtual void SetFocusFromKbd();

private:
	bool AllowSetFocusFromKbd;

cpp:
void CMyClass::SetFocusFromKbd()
{
	if (AllowSetFocusFromKbd)
		BaseClass::SetFocusFromKbd();
	else
		Navigate();
}

 

Спасибо мудрецам c форума шадонета за наводку


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Учимся вводить только цифры в wxTextCtrl

September 8th, 2008 Begemot

Поразительная фигня, казалось бы простая задача  и должно быть готовое решение. И правда есть, только поразительно кривое:(

Итак, задача – необходимо дать возможность пользователю указать число, например в настройках, количество записей  для отображения где-нибудь… Первое что приходит в голову – wxSlider, ну знаете такой контрол со стрелочками. Так как у меня диапазон от нуля до 10 000, а возможность задать шаг инкрементации для стрелочек я не нашел, и равен он 1 – то этот вариант, оказывается издевательством над юзером.

Думаем дальше и вспоминаем, про wxTextCtrl и валидаторы. Радуемся и пишем код, что-то типа

m_Count = new wxTextCtrl( this, ID_MAXCLIPTEXT, _T(""), wxDefaultPosition, wxSize(50, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &count));

Я ожидал что контрол будет давать вводить в себя только цифры. Я ошибся, он также пропускал точку и запятую, что еще хоть как-то можно понять, хотя его и не просили. Но еще оказались разрешенными: ‘+’ и ‘–’. Также он спокойно пропускал все буквы кирилицы. Похоже что контрол отфильтровывал только пробел, спецсимволы и латиницу. Хотя даже это можно ввести туда пользуясь драг анд дропом или простой вставкой. Вообщем я разочаровался.

Попробывал задать более конкретно wxFILTER_INCLUDE_CHAR_LIST и разрешил только цифры. “голосуй, не голосуй, все равно … “ (с). Теже траблы со вставкой текста из буфера и …. с кирилицей. Прямо наваждение какое-то.

Решил писать сам, вот что получилось


h:
	void OnMaxClipTextUpdated( wxCommandEvent& event );

	wxTextCtrl* m_Count;

	unsigned long maxCount;
	long maxInsertionPoint;
	wxString maxCountStr;
	bool maxSetManually;

cpp:
	EVT_TEXT( ID_MAXCLIPTEXT, COPDatabase::OnMaxClipTextUpdated )

	m_Count = new wxTextCtrl( this, ID_MAXCLIPTEXT, _T(""), wxDefaultPosition, wxSize(50, -1), 0);
	m_Count->SetMaxLength(4);

void COPDatabase::OnMaxClipTextUpdated( wxCommandEvent& event )
{
	if (maxSetManually) return;
	wxString str=m_Count->GetValue();

	if (str.empty() || (str==wxT(" "))) // вторая проверка нужна для случая когда юзер выделяет все в контроле и жмет пробел
	{
		maxCount=0;
		str=wxT("0");
		maxInsertionPoint=1;
		// or if you want to let empty string - replace last 2 string to these - maxCountStr=wxEmptyString; maxInsertionPoint=0;
	}

	if (str.ToULong(&maxCount))
	{ // successfully converted to ulong, check range now
		if (maxCount>10000) maxCount=10000;
		else if (maxCount<0) maxCount=0;

		maxInsertionPoint=m_Count->GetInsertionPoint();
		maxCountStr=wxString::Format(wxT("%i"), maxCount); // we should do like this! иначе траблы с пробелами, нулями..
	}

	maxSetManually=true;
	m_Count->SetValue(maxCountStr);
	maxSetManually=false;
	m_Count->SetInsertionPoint(maxInsertionPoint);
}

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

Поведение (юзабилити) не идеально, но твердую 4-ку я бы поставил. Хотя в случае если диапазон снизу ограничен не нулем, тогда поведение хреново будет, но у меня такого случая пока не было. Как выход можно исключить динамическую проверку диапазона, и перенести ее в код сохраняющий значение.

Еще совет, лучше поставить ограничение на длину вводимых символов, типа m_Count->SetMaxLength(4); для верхней границы 10000 и т.д.

Пользуйтесь. Высказывайтесь.


Если пост полезен для вас вы можете подписаться на RSS или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.