Программирование

Исключаем контрол из 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 или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Как выборочно отключить шоткаты в меню. Часть вторая – фигвам.

October 1st, 2008 Begemot

В прошлом посте писал о том как как выборочно отключить шоткаты в меню, всего пару дней мне понадобилось что бы заметить что все это не работает.

Подход основывался на изменении tilte для wxMenu - удаления шотката при закрытии меню и добавления при открытии. Я еще тогда пытался изменить код на Enable\Disable – чтобы оставить текст тайтла в одном месте (легче менять если понадобится). Но это не сработало, разбиратся почему я не стал. Теперь знаю.

При нажатии горячей клавиши ассоциированной с пунктом меню, фрейм получает сообщение об открытии меню и соответвенно отрабатывает OnOpenMenu. Поэтому не работала идея дисейблить пункты, так как при нажатии хоткея  сначала вызывался OnOpenMenu, который делает Enable(), после чего разумеется шоткат срабатывал.

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

Вызывается OnOpenMenu, добавляет сокращения ко всем пунктам, которые мы вручную отключаем, а вот OnCloseMenu, в данном случае не вызывается.

Полностью отказыватся от автоматический обработки, не хочется, хотя и придется если не найду выхода. Других путей решения задачи пока не нашел. У кого-то есть идеи?


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


Как выборочно отключить шоткаты в меню

September 26th, 2008 Begemot

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

Уже во второй программе я сталкиваюсь с тем что мне необходимо, отключить автоматическую обработку для некоторых пунктов меню. Прямого способа нет. Я спрашивал в wx-листе, но там или меня не поняли или тоже не знали ответа.

Решение нашлось на форуме, собственно ответ тут. Добавляем обработчики для открытия\закрытия меню.

 


EVT_MENU_OPEN(MainFrame::OnOpenMenu)
EVT_MENU_CLOSE(MainFrame::OnCloseMenu)

void MainFrame::OnOpenMenu(wxMenuEvent & event)
{
       GetMenuBar()->FindItem(ID_COPYITEMTOCLIPBOARD)->SetItemLabel(_("&Copy to Clipboard\tCtrl+C"));
	event.Skip();
}

void MainFrame::OnCloseMenu(wxMenuEvent & event)
{
	GetMenuBar()->FindItem(ID_COPYITEMTOCLIPBOARD)->SetItemLabel(_("&Copy to Clipboard"));
	GetMenuBar()->FindItem(ID_COPYITEMTOCLIPBOARD)->SetBitmaps(wxBitmap(copy_clipboard_xpm), wxNullBitmap);
	event.Skip();
}

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


Если пост полезен для вас вы можете подписаться на 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 или мы можем доставлять вам новые посты прямо в ваш почтовый ящик.


Первые траблы с Chome и wxWidgets.

September 3rd, 2008 Begemot

Вот щеет, поставил Chome как дефолтный броузер, теперь мои wx-проги при попытке выполнить код перехода на веб страницу типа

wxLaunchDefaultBrowser(dHomeLink, wxBROWSER_NEW_WINDOW); 

запускают броузер и открывают страницу, но выдают ошибку

12:39:20: Can’t open registry key ‘HKCR\http\shell\open\DDEExec\topic’ (error 2: the system cannot find the file specified.)
12:39:20: Can’t read value of ‘HKCR\http\shell\open\DDEExec\topic’ (error 2: the system cannot find the file specified.)

Че за  новая напасть:(


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


Zip-уем данные на лету

September 2nd, 2008 Begemot

Встроенные удобства это приятно!:)

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


void SavecbContentToStream(wxMemoryOutputStream &memout, bool zlib/*=false*/) const
{
   scoped_ptr<wxDataOutputStream> dos;
   scoped_ptr<wxZlibOutputStream> zlibstr;

  if(zlib)
   {
        zlibstr.reset(new wxZlibOutputStream(memout, -1, wxZLIB_GZIP));
        dos.reset(new wxDataOutputStream (*zlibstr));
   }
   else
        dos.reset(new wxDataOutputStream (memout));

    // write some data …
   *dos <<(wxUint16)1 <<(wxUint16)cbContent.size();
   //  ...
}

Функция записывает данные в переданный буфер с опциональным архивированием их.


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


Явно Устанавливайте Имя Приложения: SetAppName

July 18th, 2008 Begemot

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

Настройки я храню, в конфиг файле

dataPath = wxStandardPaths().GetUserDataDir() + wxFileName::GetPathSeparator(); //стандартная папка с данным /application data/..

Но GetUserDataDir возвращает папку основываясь на AppName. Если вы не задаете его явно, то это имя ехе файла…

В принципе можно считать это бонусом:) Просто переименовав ехе, пользователь может получить две работающие копии с разными настройками и\или обойти запрет на запуск 2 экземпляров.

Но если это вам не надо, возьмите за правило в самом-самом начале программы использовать:


SetAppName(wxT("YourAppName")); //before GetUserDataDir()
SetVendorName(wxT("YourVendorName"));

Как бонус потом можете использовать в коде wxGetApp().GetAppName(), wxGetApp().GetVendorName() , повышая переносимость кода.


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


Кто украл Set/KillFocus?

July 17th, 2008 Begemot

Добавил 

EVT_KILL_FOCUS(MainFrame::OnKillFocus)

EVT_SET_FOCUS(MainFrame::OnKillFocus)

Не приходят, вообще. Приложение с AUI. Куда копать?


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


wxMenu с иконками и обход выделенных атемов в wxListCtrl

June 16th, 2008 Begemot

Пара маленьких функий, может кому пригодится.

Был удивлен что у wxMenu::Append нету для добавления меню с картинками. Пришлось писать самому

wxMenuItem * MainFrame::AppendMenuItemWithImage(wxMenu* parentMenu,

int id, const wxString& text, const wxString& helpString, const wxBitmap& checked, const wxBitmap& unchecked, wxItemKind kind, wxMenu* subMenu)

{

wxMenuItem* menuItem =

new wxMenuItem(parentMenu, id, text, helpString, kind, subMenu);

menuItem->SetBitmaps(checked, unchecked);

parentMenu->Append(menuItem);

return menuItem;

}

Использование:

wxMenu* itemMenu = new wxMenu;

AppendMenuItemWithImage(itemMenu, ID_HIDE, _(“&Hide In Tray\tEsc”), _T(“”), wxBitmap(hide_xpm));

AppendMenuItemWithImage(itemMenu, wxID_EXIT, _(“E&xit\tAlt-x”), _T(“”), wxBitmap(exit_xpm));

menuBar->Append(itemMenu, _(“&File”));


И еще один маленький хелпер для удобной работы  с выделенными айтемами в wxListCtrl:

vector<

long> MainFrame::GetListCtrlItems(const wxListCtrl * lcont, int state /*= wxLIST_STATE_DONTCARE*/, int geometry /*= wxLIST_NEXT_ALL*/, long item/*=-1*/)

{

vector<

long> items;

items.resize(lcont->GetSelectedItemCount());

// надеюсь так быстрее чем push_back

long ind=0;

do

{

item= lcont->GetNextItem(item, geometry, state);

if (item!=-1) items[ind++]=item; //items.push_back(item);

}

while( item != -1 );

return items;

}

Использование:

vector<

long> items=GetListCtrlItems(m_listFormat, wxLIST_STATE_SELECTED);

BOOST_FOREACH(

long item, items)

{

str+=m_listFormat->GetItemText(item)+wxT(

“\n”);

}

Иногда удобнее работать с вектором, хотя это я просто сейчас с STL знакомлюсь, вот и выпендриваюсь:)


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


Update для функции ReplaceForbiddenCharsInFileName

May 20th, 2008 Begemot

Обнаружил что Винда не любит точки в конце папок, поэтому доработал функциию ReplaceForbiddenCharsInFileName, теперь будет так

/********************** 22/03/08 19:41 *************************

deleteDotsAtEnd - удалять ли точки в конце, винда неразрешает такие имена, хотя и дает их создать програмно:)

******************************************************************/

/*static*/

wxString & BegUtils::ReplaceForbiddenCharsInFileName(wxString & name, const wxString ch/*=wxT("_")*/, bool deleteDotsAtEnd/*=true*/)

{

  wxString forbidden = wxFileName::GetForbiddenChars();

  int size=forbidden.Length();

  for (int i=0; i<size; ++i)

     name.Replace( wxString(forbidden[i]), ch,

true);

  if (deleteDotsAtEnd)

  {

     int count=0, len=name.Len()-1;

     while( name.GetChar(len-count)==_T(‘.’)) count++;

    if (count) name=name.Left(name.Length()-count);

  }

  return name;

}

(пока я пишу только под винду)


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




Page 1 of 212»