Обработка событий в wxWidgets.

November 8th, 2011 Begemot

Процесс перевод книги продолжается.

Read the rest of this entry »


Просмотр wxWidgets переменых в GDB Ubuntu

October 29th, 2011 Begemot

GDB к сожалению не самый удобный отладчик на свете, но что делать… А мой (7.2 под ubuntu 11.04) еще падал все-время, если в функции где я ставлю брейк, есть определение wxString, типа wxString str = “some string”; падал с таким сообщением

Breakpoint 2, BegUtils::GetImageFromZipResource (pathURL=…, fileName=…, type=wxBITMAP_TYPE_PNG) at /media/data/work/Flashnote/src/Utility/begutils.cpp:166
/media/data/work/Flashnote/src/Utility/begutils.cpp:166:4941:beg:0x82977e3
>>>>>>cb_gdb:
> info locals
warning: static field’s value depends on the current frame – bad debug info?
/build/buildd/gdb-7.2/gdb/findvar.c:427: internal-error: read_var_value: Assertion `frame’ failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.

Если определения строки нет, то заходил, но падал стоило провести курсором над параметром функции – строке. Вообщем дебажить было вообще невозможно.

Решение такое:

CodeBloks -> Settings -> Compiler and debugger settings -> Debugger settings -> И там в первый едит бокс добавляем строку source  /media/data/const/wxWidgets/misc/gdb/print.py

После чего падения прекращаются, и о чудо, отладчик начинает показывать значение wxString. Жизнь сразу становится много лучше:)

Еще почитать можно тут Pretty printing wxStuff in gdb и тут

Posted in Использование | Tags: ,
Comments Off on Просмотр wxWidgets переменых в GDB Ubuntu


Обработать завершение сессии в Linux

September 12th, 2011 Begemot

Пытаюсь тут портировать на линукс свой менеджер заметок написанный на с++ and wxWidgets. Столкнулся с тем что не могу отследить событие когда пользователь уходит – logout, reboot, shut down. А мне то надо как-то данные сохранять. Под виндой, есть EVT_QUERY_END_SESSION, библиотека ловит виндовое сообщение и сообщает мне о событии, пускай с большими проблемами но что-то сделать можно – сохранить данные, корректно закрыть приложение, заповним положение\размеры окна и мелкие настройки. Под макосом не пробовал, но говорят работает. Под Линуксом нет – в инете полно вопросов, жалоб – но решения нет.

Пытался использовать средства gtk (или posix, или чье это там), типа

#include <stdio.h> // for File I/O #include <signal.h> // for signals #include <unistd.h> // for sleep() void handler(int sig) { /* Just print to stderr and redirect 2>> test.txt in the shell */ fprintf(stderr, "got %d\n", signal); signal(sig, handler); // let signal be caught again } int main() { signal(SIGTERM,handler); signal(SIGINT,handler); signal(SIGQUIT, handler); // Maybe we're getting QUIT first? signal(SIGHUP, handler); // If the terminal closes, we might get this signal(SIGPIPE, handler); // Don't know why we'd get this, but check anyway while(1) // loop forever with most signals trapped, impolitely waiting for a kill -9 😉

// run }

Не фига, когда руками прибиваю приложение Ctrl+c в терминале или kill … срабатывает, когда вырубаю систему нет, сообщения не получаю. В инете все пишут тоже самое не работает.  Code::Blocks тоже не сохраняет данные, если что-то изменить и сделать logout.  

Получается линукс, или убунта, или гном не дает возможность приложению узнать что сессия завершается и корретно завершить работу, сохранив данные. Вот вам и Linux with a human face 🙁

Есть правда какой-то EggSMClient в виде сорцов, LGPL, его например использует GEdit и молодец, корректно обрабатывает все. Но что-то про EggSMClient ни упоминаний толком, ни документации – особенно ничего не находится, а так разобратся без бутылки не получается. Печально все это 🙁


Форматированный текст в контролах

March 7th, 2011 Begemot

Ура, приятная новость:  Markup in control labels. Меня эта возможность сильно порадовала в Qt когда я на нее перешел, теперь вот и в wxWidgets появляется что-то подобное, хотя конечно гораздо слабее чем в Qt, но все равно здорово. Правда не совсем понятно почему wxStaticText отстает от кнопки, но надеюсь сделают все хорошо в итоге:)


Qt vs wxWidgets личный опыт

February 28th, 2011 Begemot

Меня тут спросили, спросили – отвечаю. В кратце про Qt vs wxWidgets после некоторого опыта, очень в кратце.

 

Про Qt:

1. На Qt писать быстрее и проще (субьективно и смотря что)

2. Написанное под виндо в течении 3 месяцев запускается на макоси после часа работы.

3. Приложения не родные

4. Приложения здоровые.

 

Про wxWidgets:

1. Писать вполне нормально, хотя может и не так гладко как на Qt

2. Результат выглядит роднее

3. Бинарников по паре сотен килобайт не получается, но и не десятки метров как у Qt.

4. Запуск под макосом – требует гораздо большего количества нервов, времени и напильников.

 

Для этой программы я после 10 дней на вх, выбрал Qt (совсем его тогда не зная), и не пожалел. Для своих Clipdiary и Flashnote я все таки считаю что wx не плох, хотя следует признать что первая программа уже продается под МакОС, а вторая и третья только в далекой перспективе:)

В общем – как всегда для конкретной задачи, нужен конкретный инструмент.

А еще, учитывая последний маневр Нокии, есть вероятность что развитие Qt тормознется, об этом стоит тоже думать….


О правильных контейнерах, методах и алгоритмах

January 27th, 2011 Begemot

Довелось мне тут недавно портировать один код, считающий dog inbreeding coefficient, с C# на С++/Qt. Код портировался легко, фактически 1 в 1, за исключением того что стеки в Qt ведут себя немного не так как в шарпе, но это решилось. Через некоторое время обнаружилось, что на больших родословных код работает непозволительно медленно, в шарповской версии, что интересно, проблем не было, пришлось оптимизировать.

Шаг первый – правильные контейнеры.

Код использовал списки, при портировании я их и заменил на QList. Но в принципе списки не самый быстрый контейнер для простых операций. Первое что я сделал заменил на QVector. Автозаменой, получил прирост в 30%.

Шаг второй – правильные методы доступа.

В поисках что бы еще улучшить, случайно наткнулся в документации на следующее

For read-only access, an alternative syntax is to use at():

at() can be faster than operator[](), because it never causes a deep copy to occur.

У нас в контейнере хранились просто int’ы, ничего более сложного, поэтому чудес я не ожидал. Но произошло чудо:)

Замена всего одной строчки в коде вида

Q_FOREACH(QList<int> pf, paths_father)

{

Q_FOREACH(QList<int> pm, paths_mother)

{

if (pf[0] != pm[0]) continue;

Дала прирост на порядок для количества путей родителей XXK на XK, и в сотню раз (!) для количества порядка 220K на 30К. Сказка.

И наконец, финальный аккорд – алгоритмы.

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

В общем, правильные вещи – рулят.


Еще про локализацию

January 6th, 2011 Begemot

Сделали мне тут арабскую локализацию для двух программ. Понравилось как красиво wxWidgets все это обработала. Или это Винда?

Flashnote-ar

Flashnote-options-ar

clipdiary-ar

Ориганалы можно посмотреть тут и тут.

Правда прикольно?:)


Готовь сани летом

September 4th, 2010 Begemot

Стукнуло мне что-то тут в голову изучить вопрос глобальной обработки ошибок – создания минидампа и т.д. Что бы если где-то что-то там у них того, можно было попросить информацию.

Про то что в wxWidgets есть родные средства  я знал, но хотелось полностью готового и универсального (я еще пишу на Qt и поддерживаю MFC) решения. Начал искать.

Сначала прочел все четыре части XCrashReport, поимел общее представление и даже нашел как прикрутить это дело к wxWidgets (пришлось заходить сзади). Но оказалось что ихний exe для отсылки информации, надо пересобирать, а сделать это в 2008 студии не представляется возможным с разумными усилиями. Автор уже давно в принципе сам все поправил и значительно улучшил, но теперь хочет за современную версию $80.

Решил выкинуть их ехе который занимается отправкой, и просто генерить файлы. Потом решил, что я вообще могу выкинуть почти весь их код и использовать стандартную MiniDumpWriteDump. И вот тут я наконец решил посмотреть что есть готового в wxWidgets.

Оказалось есть, и причем неплохое – wxDebugReport. Генерит минидамп, xml со вспомогательной информацией, позволяет включить другие файлы, показывает диалог и даже может вроде их куда-то аплоадить (не тестил), жаль только по е-майл не может послать, что плохо.

image

Документация понятная, есть самп – еще более понятный. Добавляется к себе это чудо парой строчек кода + функция генерации репорта, которую можно взять в сампле и доработать. В общем, пару часов и у вас как в лучших домах Лондона и Парижа.

Но за все надо платить, в данном случае цена – 300кб, для меня многовато, но фиг с ним.

Учтите что нужно добавить в проект либы wxmsw29u_qa.lib, wxbase29u_xml.lib и wxexpat.lib. Еще нужно включить генерацию map и pdb файлов для релизной версии программы. Эти файлы нужно хранить для каждого релиза, вы же конечно используете version contorol system?


wxLANGUAGE_ENGLISH != wxLANGUAGE_ENGLISH

September 3rd, 2010 Begemot

Я зол, я дико зол, надо выпустить пар, но постараюсь без крепких выражений.

Прикрутил полгода назад локализацию, уже есть несколько языков – английский, русский, китайский и голландский. Выпускаю новую версию, получаю через день 5 писем. Мол “поставили новую версию, но интерфейс теперь на каком-то странном языке, наверное на голландском, чо делать?”.

Первым ответил что небось сами переключили случайно, потом понимаю что проблема есть, начинаю разбираться. Изучаю свой код ищу где мог ошибиться. Потом оказывается что идентификаторы языков в wxWidgets (wxLANGUAGE_ENGLISH etc) не константы, а просто enum. И недавно туда всунули новый Боснийский язык, причем не в конец, а середину как и положенно по алфовиту, в результате все что ниже его поплыло.

в результате wxLANGUAGE_ENGLISH, хранившиеся в конфиге, вместо 57го стал 58м, а 57м по стал голландский, который оказался у меня тоже. вот такая хрень.

Пока тупо написал workaround – читаю инфорамцию о языке по другому пути в конфиге, в результате у всех заново спросит какой язык они хотят. Но это лучше чем запустить и увидеть голландский.

Но это не решение проблемы, решения я пока особо не вижу, а вы? Как хранить в конфиге информацию о языке?


Сохраняем CF_DIB\CF_DIBV5 в файл

August 27th, 2010 Begemot

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

Итак у нас есть данные в памяти в форматах CF_DIB/CF_DIBV5 (да я знаю что это форматы буфера обмена!) ну или другими словами у нас есть BITMAPINFO. А мы хотим получить wxBitmap.

Сначала нам нужно получить HBITMAP, который потом уже можно конвертить в wxBitmap используя wxBitmap::SetHBITMAP(да в документации ее нету).

Много писать мне уже сегодня лень, поэтому просто покажу код, там в комментариях описаны все проблемы и решения.

 

        if (BITMAPINFO * bi = static_cast<BITMAPINFO*>(p->data.GetData()))
        {
              /*   там с клипбоардом вообще мрак, MS сам свои спецификации не соблюдает, я тебе уже жаловался, когда в классы всё это барахло заворачивал
                    когда в biCompression указано BI_BITFIELDS за структурой следуют 12 байт маски цветовых каналов, надо на 12 байт смещать начало пиксельного массива
                    1) 12 байт пропускать надо? только если biCompression==BI_BITFIELDS
                    2) по-хорошему, их надо не пропускать, а анализировать и использовать
                    3) работает ли твой код в случае с 8-битным битмапом (т.е. таким, который включает палитру)?
   
                    в третьем с конца - нужно пропустить кол-во элементов палитры
                    так, а как узнать количество элементов палитры?
                    biClrUsed или (1<<biBitCount), если biClrUsed=0  и это делать только если biBitCount <= 8
            */

                int offset = 0;
                if (bi->bmiHeader.biBitCount <= 8)
                {
                    offset = bi->bmiHeader.biClrUsed ? bi->bmiHeader.biClrUsed : (1 << bi->bmiHeader.biBitCount);
                }
                else
                {
                    if (bi->bmiHeader.biCompression == BI_BITFIELDS) offset = 3;
                }

/*
  Правильно использовать independing bitmap - но похоже тут у wxBitmap проблемы, мы получаем правильный hBitmap (видно на экране), но в файле пробелмы - на определенной
  цветности\форматах (тестировалось только для DIB)
  поэтому использую DDB - тут теряется цветность, итоговая цветность не равна оригинальной, а зависит от текущих настроек экрана... но зато работает.
  // (RGBQUAD*)((byte*)bi + bi->bmiHeader.biSize) + offset  instead of &bi->bmiColors + shift - for support both versions DIB\DIBV5
*/

#if 0
             // using independent bitmap
             char * pBits;
             HBITMAP hBitmap = CreateDIBSection(CreateCompatibleDC(NULL), bi, DIB_RGB_COLORS, (void**)&pBits, NULL, 0);
             memcpy(pBits, (RGBQUAD*)((byte*)bi + bi->bmiHeader.biSize) + offset, abs(bi->bmiHeader.biHeight) * (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8));
#else         // use DDB (dependent) - we lost information about color depth - bad way
             
             HBITMAP hBitmap = CreateDIBitmap(GetDC(NULL), &bi->bmiHeader, CBM_INIT, (RGBQUAD*)((byte*)bi + bi->bmiHeader.biSize) + offset, bi, DIB_RGB_COLORS);
#endif
//           //------------------------------------------------------------------------------------------------------------------
//              { // write to screen to test it
//                  HDC screen = GetDC(NULL);
//                  HDC bitmap = CreateCompatibleDC(screen);
//                  HBITMAP old = (HBITMAP)SelectObject(bitmap, hBitmap);
//                  int w = 0, h = 0, d = 0;
//                  w = bi->bmiHeader.biWidth; h = bi->bmiHeader.biHeight; d = bi->bmiHeader.biBitCount;
//                  BitBlt(screen, 100, 100, w, h, bitmap, 0, 0, SRCCOPY);
//                  SelectObject(bitmap, old);
//                  DeleteDC(bitmap);
//                  ReleaseDC(NULL, screen);
//              }
//             //------------------------------------------------------------------------------------------------------------------

                wxBitmap bitmap;
                bitmap.SetHBITMAP(hBitmap);
                if (bitmap.IsOk())
                {
                    bool res = bitmap.SaveFile(file, BegUtils::DetermineImageType(file));
                    wxASSERT(res);
                }
                else wxASSERT(0);
            }

 

Да p->data.GetData() может содержать либо просто DIB либо 5ю версию.

Если кто знает другое решение, которое позволит обойти проблему и сохранять данные корректно, или кто пофиксит баг в wxBitmap или хотя бы сформулирует и закинет в трекер, пишите:)