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
Для чего нужен union
Продолжаю открывать для себя С++...
Объединение служит для, как бы это ни казалось странным, объединения.
Это позволяет, записывая данные в одно поле union'а, одновременно получать эти же данные в другом поле. Причем поля могут быть разные по содержимому.
Пример:
typedef struct
{
unsigned short fbNVRIncorrectCRC :1;
unsigned short fbConfigIncorrectCRC :1;
unsigned short fbSPIInterfaceError :1;
unsigned short fbMFIncorrectCRC :1;
unsigned short fbMFWriteError :1;
unsigned short fbMFNotInstalled :1;
unsigned short fbEEJFatalError :1;
unsigned short fbUnused1 :1;
unsigned short fbNotInitialized :1;
unsigned short fbNonFiscalMode :1;
unsigned short fbShiftOpened :1;
unsigned short fb24HourOverflow :1;
unsigned short fbEEJArchieveClosed :1;
unsigned short fbEEJNotActivated :1;
unsigned short fbMFNoMemoryForShift :1;
unsigned short fbMFWrongPassword :1;
unsigned char dbDocumentType;
} ST_FRSTATUS;
typedef union
{
ST_FRSTATUS stStatus;
unsigned char dbStatus[3];
} UN_FRSTATUS;
И теперь можно записать данные в массив unsigned char dbStatus[3]; и потом получить их из структуры уже разобранными.
Т.е. можно обратиться к dbStatus[2] и к stStatus.dbDocumentType и получить один и тот же результат.
Единственное - нельзя обращаться по разным именам в одном блоке программы..
Вынести определение массива структур в другой файл
В продолжении к красоте
Объявляем (declaration)
//st.h
enum {
/* I/O ERRORS */
ERR_INVALID_STATUS = 0x01,
ERR_INVALID_FUNCTION = 0x02
};
struct fr_errs_struct
{
int err;
const char * const msg;
};
extern struct fr_errs_struct fr_errs [];
Определяем (definition)
//st.cpp
#include <st.h>
struct fr_errs_struct fr_errs [] = {
{ERR_INVALID_STATUS, "Функция невыполнима при данном статусе"},
{ERR_INVALID_FUNCTION, "В команде указан неверный номер функции"},
{0, ""}
};
Ну и функция для использования всего этого
const char* getText(int aErr)
{
int i = 0;
while(fr_errs[i].err && fr_errs[i].err != aErr)
{
i++;
}
return fr_errs[i].msg;
}
…
Красота:
enum {
/* I/O ERRORS */
ERR_INVALID_STATUS = 0x01,
ERR_INVALID_FUNCTION = 0x02
};
struct
{
int err;
const char * const msg;
} fr_errs [] = {
{ERR_INVALID_STATUS, "Функция невыполнима при данном статусе"},
{ERR_INVALID_FUNCTION, "В команде указан неверный номер функции"}
{0, ""}
};
[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
[Android NDK] Unable to find native library
Пытаясь собрать пример из NDK получаю вот такую ошибку:
Caused by: java.lang.IllegalArgumentException: Unable to find native library: native-activity
Весь интернет пишет какую-то ересь типа:
"Поправьте в AndroidManifest.xml строчку android:hasCode="false" на android:hasCode="true" и будет вам счастье"
А вот хер! Никакого эффекта.
Так бы и закончилось моё желание писать на С++ под Дроида, но тут я натыкаюсь на отличную ссылочку:
http://mobilepearls.com/labs/ndk-builder-in-eclipse/
Получается, что проблема в самом Эклипсе, блин.
Коротко:
1. Заходим в Properties проекта в раздел Builders. Жмём New...
2. Выбираем тип Program и жмём Ok
3. Location указываем путь до ndk-builer'а (я указал абсолютный путь. Под Вин это звучит так: <путь в системе>\android-ndk-r8\ndk-build.cmd)
4. Working directory - путь до папки с проектом (Моё: <путь в системе>\android-ndk-r8\samples\native-activity
5. На том же окошке переходим во вкладку Refresh, ставим галочку и выбираем Specific resources. Разворачиваем проект и ставим галочку на lib. Finish
6. Вкладка Build Options. Проверяем наличие галочки на During auto builds и ставим галку на Specify working set of relevant resources. Разворачиваем проект и ставим галочку на jni
7. Жмем Apply, Ok, Ok
Не забываем нажать Project/Clean
Всё, теперь проект запускается без ошибок.
[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();
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();
}
[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);
...
}
[Еще вариант] Отправляем объект из внешней библиотеки в скрипт.
В первом варианте код был жестко завязан на интерфейсный класс плагина.
Как оказалось, можно обойтись и без него.
Для этого надо:
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);