Записки программиста Программирование и не только

17Авг/160

QBitArray to QByteArray

QByteArray bit2byte(const QBitArray &__bits)
{
    // 
    QByteArray bytes;
    bytes.resize(__bits.count() / 8 + 1);    // Резервируем место
    bytes.fill(0);                           // Заполняем всё нулями

    // Конвертируем из QBitArray в QByteArray
    for(int b = 0; b < __bits.count(); ++b)
    {
        bytes[b/8] = (bytes.at(b/8) | ( (__bits.testBit(b) ? 1 : 0)<<(7-(b%8)) ) );
        // Конструкция (7-(b%8)) даёт прямой порядок. Для обратного (b%8)
    }

    return bytes;
}

Ключевые слова:
qbitarray2qbytearray

Метки записи: , , Нет комментариев
24Дек/120

Qt Digia или где взять?

Итак, знаменитый фреймворк продан сторонней организации.
И первое, что Вы поймёте при заходе на сайт qt.digia.com - скачать Qt просто так Вам больше не удастся.

Итак.
Есть сайт qt-project.org, где всё таки можно скачать последние версии библиотеки Qt.
Бинарники есть только для: 4.6.4, 4.8.4, 5.0.0
Qt creator только: 2.6.1
Все остальные версии доступны в виде исходных кодов тут qt.gitorious.org

MinGW в комплекте больше нет. Для 4.6.4 нужен gcc-4.4.0
Берём тут: mingw-2010.04-as-is.7z

Под Win8 штатный GDB работать отказался.
Брать тут: origin.releases.qt-project.org/gdb

Метки записи: Нет комментариев
26Ноя/121

[Qt] UTF в 1251 и 1251 в UTF

На входе имеем строку в HEX виде, да еще и в кодировке CP-1251. Надо Переделать её в UTF-8
Я использовал для этого QTextCodec.

QByteArray msg = QByteArray::fromHex("cde5eff0e0e2e8ebfcedeee520f1eeeee1f9e5ede8e5204b4f4e5f544d5f484f53544b4e4620eef220d3cad2d121");
QTextCodec *codec = QTextCodec::codecForName("Windows-1251");
QString strf = codec->toUnicode(msg);
qDebug() << strf;

Переварили строчку и надо отправить её обратно, но на выходе нужен CP-1251
Процедура обратная.

QByteArray wtf_s(strf.toStdString().c_str()); //либо так
//wtf_s.append(strf); //либо так

QByteArray wtf = codec->fromUnicode(wtf_s);
qDebug() << wtf.toHex();

Ключевые слова: Qt, UTFtoCP1251, CP1251toUTF

5Июн/120

[Qt] Запись файла в SQLite

Собственно, всё просто
Создали в БД таблицу с атрибутом типа BLOB:

CREATE TABLE fileTable (id_file integer NOT NULL PRIMARY KEY AUTOINCREMENT, file BLOB NOT NULL);

Потом:

    QFile file(QApplication::applicationDirPath().append("/file"));
    file.open(QIODevice::ReadOnly);    //открыли файл
    QByteArray ba = file.readAll();    //прочитали из него всё
    QSqlQuery query(QSqlDatabase::database("sql"));    //
    query.prepare("INSERT INTO fileTable (file) VALUES(:val);");    //создали запрос
    query.bindValue ( ":val", ba);
    query.exec();    //запустили
    file.close();    //файл закрыли

И всё. Ну, естественно, дописали обработку ошибок.

Обратный процесс - чтение файла из SQLite:

    QFile file(QApplication::applicationDirPath().append("/newfile"));
    file.open(QIODevice::WriteOnly);
    QSqlQuery query(QSqlDatabase::database("sql"));

    query.prepare("SELECT file FROM fileTable;");
    query.exec();

    query.next();
    QByteArray ba = query.value(0).toByteArray();
    file.write(ba);
    file.close();
Метки записи: , , , Нет комментариев
28Апр/120

qDebug() и структуры

В дополнении к этому

Есть в классе произвольная структура.
Надо научить её выводиться в qDebug()

Структура:

class MyClass
{
    struct MyStruct
    {
        quint8 a1;
        quint8 a2;
        quint8 a3;
        quint8 a4;
    };
};

Дописываем в *.h :

#ifndef QT_NO_DEBUG_STREAM
QDebug operator<<(QDebug, const MyClass::MyStruct);
#endif

А в *.cpp :

QDebug operator<<(QDebug aDbg, const MyClass::MyStruct strc)
{
    aDbg.nospace() << "( " << "MyStruct" << " ("
                   << strc.a1 << ", "
                   << strc.a2 << ", "
                   << strc.a3 << ", "
                   << strc.a4
                   << ") )";
    return aDbg.space();
}
Метки записи: , , Нет комментариев
20Апр/120

[QtScript] Получить доступ из пользовательской функции к интерфейсу.

Продолжаем извращаться.

Захотелось мне написать свою функцию print для QtScript чтобы вывод шел в QTextEdit.
Класс, который содержит в себе TextEdit у меня зовётся Widget

Функция (Вне классов):

QScriptValue funcPrint(QScriptContext *context, QScriptEngine *engine)
{
    QString result;
    for (int i = 0; i < context->argumentCount(); ++i) {
        if (i > 0)
            result.append(" ");
        result.append(context->argument(i).toString());
    }

    Widget *bgg = (Widget*)engine->parent();
    bgg->print(result);

    return engine->undefinedValue();
}

Регистрируем:

engine->globalObject().setProperty("print", engine->newFunction(funcPrint, 1));

Метод банален:

void Widget::print(QString aStr)
{
    ui->TextEdit->append(aStr);
}

Тонкости:
engine является членом класса Widget (приватным) и инициализируется:

engine = new QScriptEngine(this);

Обязательно указать родителя! Иначе его потом не получить и будет segfault

Соответственно можно объявить engine и не указателем.
Тогда обязательно(!) инициализировать в конструкторе:

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget),
    engine(this)              //!!!!!
{
    ui->setupUi(this);
    ...
}
Метки записи: , , Нет комментариев
19Апр/123

МСВС и Qt

Понадобилось запустить программу под МСВС3.0 (Kernel 2.4.32, gcc-2.95 и 3.3, Qt 4.4.2)
Сама программа писалась под Qt 4.6.3
Отличия 4.6 от 4.4 достаточно существенны, чтобы программы не компилировалась совсем.
Статическая сборка (собиралось под gcc44 и на ядре 2.6+) работать отказалась, мотивируя отказ фразой "Исключение в операции с плавающей точкой (core dumped)"

Решил задачу так.
Qt 4.6 можно собрать только на gcc4, поэтому скачал gcc-4.2, скомпилировал и поставил.
Скачал qt-4.6.3 (qt-everywhere-opensource-src-4.6.3.tar.gz), распаковал, собрал как статику:
./configure -debug-and-release -static -qt-sql-sqlite -no-qt3support -qt-libtiff -qt-libpng -qt-libjpeg -nomake demos -nomake examples -nomake tools -no-webkit -prefix /opt/qt4.6.3static
Всё успешно собралось и установилось.
Creator удалось поставить вот такой версии - qt-creator-linux-x86-gcc3.3-opensource-1.2.1.bin

Проект с программой успешно собрался, но release версия так работать и не захотела. Segmentation fault и всё тут.
Зато debug версия запустилась на ура.

Перетащил на чистый МСВС - не может найти и загрузить libstdc++.so.6
Утаскиваем и её. Положил рядом с бинарником, сделал симлинк ln -s libstdc++.so.6.0.3 /usr/lib/libstdc++.so.6

Всё завелось и полетело. Решить бы еще проблему с release версией... Но это уже не так страшно.

Метки записи: , 3 Комментарии
20Мар/120

[Еще вариант] Отправляем объект из внешней библиотеки в скрипт.

В первом варианте код был жестко завязан на интерфейсный класс плагина.

Как оказалось, можно обойтись и без него.
Для этого надо:
1. В плагине к конструктору добавить служебную конструкцию Q_INVOKABLE. Т.е. должно получиться так:

Q_INVOKABLE explicit ScriptObject(QObject *parent = 0);

А в основной программе нужно убрать строку с приведением qobject_cast и заменить строку с регистрацией объекта в движке на вот такую:

QScriptValue scObj = engine.newQObject(plugin->metaObject()->newInstance(), QScriptEngine::ScriptOwnership);

И всё! Никакой привязки к интерфейсу!

Теперь буду разбираться с тем, как бы всё это безобразие соединять сигналами. Как-нибудь по динамичнее.

upd: Не забываем в после засовывания объекта в скрипт его там зарегистрировать.

engine.globalObject().setProperty("ScObj", scObj);
Метки записи: , , Нет комментариев
20Мар/120

Отправляем объект из внешней библиотеки в скрипт

В Qt, как известно, есть замечательная вещь как QScript, позволяющая использовать ECMA скрипт.
В данный скриптовый движок возможно запихивать как отдельные функции, так и целые объекты.
А можно ли запихать в движок объект из внешней библиотеки (.dll, .so etc)?

Оказывается, что можно.

Метки записи: , , , Читать полностью
21Фев/120

QHash и структура в качестве ключа.

Тема легкая, но мне, почему-то далась достаточно напряжно.

Задача: использовать в качестве ключа QHash структуру.
Читаем документацию - для данной операции достаточно в структуре определить оператор "==" и написать глобальную функцию qHash для нашей структуры.

Решение:

struct MyStruct
{
    quint8 a1;
    quint8 a2;
    quint8 a3;
    quint8 a4;
    bool operator==(const MyStruct struc) const
    {
        return (a1 == struc.a1 &&
                a2 == struc.a2 &&
                a3 == struc.a3 &&
                a4 == struc.a4);
    }
};
uint qHash(const MyStruct &struc)
{
    //как-то вычисляем хеш
    //в моём случае в структуре содержалось 4 целых числа и я просто записал их в одно число со сдвигом
    uint result = struc.a1;

    result <<=(sizeof(quint8)*8);
    result = result|struc.a2;

    result <<=(sizeof(quint8)*8);
    result = result|struc.a3;

    result <<=(sizeof(quint8)*8);
    result = result|struc.a4;
    return result;
}

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

QHash < MyStruct, QString > myQHash

Всё работает отлично.

А вот при попытке использовать еще одну структуру в качестве значения QHash

QHash < MyStruct, MyOtherStruct > myOtherQHash

При запросе значения по ключу - всё работает отлично, но при попытке получить ключ по значению получаем надпись:

no match for 'operator==' in 'i.QHash<Key, T>::const_iterator::value [with Key = MyStruct, T = MyOtherStruct]() == avalue'

Страшная надпись, не правда ли? :)

Причина - не хватает операции "==" во второй структуре. Добавляем её и всё работает.
Вот так.

struct, key, qhash

Метки записи: , Нет комментариев