Hatred's Log Place

DON'T PANIC!

Nov 1, 2010 - 3 minute read - programming c++

QFileDialog с Image Preview: метод хакера

В Qt3 была чудная возможность в диалоге открытия интегрировать виджет в котором осуществлять предпросмотра содержимого файла, в частность делать предпросмотр изображений. В Qt4 такую возможность убрали. Да, можно приделать при помощи ItemDelegate кастомное отображение для иконок, и тем самым осуществлять предпросмотр, но не всегда это бывает удобным. Следующий вариант: писать свою реализацию класса для диалога открытия/сохранения. Я же решил попробовать хитрый способ…

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

Итак смыл: наследовать свой класс от QFileDialog, в конструкторе при помощи findChild() по имени искать контейнер в котором располагается виджеты для отображения иконок и быстрых ссылок, приводить его к нужному типу, создавать виджет для предпросмотра, добавлять его в контейнер, при смене файла обновлять содержимое.

Для того, что бы узнать какой контейнер используется (что бы произвести приведение типа) и его имя, нам потребуются исходники Qt, которые скачиваем с сайта Nokia: http://qt.nokia.com, распаковываем, находим файл *qfiledialog.ui// и загружаем его в Qt Designer. После пары минут изучения находим, что контейнер это компонент типа QSplitter и имя у него - splitter. Всё просто и лаконично.

Теперь создаём свой класс, наследуем его от QFileDialog

class MFileDialog : public QFileDialog

В теле класса обязательно ставим Q_OBJECT

в секции private: создаем прототип функции init() - её будем вызвать из конструктора (если вы решитесь объявить их несколько), и указатель на экземпляр класса QLabel - его будем использовать для вывода миниатюры изображения:

private:
    void init();
    QLabel *_preview;

Да, я обычно использую для методов класса одну секцию private/public/etc, а для переменных - другую. Так получается нагляднее.

Далее, сразу вспоминаем, что нам нужно обновлять предпросмотр при смене файла, для этого создадим слот - обработчик сигнала currentChanged(**QString**):

public slots:
    void fileChanged(const QString &file);

Реализации методов init() и fileChanged(**QString** &file) в листинге ниже:

void MFileDialog::init()
{
    _preview = 0;

    // HACK: original file dialog in Qt4 does not have preview functinality
    // Work well on 4.7.1
    QSplitter *splitter = findChild<QSplitter*>("splitter");
    if (splitter == 0)
    {
        return;
    }

    _preview = new QLabel();
    QRect geomerty = _preview->geometry();
    geomerty.setWidth(160); // Настройки геометрии, можно так же сделать что бы рамочка отображалась или что-то вроде 
    _preview->setGeometry(geomerty);

    splitter->addWidget(_preview); // Собсвенно, добавляем наш виджет в контейнер

    // подключаем обработчик сигнала currentChanged
    connect(this, SIGNAL(currentChanged(QString)),
            this, SLOT(fileChanged(QString)));
}

void MFileDialog::fileChanged(const QString &file)
{
    if (_preview == 0)
    {
        return;
    }

    QPixmap pix(file);
    if (pix.isNull())
    {
        _preview->setPixmap(QPixmap());
    }
    else
    {
        // Не зыбываем масштабировать изображение к размеру нашей области просмотра 
        QSize size = _preview->size();
        pix = pix.scaled(size, Qt::KeepAspectRatio);
        _preview->setPixmap(pix);
    }
}

Не забываем в конструкторе вызвать init(), а в деструктор поместить delete _preview. И всё, примерно так это выглядит:

При этом, если даже не будет найдет разделитель с таким именем, диалог не поломается - просто не будет отображаться окошко предпросмотра.

Какие улучшения тут можно сделать? Я думаю как минимум такие:

  1. Установление ограничение на размер файла для которого будет автоматически делаться предпросмотр, ибо загрузка занимает время, а файлы могут быть оооочень большими (у меня, к примеру, есть такие которые не отрываются по причине нехватки памяти).
  2. Вместо QLabel использовать QToolButton и если файл слишком большой отрабатывать нажатие и делать принудительный предпросмотр, либо какие-то другие действия.

PS Кому нужны исходники, пишите на мыло.

Oct 23, 2010 - 2 minute read - programming c++

Qt4 и Custom Types

Известно, что, без преувеличения, основа Qt это moc и их система метатипов. В базе метатипов зарегистрированы все простые C/C++ типы и все сложные Qt типы, часто этого бывает с головой достаточно для написания программ: при использовании QVariant и QSettings или при организации вызовов типа сигнал-слот…

Но бывает, что в качестве параметра сигнала нужно передавать свою структуру или класс, или преобразовывать свой тип в QVariant. Для этого нужно зарегистрировать свой тип перед первым использованием (можно в функции main()), примерно так:

qRegisterMetaType<PhotoFormat>("PhotoFormat");

После этого его можно использовать в качестве параметра в механизме сигнал-слот.

Следующим полезным шагом - приведение нашего типа к QVariant, для этого, в дополнение к предыдущему, в заголовочном файла где располагается объявление нашего типа (на самом деле - в любом месте, но так будет логичнее) нужно разместить такую конструкцию:

Q_DECLARE_METATYPE(PhotoFormat);

Всё, после этого можно использовать подобные конструкции:

QVariant var = qVariantFromValue(PhotoFotmat("Name", 23, 22));
PhotoFormat format = qVariantValue<PhotoFormat>(var);

Ну и последнее, сохранение и восстановление нашего класса при помощи QSettings. Для этого нужно, для начала, зарегистрировать потоковые операторы:

qRegisterMetaTypeStreamOperators<PhotoFormat>("PhotoFormat");

Далее, обычно в заголовочном файле, где объявлен класс, объявляются операторы << и >>:

QDataStream &operator<<(QDataStream &out, const PhotoFormat &obj);
QDataStream &operator>>(QDataStream &in, PhotoFormat &obj);

Обращаю внимание - за пределами class {};

А реализация примерно такая:

QDataStream & operator <<(QDataStream &out, const PhotoFormat &obj)
{
    QString name = obj.getFormatName();
    QSizeF  size = obj.getSize();
    qreal   dst1 = obj.getTopPateDistance();
    qreal   dst2 = obj.getNoseChinDistance();

    out << name << size << dst1 << dst2;
    return out;
}

QDataStream & operator >>(QDataStream &in, PhotoFormat &obj)
{
    QString name;
    QSizeF  size;
    qreal   dst1;
    qreal   dst2;

    in >> name >> size >> dst1 >> dst2;

    obj.setFormanName(name);
    obj.setSize(size);
    obj.setTopPateDistance(dst1);
    obj.setNoseChinDistance(dst2);

    return in;
}

По сути, сериализация класса. Более подробная информация - на странице справки по классу QMetaType, и можно глянуть тут: http://www.crossplatform.ru/?q=node/281

Oct 23, 2010 - 2 minute read - programming c++

Qt4 on Mac OS X

Делал тут небольшую работку, писал программку, которая позволяла таскать линии по холсту и формировать по его данным потом xml файл в заданном формате, который потом превращался в уровень для игры. Заказчик просил ObjectivC и целевая платформа Mac OS X, на мой вопрос о критичности ObjectvC ответил - не суть, предложил написать на Qt4, тем самым покроем, одним махом, три платформы: Linux/Windows/Mac, но будет нуанс - я только примерно знаю как собирать под Mac, в общем, подумав - согласились.

Работу, естественно, я делал под Linux, проверил сборку для Windows (опять таки - кросскомпиляция). Показал результаты (сборку под Win32 и скапченый видеоролик работы в Linux), заказчику понравилось, дальше пошла очередь запуска на Mac OS X…

Первым делом был скачан Qt SDK 2010.05 - бронебойно, но зато всё сразу есть. Собрать получилось без проблем (были ворнинги у линковщика на лишние пути, указанные через атрибут -L, которые реально не существуют, но тут камень в огород создателям SDK). А вот дальше встал вопрос - а как запускать приложение на машинах где нет Qt4? Под windows/linux, в случае распространения бинарников, можно просто положить необходимые dll/so рядом и исполняемым файлов, но в Mac OS X они распространяются в виде бандла (директория с определённой структурой и суффиксом .app). Так вот, что бы собрать всё нужные библиотеки в бандл, разработчики Qt сделали утилиту macdeployqt, которую, после сборки, достаточно натравить на полученное приложение так:

macdeployqt helloworld.app

Тут человек с ником Ayoy, тоже озадачивался подобными вопросами, и рассмотрел более подробно. Так же, он столкнулся с тем, что если используются библиотеки/фреймворки которые используют Qt, после обработки macdeployqt они будут продолжать ссылаться на системные, а не те, что в бандле. Что бы это исправить он написал скрипт на перл, которые позволяет это исправлять: http://gist.github.com/109674

Чуть позже поставлю в виртуалку Mac OS X, посмотрю, может на будущее буду сам делать бандлы, а ещё заинтересовала кросс-компиляция для макоси :)

Oct 13, 2010 - 1 minute read - linux

Пара замечаний

Замечание 1: Qt Creator (одна из последних git сборок)

При включенном отображении Outline в левой панели, при работе появляются значительные тормоза даже на небольших проектах (при моих 1024Мб RAM и Atom 1.6Гц). Решение: выбрать другой режим, тем более что в значительный промежуток времени эта панель вообще не нужна (убирается и вновь показывается при помощи Alt-0), да и есть мощный инструмент Locate (Ctrl-K)

Замечание 2: sshfs и не уходим в sleep

Я активно пользуюсь sshfs для подключения удалённых ресурсов, удобно, быстро, не нужно дополнительных плясок. Недавно стал наблюдать, что система при каких-то условиях перестала засыпать на нетбуке. Опытным путем выяснилось условие: ресурс, примонтированный при помощи sshfs, был отлючен с использованием опции lazy у fusermount (иначе ругался на Resource busy). При этом продолжал висеть процесс sshfs, его убийство после, опять позволяло уводить систему в sleep.

Oct 11, 2010 - 1 minute read -

Crowns 0.5.0

Вышла версия 0.5.0 программы Crowns для построения проекций крон деревьев. Скачать можно тут

В этой версии, основные изменения, касающиеся функционала в целом:

  • Добавлена возможность удалять подложку из проекта.
  • Добавлена возможность экспорта параметров крон деревьев в формат, пригодный для обработки в математических программах типа Octave (100% проверено), Scilab (проверено частично), Mathlab (теоретически должно работать). Т.к. проекции теперь строятся при помощи кривых Безье, то при экспорта с точностью 0.1 выдаются и промежуточные точки для построения полной проекции, теоретически, после обработки данные будут пригодны для загрузки в GIS.
  • Исправлена ошибка, при которой подложка не удалялась при открытии проекта без оной или создании нового проекта.
  • Исправлена ошибка, при которой случайное нажатие клавиши Esc приводило к закрытию окна программы.

Другие изменения, касающиеся технических аспектов разработки:

  • Исправлены вспомогательный скрипты для отстройки и паковки win32 версии из среды Linux.
  • Был осуществлен переход на систему сборки CMake.
  • Исправлено не критическое поведение с float типами при сохранении проекта: значения сохранялись как @Variant(..).

Полный список изменений: ChageLog

Oct 9, 2010 - 1 minute read - programming

Документация по GCC

На правах мемориза.

Тут лежит полная и последняя: http://gcc.gnu.org/onlinedocs/ в различных форматах, берём то, что нужно, а в системе пользуемся инфо

А здесь полезная информация от гентоводов: http://en.gentoo-wiki.com/wiki/Safe_Cflags - безопасные флаги оптимизация для различных процессоров (далее по тексту - ссылки)

Oct 2, 2010 - 9 minute read - programming

Цветовое пространство YUV

Многим знакомо цветовое пространство RGB (Red/Green/Blue), мне потребовалось же работать с входными данными пространства YUV, которое широко используется в семействе кодеков MPEG.

Sep 30, 2010 - 1 minute read - programming c++

На правах заметки Using Visual C++ DLLs with C++Builder

Потребовалось тут собрать для C++Builder DLL, наткнулся походу на такой мануал:

http://bcbjournal.org/articles/vol4/0012/Using_Visual_C_DLLs_with_CBuilder.htm

В мемориз, хотя, надеюсь, оно мне никогда не пригодится, собирать под винду, это ужас…

Sep 28, 2010 - 1 minute read -

FlashBlock в Opera

Полезная ссылка: http://my.opera.com/Lex1/blog/flashblock-for-opera-9/

даны различные рецепты, в том числе очень удобный для Opera 10.5+: просто включить опцию EnableOnDemandPlugin, для чего нужно открыть настройки: opera:config#UserPrefs|EnableOnDemandPlugin, опция автоматически добавится, и можно её включить. Да, это будет работать для любых плагинов.