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

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

July 18th, 2008 Begemot

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

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

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

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

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

Но если это вам не надо, возьмите за правило в самом-самом начале программы использовать:
[sourcecode language=’cpp’]
SetAppName(wxT(“YourAppName”)); //before GetUserDataDir()
SetVendorName(wxT(“YourVendorName”));

[/sourcecode]

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

Posted in Программирование | Tags:
Comments Off on Явно Устанавливайте Имя Приложения: SetAppName


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

July 17th, 2008 Begemot

Добавил 

EVT_KILL_FOCUS(MainFrame::OnKillFocus)

EVT_SET_FOCUS(MainFrame::OnKillFocus)

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


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 знакомлюсь, вот и выпендриваюсь:)


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;

}

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

Posted in Программирование
Comments Off on Update для функции ReplaceForbiddenCharsInFileName


GetForbiddenChars() -> ReplaceForbiddenCharsInFileName()

March 27th, 2008 Begemot

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

wxFileName::GetForbiddenChars() есть, а обработать имя нечем. Написал свою.

/*static*/

wxString & BegUtils::ReplaceForbiddenCharsInFileName(wxString & name, const wxString ch/*=wxT(“_”)*/)

{

wxString forbidden = wxFileName::GetForbiddenChars();

int size=forbidden.Length();

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

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

true);

return name;

}


P.S. Кстати если в диалоге выбора папки – выбрать что-нибудь типа Мой Компьюте или Сетевое Окружение и нажать ОК, то диалог ввернет wxID_CANCEL. Он то вроде и правильно, нельзя же в эти папки писать – но пользователь может и не понять. Под MFC возращает id_ok и кривой путь, в результате получается запись в корень с:


Грузим текстовый файл

March 6th, 2008 Begemot

Задача: есть wxTextCtrl, пользователь должен уметь загружать в него свои текстовые файлы для просмотра и редактирования, своего рода notepad. Файлы у пользователя могут быть в ANSI, utf-8 и в одном из двух юникодов.

Есть wxTextCtrl::LoadFile() – думаю зашибись, повезло. Тестирую, юникод\утф-8 грузит, ANSI грузит только если там одни английские символы, если есть русские обламывается. Нахожу? что проблема в дебрях библиотеки, в попытке грузить файл как wxFFile::ReadAll(wxString * str, wxMBConv& conv = wxConvUTF8)

Спрашиваю в wx-dev@, вот ответ

TN> Is this a bug? If no, is there a any way to load ANSI files in unicode
TN> build?

Yes, use wxCSConv(wxFONTENCODING_CP1251) instead of default wxConvAuto
which only handles UTF-x encodings in 2.8 (in the trunk it falls back to
the system default encoding if the input doesn’t seem to be in UTF-8, but
not in 2.8).

Баг это или нет, я так и не понял. Но понял что wxTextCtrl::LoadFile() использовать нельзя, так как кодировку там задать нет возможности. Пришлось использовать напрямую wxFFile, с шаманством. Вот функция для загрузки файла

bool BegUtils::ReadFileToString(const wxString & FileName, wxString & Data)

{

wxFFile file(FileName);

if (!file.IsOpened() ) return false;

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

if (!file.ReadAll(&Data)) return false;

if (Data.IsEmpty() && file.Length()>0)

{ // Если строка пустая и длина у файла есть – то он наверняка был анси, читаем как анси

file.Seek(0);

if (!file.ReadAll(&Data, *wxConvCurrent)) return false;

}

return true;

}

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

Подозреваю что это довольно кривой метод, поэтому если кто знает как решить задачу “правильно”, с удовольствием послушаю.


Легким движением руки брюки превращаются… (опять поиск и замена wxTextCtrl)

March 3rd, 2008 Begemot

Я уже давал ссылку на мою статью про написание Find & Replace для wxWidgets-приложений. Тот код я начинал писать для wxTextCtrl’a со стилем wxTE_RICH, а закончил и окончательно тестировал на wxRichTextCtrl’e. Сейчас я отказался от использования wxRichTextCtrl (только если вдруг его допишут до юзабельного состояния), и вернулся на самый что не на есть простой виндовый эдит, тот который в нотепаде. Пришлось править код поиска и замены.  Если вам нужен код для поиска и замены в *обычном* wxTextCtrl (без  wxTE_RICH), то правьте код из статьи вместе со мной. Пока я нашел вот что.

1. Выкидываем или убираем под дефайн следующую строчку

#ifdef

WeUseWXRichTextCtrl

//If we have not selection, wxTextCtrl return StartFromBack=StartFromForward=Current_Insertion_Point, but wxRichTextCtrl return -2,-2

if (StartFromBack<0) StartFromBack=StartFromForward=m_Note->GetInsertionPoint();

#endif

2. Дальше оказывается что ищет криво, причина находится в документации. Перед тем как считать startPos и endPos, добавляем следующий код (изврат конечно, но что делать, кому сейчас легко?):

#ifdef WeUseWXTextCtrl

#ifdef

__WIN32__

// проблемма с wxTextCtrl – The multiline text controls always store the text as a sequence of lines separated by \n characters, i.e. in the Unix text format even on non-Unix platforms. This allows the user code to ignore the differences between the platforms but at a price: the indices in the control such as those returned by GetInsertionPoint or GetSelection can not be used as indices into the string returned by GetValue as they’re going to be slightly off for platforms using \r\n as separator (as Windows does), for example.

m_foundPos+=(string.Left(m_foundPos)).Replace(wxT(

"\n"), wxT("\n")); // Returns the number of replacements made.

#endif

#endif

3. В OnReplace убираем или выносим под ифдеф 1 строчку.

if (SelText==FindText)

{

#ifdef

WeUseWXRichTextCtrl

m_Note->DeleteSelection(); // this line is needed only for wxRichTextCtrl and needed not for wxTextCtrl

#endif

m_Note->WriteText(m_findData.GetReplaceString());

}

В итоге брюки превращаются…

Теперь вроде все ок, но если что еще найду – напишу.

Posted in Программирование
Comments Off on Легким движением руки брюки превращаются… (опять поиск и замена wxTextCtrl)


Find and Replace для текстового редактора

February 2nd, 2008 Begemot

На блог http://wxwidgets.info добавлена моя статья Find & Replace для wxWidgets-приложений.  Полный код для встраивания функциональности поиска и замены для текстового редактора. Пользуйтесь и не уподобляйтесь MS которая выпустила Windows Live Writer без функции Replace (!) (только вчера узнал когда понадобилось).

Posted in Программирование
Comments Off on Find and Replace для текстового редактора


Как reference counting чуть было не заставил поверить меня в мистику

January 15th, 2008 Begemot

Вчера вечером была написанна функция. Сегодня утром DialogBloks похерил мне весь файл, файл был восстановлен с архива, функция востановленна с аськи\почты. Но одно но – она не работала!, не работал не первый, ни второй вариант, всего было написанно три, третий работал но я проверил его только в конце. Функция простая как две копейки, берем строку, получаем ее внутренний буфер и отдаем винапи для изменения.

Обьявление функции:

void BegUtils::StrMakeLowerUniversal(wxString & data)

Первый

CharLower( data.GetWriteBuf(data.Length()) );

data.UngetWriteBuf();

и второй нерабочий вариант тела

wxStringBuffer buf(data, data.length()+1);

CharLower(buf);

Вчера работало – сегодня нет, классика 🙂

 

Оказалось все дело в контексте вызова – вот так работает

wxString data=_("NTnt НТнт öffnen вікно привет Donnée rápido test");

BegUtils::StrMakeLowerUniversal(data);

wxMessageBox(data);

А вот так уже нет

wxString data1=_("NTnt НТнт öffnen вікно привет Donnée rápido test");

wxString data(data1);

BegUtils::StrMakeLowerUniversal(data);

wxMessageBox(data);

Все оказалось прозаично, оптимизация строк, reference counting и разделямый внутренний буфер. Подробности обьяснять не буду – сам толком не понимаю, а ляпнуть что-нибудь и выглядеть дураком не хочется:) Зато дам вариант функции который работает и который я юзаю.

 

void

BegUtils::StrMakeLowerUniversal(wxString & data)

{

  #ifdef __WIN32__

      int len=data.length()+1;

      wxChar * buf = new wxChar[len];

      wxStrcpy(buf, data.c_str());

      CharLower(buf);

      data=buf;

      delete [] buf;

#else

      data.MakeLower();

#endif

}

 

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


Реализуем поиск в wxTextCtrl

December 24th, 2007 Begemot

Потребовалось мне значит добавить стандартные процедуры -  find, find next, replace. wxTextCtrl напрямую их не поддерживает, так что приходится писать руками. Полез искать примеры – самому писать немного муторно – надо много чего учитывать, а велосипед изобретать не хотелось – задача то по идее тривиальная. Как оказалось легче все таки самому:) Все велосипеды, что нашлись были или сильно самописыными (без использования стандартных диалогов) или вообще кривыми самокатами. Наиболее подходящим оказался вот этот код, сразу видно писал крутой программист и ему было не до тестрования.

И еще не могу понять почему все пытаются использовать Get\SetInsertionPoint когда помоему правильнее юзать только Get\SetSelection?

void FlashnoteFrame::OnFind()
{
     wxString find = m_findData.GetFindString();
    int flags = m_findData.GetFlags();
   

    bool forward(flags & wxFR_DOWN);
    long m_foundPos, StartFromBack, StartFromForward;
    m_Note->GetSelection(&StartFromBack, &StartFromForward);

    wxString string = forward ? m_Note->GetRange(StartFromForward, m_Note->GetLastPosition()) : m_Note->GetRange(0, StartFromBack);

    if (flags & wxFR_MATCHCASE)
            m_foundPos = forward ? string.find(find) : string.rfind(find);
    else
           m_foundPos = forward ? string.Lower().find(find.Lower()) : string.Lower().rfind(find.Lower());

    if (m_foundPos==-1) return;

    long startPos = forward ? StartFromForward + m_foundPos : m_foundPos;
    long endPos = startPos + find.length();

    m_Note->SetSelection(startPos, endPos);
}

Posted in Программирование
Comments Off on Реализуем поиск в wxTextCtrl