Последнее обновление:
August 9, 2018

Есть мысль... Жми, напиши!
Что имеем: Постов : 178 Авторов: 1 Категорий: 38

Qt настраиваем логирование в проекте (формат лога)

Приветствую!

Отладочные сообщения в QtCreator достаточно не информативные, особенно в большом проекте, а каждый раз прописывать  что-то вроде:

qDebug()<<"MyClass::functionName params"<<p1<<p2;

что бы знать в каком хоть классе и функции идёт вывод достаточно долго.

Можно перехватить вывод qDebug, а заодно qInfo, qWarning и т.д. и выводить их в файл логов (либо писать в базу, либо отправлять на лог-сервер).

Делается это так:

в main.cpp  сразу после QApplication app(…); прописываем:

 qInstallMessageHandler(myMessageHandler);

В *.pro файле добавляем:

DEFINES += QT_MESSAGELOGCONTEXT

что бы обрабатывался контекст вызова, ну и делаем свой обработчик вывода:

#include <QDateTime>
void myMessageHandler(QtMsgType type, const QMessageLogContext& context, const QString &msg)
{
    QString txt;   
    static long long uid=0; //-- номеруем вывод
    //-- название функции с классом, берём только класс и саму функцию
    QRegExp rx("([\\w-]+::[\\w-]+)");
    if (rx.indexIn(context.function) ==-1) return;
    QString function = rx.cap(1);

    QString msgSep = (msg.length()>0)? ">> " : "";

    switch (type) {
        case QtInfoMsg:
            txt = QString("Info: %1%2%3").arg(function).arg(msgSep).arg(msg);
        break;
        case QtDebugMsg:
            txt = QString("Debug: %1%2%3").arg(function).arg(msgSep).arg(msg);
            break;
        case QtWarningMsg:
            txt = QString("Warning: %1%2%3").arg(function).arg(msgSep).arg(msg);
        break;
        case QtCriticalMsg:
            txt = QString("Critical: %1%2%3").arg(function).arg(msgSep).arg(msg);
        break;
        case QtFatalMsg:
            txt = QString("Fatal: %1%2%3").arg(function).arg(msgSep).arg(msg);
            abort();
        break;
    }

    QDateTime dateTime = QDateTime::currentDateTime();
    uid++;
    txt=QString("%1:%2 %3").arg(dateTime.toString(Qt::ISODate)).arg(uid).arg(txt);

    QFile outFile(QString("%1/log-%2.log").arg(".").arg(QDate::currentDate().toString("dd.MM.yy")));
    outFile.open(QIODevice::WriteOnly | QIODevice::Append);
    QTextStream ts(&outFile);
    ts << txt << endl;
    outFile.close();


}

Дальше, если у вас Линь, то достаточно просто в консольке прописать:

tail -f  log-18.09.16.log

и весь вывод будет идти в реал тайме.

Если разбор выражения на отдельные поля не требуется, то можно сразу задать шаблон вывода:

в main.cpp перед QApplication  прописать:

qSetMessagePattern("%{type} %{if-category}%{category}: %{endif}%{function}: %{message}");

Подробнее можно найти в офф. доках: http://doc.qt.io/qt-5/qtglobal.html#qSetMessagePattern

Вот как-то так =)

Views :

1126

Android MySql (QMysql) драйвер для Qt5.6 на Windows и Linux компиляция

В общем понадобилось портировать одну прогу под Андроид arm7, но она плотненько работает с базой данных, а так как я человек впринципе ленивый, то обёртку для REST API сервера было лень писать, решился на компилирование MySQL плагина, но если бы я знал тогда, что это займёт у меня 20 часов…
красноглазик

 

В общем вот вам готовый рецепт из 12 шагов для компиляции на Ubuntu и на Windows
То, что помечено windows16 -выполнять только на винде.
Установим инструменты:
1. Качаем и устанавливаем CMake https://cmake.org/download/ у меня 3.5.2
2. Разумеется Android NDK у вас уже должен быть установлен, но вдруг: https://developer.android.com/tools/sdk/ndk/index.html
windows163. Качаем и ставим MSYS https://sourceforge.net/projects/mingw/files/latest/download?source=files (отмечаем всё, что можно)
4. При установке Qt нужно было поставить и исходники (папка qt/5.6/src/qtbase), если нет её, то качаем и ставим
windows165. Открываем консольку MSYS (c:\mingw\msys\1.0\msys.bat), в дальнейшем все действия будут вестись в ней и для удобства выкачивания установим wget:

/c/mingw/bin/mingw-get install msys-wget-bin

1. Создадим отдельную директорию, где будем развлекаться и перейдём в неё:

mkdir /d/Projects/AndroidMySQL
 cd /d/Projects/AndroidMySQL

2. Выкачиваем саму MariaDB, а именно коннектор

wget https://downloads.mariadb.org/interstitial/connector-c-3.0.0/mariadb-connector-c-3.0.0-alpha-src.tar.gz
 tar -xzvf mariadb-connector-c-3.0.0-alpha-src.tar.gz

3. Выкачиваем и распаковываем исходники iconv http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz

wget http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.14.tar.gz
 tar -xvzf libiconv-1.14.tar.gz

4. Выкачиваем и распаковываем OpenSSL

wget -c http://www.openssl.org/source/openssl-1.0.1h.tar.gz --no-check-certificate
 tar -xvzf openssl-1.0.1h.tar.gz

5. Задаём общие глобальные переменные
windows16

 export PATH="$PATH:/c/mingw/bin:/c/Program Files (x86)/CMake/bin"
 export ANDROID_NDK_ROOT=/d/Android/android-ndk-r10e
 export SR="$ANDROID_NDK_ROOT"/platforms/android-19/arch-arm/usr # Укажите платформу, под которую собираете ваши проекты (Лучше, 19)
 export BR="$ANDROID_NDK_ROOT"/toolchains/arm-linux-androideabi-4.9/prebuilt/windows-x86_64/bin/arm-linux-androideabi-
 export CPP="$BR"cpp
 export AR="$BR"ar
 export STRIP="$BR"strip
 export RANLIB="$BR"ranlib
 export LINKER="$BR"ld
 export OBJDUMP="$BR"objdump
 export CC="$BR"gcc
 export CFLAGS="--sysroot=$SR"
 export CPPFLAGS="$CFLAGS"
 export C_INCLUDE_PATH=$SR/include
 export ANDROID_DEV=$SR/usr
 export MAKEDEPPROG="$CC -M"

6. Собираем сначала iconv

cd libiconv-1.14
 ./configure --host=arm --prefix=$SR/usr --with-sysroot=$SR
 make
 make install

7. Собираем OpenSSL

cd ../openssl-1.0.1h
 CC="$CC -march=armv7-a -mfloat-abi=softfp"
 ./Configure android-armv7 --prefix=$SR/usr no-asm
 make
 make install
 make install_sw
Если заматериться error: undefined reference to ‘__ctype_get_mb_cur_max’,
то в файл libcharset/lib/localcharset.c после дефайнов добавляем

size_t __ctype_get_mb_cur_max(void){
 return 1;
 }

8. Нус, начинаем подготовку к сборке MariaDB

В файл include/my_global.h необходимо добавить определение типа ushort

#ifndef ushort
 #define ushort uint16
 #endif

9. Подготавливаем сборку

cd ../mariadb-connector-c-3.0.0-alpha-src
mkdir build
 cd build
cmake -G "Unix Makefiles"
 -DCMAKE_BUILD_TYPE=Release \
 -DCMAKE_AR="$BR"ar.exe \
 -DCMAKE_C_COMPILER="$BR"gcc.exe \
 -DCMAKE_C_FLAGS=--sysroot=$SR \
 -DCMAKE_LINKER="$BR"ld.exe \
 -DCMAKE_RANLIB="$BR"ranlib.exe \
 -DCMAKE_STRIP="$BR"strip.exe \
 -DCMAKE_SYSTEM_NAME=Linux \
 -DICONV_INCLUDE_DIR="$SR/usr/include" \
 -DICONV_LIBRARIES="$SR/usr/lib/libiconv.a" \
 -DOPENSSL_ROOT_DIR="$SR/usr/lib/" \
 ../

10. Зажмуриваемся и собираем

make
windows16 ага, фиг то там, failed to create symbolic link ‘libmysqlclient.a’: No error
внезапно… тут, похоже, баг самого CMake, поэтому в файле
\AndroidMySQL\mariadb-connector-c-3.0.0-alpha-src\build\libmariadb\CMakeFiles\SYM_libmysqlclient.a.dir\build.make
находим строки (их по две) c -E create_symlink libmariadbclient.a libmysqlclient.a, удаляем её полностью
а так же -E create_symlink libmariadb.so libmysqlclient_r.so аналогично
и вручную копируем и продолжаем сборку

cp libmariadb/libmariadbclient.a libmariadb/libmysqlclient.a
 cp libmariadb/libmariadbclient.a libmariadb/libmysqlclient_r.a
 cp libmariadb/libmariadb.so libmariadb/libmysqlclient.so
 cp libmariadb/libmariadb.so libmariadb/libmysqlclient_r.so
 make
и ещё раз фиг error: unknown type name ‘pthread_mutex_t’
в файле ../unittest/libmariadb/thread.c
находим pthread_t threads[THREAD_NUM]; заменяем на void * threads[THREAD_NUM];
и там же заменяем pthread_mutex_t LOCK_test; на void * LOCK_test;
и опять
make

На этот раз должно всё ок пройти, ну и устанавливаем и копируем к нашему ndk

make install
mkdir "$SR/usr/lib/mariadb"
 mkdir "$SR/usr/include/mariadb/"
 cp libmariadb/*.{a,so} "$SR/usr/lib/mariadb/"
 cp ../include/* "$SR/usr/include/mariadb/"

11. Собираем плагин QMySQL, открываем обычную консольку пути только на свои замените

cd /d/Qt/5.6/Src/qtbase/src/plugins/sqldrivers/mysql/
 /d/Qt/5.6/android_armv7/bin/qmake.exe \
 "INCLUDEPATH+=$SR/usr/include/mariadb" \
 "LIBS+=-L$SR/usr/lib/mariadb -lmariadbclient -lssl -lcrypto -liconv" \
 -o Makefile mysql.pro
make
 make install

12. Разрабатываем тестовый проект
Так как зависит от libmariadb.so, то его необходимо таскать с проектом, для этого в *.pro файле проекта добавить

contains(ANDROID_TARGET_ARCH,armeabi-v7a) {
 ANDROID_EXTRA_LIBS = \
 d:/Projects/AndroidMySQL/mariadb-connector-c-3.0.0-alpha-src/build/libmariadb/libmariadb.so
 }

Пересобираем проект, запускаем, и хуй то там =)
QMYSQL driver not loaded
яоминь
Посмотрим зависимости libqsqlmysql.so, которая в каталоге /home/pavelk/Qt/5.6/android_armv7/plugins/sqldrivers

ldd libqsqlmysql.so

и опять облом, нужна ldd для arm, ладно и с этим разберёмся, например так, тынц.

ldd-avr libqsqlmysql.so

Дело в том, что в зависимостях у libmysql.so есть libmariadb.so.3, а не libmariadb.so
почуяли разницу? =))

В общем, что бы побыстроляну пофиксить
в файле libmariadb/CMakeLists.txt
находим

SOVERSION ${CPACK_PACKAGE_VERSION_MAJOR})

и заменяем на

SOVERSION "so")

ну а дальше удалить полностью build и заново, начиная с 9 шага
troll

!пересобираем! проект, не забыть исправить в pro файле на libmariadb.so.so запускаем и радуемся =)

Итого: сэкономлено куча времени и нервов. Хоть спасибо скажите =))

Views :

1022

Qt Android JNI преобразование QByteArray в jbytearray и обратно, а так же получение и передача в jni функцию

Подребовалось мне из Java класса вызвать функцию, наподобии этой:

public int send(byte[] data)
{     
....
}

Ну а что бы её вызвать из C++ нужно было преобразовать QByteArray в jbytearray
делается это так:

    jbyteArray QByteArray2jbyteArray(QByteArray buf)
    {
     QAndroidJniEnvironment env;
     jbyteArray array = env->NewByteArray(buf.length());
     env->SetByteArrayRegion (array, 0, buf.length(), reinterpret_cast<jbyte*>(buf.data()));
     return array;
    }

если нужно обратное преобразование, то делается так:

QByteArray jbyteArray2QByteArray(jbyteArray buf)
    {
       QAndroidJniEnvironment env;
       int len = env->GetArrayLength(buf);
       QByteArray array;
       array.resize(len);
       env->GetByteArrayRegion (buf, 0, len, reinterpret_cast<jbyte*>(array.data()));
       return array;
    }

ну а саму функцию из Java класса с помощью JNI можно вызвать так:

QAndroidJniObject myActivity=  QtAndroid::androidActivity();
myActivity.callMethod<int>("send", "([B)I", QByteArray2jbytearray(myByteArray));

Если нужно наоборот вернуть из функции jbytearray, то тут немного по сложнее:

QAndroidJniObject myActivity=  QtAndroid::androidActivity();
QAndroidJniObject readData = myActivity.callObjectMethod("read", "(V)[B");
jbyteArray array =readData.object<jbyteArray>();

Кстати, не забываем подключать заголовочники:

#include <QtAndroid>
#include <QAndroidJniEnvironment>
#include <QAndroidJniObject>

И в *.pro файле добавлять

QT +=  androidextras

Вот как то так =)

Views :

702

Печатаем на фискальнике Custom VKP-80K из c++ на Qt

В общем задача была разобраться с печатью именно фискалки, благо с обычной печатью всё просто, попробуем теперь с ним.

Т.к. дела раньше с фискальниками почти не имел, ссался, что в нём уже стоит ЭКЛЗ и все мои тестовые продажи Нидерландов уйдут в память, а потом при проверке налоговая не досчитается несколько ВВП,

но всё оказалась проще, ЭКЛЗ нет, а в сервисе сказали, что даётся 1000 тестовых печатей, пока там какая-то память не включиться, чтож, ок.

 

Первым делом как обычно качаем драйвера OPOS. Почему OPOS ? Лично я уже просто привык. У меня через них работает и чекопечатник и сканер штрих-кодов и печатник штрих-кодов и карт ридер и по мелочи разные фентифлюшки и в случай их замены не придётся пол протокола переписывать.

Дальше ставим непосредственно драйвера фискальника. Скорее всего это будет АТОЛ в рот ему ноги (версия 4.18). Ставим как обычно.

Проверить фискальник можно зайдя в папку с дровами и запустив (C:\Program Files\АТОЛ\Drivers\Bin\FPRNM_T.exe)

справа внизу клацаете галку устройство включено, вверху справа выбираете режим «1 регистрация», жамкаете «Войти»,

затем непосредственно продаёте: переходите на таб  «Регистрация» жамкаете на   «Продажа» и затем «Закрыть чек без сдачи».

Должен вылезти чек. За ошибками смотреть внизу в поле «Результат»

Так, теперь пора бы и начать кодить, а фиг там.

Ещё нужно сгенерировать заголовочник и реализацию для OPOS, а если точнее для ActiveX компонента, т.к. работа идёт через него.

Запускаем консольку, вбиваем:

cd C:\Projects\VKP-80K\
C:\Qt\5.4\mingw491_32\bin\dumpcpp "C:\Program Files (x86)\OPOS\CommonCO\OPOSFiscalPrinter.ocx"

Ток пути на свои замените.

В папке C:\Projects\VKP-80K\  должны появится вожделенные заголовочник и реализация.

Так же в эту папку не помешает кинуть заголовочник с константами OposFptr.h и Opos.h (из папки с установленными OPOS)

А вот теперь можно и покодить.

Создаём новый проектик (у меня простой консольный) и сразу в .pro файл добавляем

CONFIG += qaxcontainer # Для работы с ActiveX

Дальше в main.cpp подключаем наш заголовочник, константы, и заодно пространство имён (откройте заголовочник, вверху увидите), в моём случае

#include "oposfiscalprinter_cco.h"
#include "OposFptr.h"
using namespace OposFiscalPrinter_CCO;

Ну и теперь печатаем нашу продажу, приведу код с комментами, там всё просто:

OPOSFiscalPrinter * ECR;

ECR = new OPOSFiscalPrinter();

ECR->Open(""); //-- Подключаемся. Стандартное имя для этой фискалки, ищите в инструкции
ECR->ClaimDevice(1000); //-- Захватываем
ECR->SetDeviceEnabled(true); //-- Включаем

ECR->ResetPrinter(); //-- сбрасываем состояние в дефолтное

ECR->SetFiscalReceiptType(FPTR_RT_SALES); //-- Говорим, что начинаем продажу

ECR->BeginFiscalReceipt(false); //-- Начинаем печатать фискальный чек

int summ = 123;
int count = 1;

ECR->PrintRecItem( "ТЕСТ ПРОДАЖИ" , summ ,  count*1000, 0 , summ , "psc" ); //-- Печатаем продажу. count*1000 не ошибка, так надо =) 

int salesSumm =123; //-- нам нужно при окончании указать точную сумму всех операций, иначе чек будет анулирован

ECR->PrintRecTotal(salesSumm,  salesSumm , "1"); //-- печатаем итоговую сумму, сколько внесено, валюту.

ECR->PrintRecMessage("Тест прошёл успешно"); //-- кастомные сообщений после основной части текста

ECR->EndFiscalReceipt(false); //-- завершаем фискальник и выплёвываем его

ECR->PrintZReport(); //-- по-приколу распечатаем z-отчёт. P.S. должны быть промежутки между печатью z-ки, у меня принтер раньше, чем каждые 2 часа не давал.

ECR->SetDeviceEnabled(false);
ECR->close();

Вот так вот =)  Надеюсь всё получилось.

 

И на десерт — в Qt 5.5 не печатает на фискалке копейки 😀 в чём проблема я разобрался, но на это ушла вся ночь, поэтому решение за отдельную плату,  сами разберётесь, там просто оказывается.

 

Views :

630

OpenCV 3.1 захват видео с камеры в Qt 5.6

Надеюсь, компиляция прошла успешно =)

Обновил на новый лад с использованием Mat

Создаём новый консольный проект, в .pro файле дописываем:

INCLUDEPATH += "/usr/local/opencv/3.1/include/"
LIBS += -L"/usr/local/opencv/3.1/lib/"
LIBS += -lopencv_core \
        -lopencv_features2d \
        -lopencv_highgui \
        -lopencv_imgcodecs \
        -lopencv_imgproc \
        -lopencv_video \
        -lopencv_videoio \
        -lopencv_videostab

Теперь основное main.cpp:

#include <QApplication>
#include <QDebug>

#include <opencv2/opencv.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    qDebug()<<"Hello world";

    //-- Выбираем первую попавшуюся камеру
    VideoCapture cap(0);

    //-- Проверяем, удалось ли подключиться
    if (!cap.isOpened()) {
        qDebug()<<"Camera not opened!";
        return 0;
    }

    //-- Выставляем параметры камеры ширину и высоту кадра в пикселях
    cap.set(CV_CAP_PROP_FRAME_WIDTH, 1280);
    cap.set(CV_CAP_PROP_FRAME_HEIGHT, 960);

    Mat frame;

    while (true) {
        cap >> frame; //-- захватываем очередной кадр

        imshow("Video", frame); //-- показываем его

        char c = cvWaitKey(33); //-- если была нажата клавиша, узнаём её код

        if (c==27) { //-- нажата ESC, прерываем цикл
            break;
        }

    }


    return app.exec();
}

Впринципе, ничего сложного.

Views :

5210

PoDoFo сборка для Qt на Ubuntu 14.10

PoDoFO

PoDoFo это библиотека для чтения и записи PDF файлов.

Для Windows мануал здесь.

Создаём папку, в которой будет идти вся сборка, у меня это ~/Projects/PoDoFO/

Скачиваем саму PoDoFO
Распаковываем файлы архива в папку  podofo-src

Ещё понадобиться LibJpeg
Распаковываем файлы в папку jpeg-9a
Компилируем LibJpeg.
В терминале:

cd ~/Projects/PoDoFo/jpeg-9a/
./configure
make
sudo make install

Так же потребуется LibPng, устанавливаем так:

sudo apt-get install libpng-dev

Теперь, наконец-то, собираем сам PoDoFo

cd  ~/Projects/PoDoFO/podofo-build/
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="$HOME/Projects/PoDoFo/lib" ../podofo-src
make
sudo make install

Библиотека скомпилирована! Всё необходимое будет в папке ~/Projects/PoDoFo/lib

Документация по PoDoFo здесь.

Исходники тестового проекта Qt и PoDoFo.

Views :

687

Установка и печать на термопринтере VKP-80II из Qt 5

Прилетела на днях сия  игрушка.
Применений к ней куча — всё зависит от фантазии.

Сейчас расскажу как на нём печатать из Qt.

Первым делом идём на сайт производителя за дровами, да не простыми, а OPOS.

Вставим чековую ленту в принтер, теперь вынимаем питание, зажимаем верхнюю кнопку (Line feed), включаем питание, ждём пока зажужжит и отпускаем кнопку.

Напечатаются настройки и жмём снова верхнюю кнопку (Line feed) что бы принтер выплюнул ленту.

С ленты нас интересует только параметры RS232, они сейчас потребуются.

Запускаем установку дров, указываем способ соединения и параметры скорости (по умолчанию 19200) и прочие, при необходимости.

Для теста, запускаем OPOS POS Printer configurator и настраиваем параметры.

В нём мы настраиваем как связатсья с принтером через OPOS драйвер. Запомните device name — оно нам пригодится.

Потом запускаем OPOS POS Printer test и можно немного поиграться.

Если всё работает, то пора создавать новый Qt проект (тип — на ваш выбор).

Всё общение с термопринтером идёт через ActiveX компонент OPOSPOSPrinter.ocx, поэтому сейчас заодно покажу как работать с ActiveX в Qt.

Для работы нам нужно получить от библиотеки реализацию cpp и h файлов с помощью утилитки, входящую в состав Qt — dumpcpp.

Открываем виндузятную консольку, переходим в каталог, где будем создавать классы, и запускаем dumpcpp:

cd C:\Projects\1CTerminal\1CTerminal\opos
dumpcpp "C:\Program Files (x86)\OLEForRetail\ServiceOPOS\POSPrinter\CustomEngineering\OPOSPOSPrinter.ocx"

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

Т.е. как минимум узнаём пространство имён (OposPOSPrinter_1_9_Lib) и название класса (OPOSPOSPrinter).

В *.pro файле проекта добавляем:

CONFIG += qaxcontainer # Для работы с ActiveX

Добавляем в проект сгенерированные файлы oposposprinter_1_9_lib.cpp и oposposprinter_1_9_lib.h

Заодно добавьте следующий заголовочный файл, в нём собрал все используемые статусные сообщения:

Заголовочник opos/oposprinter_consts.h

//-- Коды результата
namespace OposPOSPrinter_1_9_Lib {

    #define OPOS_SUCCESS            0
    #define OPOS_E_CLOSED           101
    #define OPOS_E_CLAIMED          102
    #define OPOS_E_NOTCLAIMED       103
    #define OPOS_E_NOSERVICE        104
    #define OPOS_E_DISABLED         105
    #define OPOS_E_ILLEGAL          106
    #define OPOS_E_NOHARDWARE       107
    #define OPOS_E_OFFLINE          108
    #define OPOS_E_NOEXIST          109
    #define OPOS_E_EXISTS           110
    #define OPOS_E_FAILURE          111
    #define OPOS_E_TIMEOUT          112
    #define OPOS_E_BUSY             113
    #define OPOS_E_EXTENDED         114

    #define strOPOS_SUCCESS         "OPOS_SUCCESS"
    #define strOPOS_E_CLOSED        "OPOS_E_CLOSED"
    #define strOPOS_E_CLAIMED       "OPOS_E_CLAIMED"
    #define strOPOS_E_NOTCLAIMED    "OPOS_E_NOTCLAIMED"
    #define strOPOS_E_NOSERVICE     "OPOS_E_NOSERVICE"
    #define strOPOS_E_DISABLED      "OPOS_E_DISABLED"
    #define strOPOS_E_ILLEGAL       "OPOS_E_ILLEGAL"
    #define strOPOS_E_NOHARDWARE    "OPOS_E_NOHARDWARE"
    #define strOPOS_E_OFFLINE       "OPOS_E_OFFLINE"
    #define strOPOS_E_NOEXIST       "OPOS_E_NOEXISTS"
    #define strOPOS_E_EXISTS        "OPOS_E_EXISTS"
    #define strOPOS_E_FAILURE       "OPOS_E_FAILURE"
    #define strOPOS_E_TIMEOUT       "OPOS_E_TIMEOUT"
    #define strOPOS_E_BUSY          "OPOS_E_BUSY"
    #define strOPOS_E_EXTENDED      "OPOS_E_EXTENDED"

    //-- Коды состояний
    #define PTR_S_RECEIPT           2

    //-- Коды параметров
    #define PTR_SUE_COVER_OPEN      11
    #define PTR_SUE_COVER_OK        12

    #define PTR_SUE_JRN_EMPTY       21
    #define PTR_SUE_JRN_NEAREMPTY   22
    #define PTR_SUE_JRN_PAPEROK     23

    #define PTR_SUE_REC_EMPTY       24
    #define PTR_SUE_REC_NEAREMPTY   25
    #define PTR_SUE_REC_PAPEROK     26

    #define PTR_SUE_SLP_EMPTY       27
    #define PTR_SUE_SLP_NEAREMPTY   28
    #define PTR_SUE_SLP_PAPEROK     29

    #define PTR_SUE_JRN_CARTRIDGE_EMPTY         41
    #define PTR_SUE_JRN_CARTRIDGE_NEAREMPTY     42
    #define PTR_SUE_JRN_HEAD_CLEANING           43
    #define PTR_SUE_JRN_CARTRIDGE_OK            44

    #define PTR_SUE_REC_CARTRIDGE_EMPTY         45
    #define PTR_SUE_REC_CARTRIDGE_NEAREMPTY     46
    #define PTR_SUE_REC_HEAD_CLEANING           47
    #define PTR_SUE_REC_CARTRIDGE_OK            48

    #define PTR_SUE_SLP_CARTRIDGE_EMPTY         49
    #define PTR_SUE_SLP_CARTRIDGE_NEAREMPTY     50
    #define PTR_SUE_SLP_HEAD_CLEANING           51
    #define PTR_SUE_SLP_CARTRIDGE_OK            52

    #define PTR_SUE_IDLE                        1001

    #define strPTR_SUE_COVER_OPEN               "PTR_SUE_COVER_OPEN"
    #define strPTR_SUE_COVER_OK                 "PTR_SUE_COVER_OK"
    #define strPTR_SUE_REC_EMPTY                "PTR_SUE_REC_EMPTY"
    #define strPTR_SUE_REC_NEAREMPTY            "PTR_SUE_REC_NEAREMPTY"
    #define strPTR_SUE_REC_PAPEROK              "PTR_SUE_REC_PAPEROK"
    #define strPTR_SUE_IDLE                     "PTR_SUE_IDLE"

    #define PTR_BM_ASIS                         -11
    #define PTR_BM_CENTER                       -2

    #define PTR_BCS_UPCA                        101
    #define PTR_BCS_UPCE                        102
    #define PTR_BCS_EAN128                      120
    #define PTR_BCS_Code128                     110


    #define PTR_BC_TEXT_ABOVE                   -12
    #define PTR_BC_TEXT_BELOW                   -13
    #define PTR_BC_CENTER                       -2

}

#endif // OPOSPRINTER_CONSTS_H

Так же создадим новый класс, например Printer, в котором будем осуществлять непосредственно печать.

Дальше я разбирался с помощью интуиции и примерного проекта (В основном: C:\Program Files (x86)\OLEForRetail\ServiceOPOS\POSPrinter\CustomEngineering\OPOSPOSPrinterTest_Src\FormMainApp.frm).

Printer.h:

#ifndef PRINTER_H
#define PRINTER_H

#include "opos/oposposprinter_1_9_lib.h"
#include "opos/oposprinter_consts.h"
using namespace OposPOSPrinter_1_9_Lib;

class Printer : public QObject
{
   Q_OBJECT
public:
   explicit Printer(QObject *parent = 0);

signals:
public slots:
private:
   IOPOSPOSPrinter * oposPrinter;
};
#endif // PRINTER_H

и printer.cpp

#include "printer.h"

Printer::Printer(QObject *parent) :
QObject(parent)
{
   oposPrinter = new IOPOSPOSPrinter();
   oposPrinter->setControl("{ccb90152-b81e-11d2-ab74-0040054c3719}");
   int res = oposPrinter->Open("Custom POS Printer");
   qDebug()<<"Open sataus: "<<res;
   oposPrinter->ClaimDevice(100);
   oposPrinter->SetDeviceEnabled(true);
   oposPrinter->PrintImmediate(2, "Hello, QT!, Привет, мир!" );
   oposPrinter->CutPaper(100);
   oposPrinter->Close();
}

Надеюсь, запечатает. На этом всё =)

Архивчик со вспомогательным классом: Printer

В printer.cpp заменить  AppSettings()->value(«com_printer»).toString()  на device name  из OPOS POS Printer configurator.

Навсякий случай дрова OPOS для Custom VKP-80II

Views :

1904

KDSoap + Qt5 пример написания SOAP клиента

Надеюсь сборка прошла гладко =) теперь небольшой пример использования SOAP протокола =)

Для начала определимся с каким сервисом будем работать.  Для примера я предлагаю получить курс валюты на определённую дату от ЦентроБанка

Страничка сервиса и доступные методы и сам  wsdl файл

В QtCreator создаём новый проект на Ваше усмотрение.

В *.pro файле дописываем:

LIBS += -LC:/Projects/kdsoap/lib -lkdsoapd1
QT += network core
INCLUDEPATH += C:/Projects/kdsoap/include

Скачиваем wsdl файл и кидаем его в корень директории своего проекта, у меня файл назван DailyInfo.wsdl

Дальше нужно сгенерировать классы для работы с soap из wsdl файла, для этого служит утилита kdwsdl2cpp.exe из каталога C:\Projects\kdsoap\bin

Открываем консольку и переходим в  корневую папку проекта (у меня C:\Projects\1CTerminal\1CTerminal\)
и генерируем файлы:

cd C:\Projects\1CTerminal\1CTerminal\
C:\Projects\kdsoap\bin\kdwsdl2cpp.exe  -o dailyinfo.h dailyinfo.wsdl
C:\Projects\kdsoap\bin\kdwsdl2cpp.exe -impl dailyinfo.h -o dailyinfo.cpp dailyinfo.wsdl
Скорее всего понадобиться добавить пути  в Path:
set PATH=C:\Qt\Qt5.2.1\5.2.1\mingw48_32\bin;%PATH%

dailyinfo.h — сгенерированный заголовочный файл для работы с dailyinfo.wsdl
и соответственно dailyinfo.cpp — реализация.
Не забудьте — при изменение wsdl файла описания сервиса нужно заново пересобирать эти классы!

Можно сделать автогенерацию классов при компиляции, для этого в *.pro файле:

KDWSDL = dailyinfo.wsdl 
WSDL_DIR = generated //-- Путь, куда складывать сгенерированные файлы
KDSOAPDIR = C:\Projects\kdsoap
include(kdsoap.pri)

А также в корень проекта кинуть сам kdsoap.pri из папки с kdsoap.
Также тогда потребуется убрать добавление библиотеки из  LIBS  и INCLUDEPATH
Кстати, так же нужно будет сгенерить дебажную и релизную версии kdsoap
Ну и проверить в kdsoap.pri правильно ли называются сами библиотеки.

 

Работа KDSoap основана на механизме сигнал-слотов.

Нас интересует пока что метод GetCursOnDate (описание методов тут или тут)

Открываем dailyinfo.h  и в самом начале видим основное пространство имён (DailyInfo) а так же основной класс (DailyInfoSoap12), через который мы будем вызывать методы сервиса.
Сигналы обычно именуются следующим образом:

  • об успешном выполнении getCursOnDateDone
  • об ошибке: getCursOnDateError.

Что бы узнать какие нужны параметры для вызова метода ищем поиском объявление функции «getCursOnDate(«.

В данном случае параметром будет  const TNS__GetCursOnDate& parameters,
аналогично ищем для сигналов getCursOnDateDone  и getCursOnDateError.
Кстати, QtCreator сам подскажет какие, если что 😉

Создадим вспомогательный класс, например  SoapClient, наследуемся от QObject.

soapclient.h

#ifndef SOAPCLIENT_H
#define SOAPCLIENT_H
#include <QObject>
#include <QDebug>

//-- Подключаем сгенерированный класс.
//-- Если Вы классы для wsdl генерируете из qmake, то называться будет wsdl_dailyinfo.h
#include "wsdl_DailyInfo.h"
using namespace DailyInfo;
class SoapClient : public QObject
{
Q_OBJECT
public:
   explicit SoapClient(QObject *parent = 0);

signals:

public slots:

private slots:
   void onGetCursOnDateDone(const TNS__GetCursOnDateResponse& parameters); //-- успешное выполнение метода, принимаем результат
   void onGetCursOnDateError(const KDSoapMessage& fault); //-- Ошибка
private:
    DailyInfoSoap * dailyInfo;

};
#endif // SOAPCLIENT_H

Реализация soapclient.cpp:

#include "soapclient.h"

SoapClient::SoapClient(QObject *parent) : QObject(parent)

{

   dailyInfo = new DailyInfoSoap(this); //-- Новый объект для работы с сервисом
   dailyInfo->setEndPoint(QLatin1String("http://www.cbr.ru/DailyInfoWebServ/DailyInfo.asmx")); //-- Адрес сервиса
   dailyInfo->setSoapVersion(KDSoapClientInterface::SOAP1_2); //-- Протокол

   //-- Коннектим сигналы со слотами
   connect(dailyInfo, &DailyInfoSoap::getCursOnDateError, this, &SoapClient::onGetCursOnDateError);
   connect(dailyInfo, &DailyInfoSoap::getCursOnDateDone, this, &SoapClient::onGetCursOnDateDone);

   //-- Парметры для вызова метода GetCursOnDate
   TNS__GetCursOnDate params;
   KDDateTime data = KDDateTime::currentDateTime(); //-- не долго мучаясь поставим текущую
   params.setOn_date(data);

   dailyInfo->asyncGetCursOnDate(params);

}

void SoapClient::onGetCursOnDateDone(const TNS__GetCursOnDateResponse& parameters) {

   qDebug()<<"Done!!!";

   TNS__GetCursOnDateResult res= parameters.getCursOnDateResult();

   qDebug()<<res.any().toXml(); //-- Из вывода узнаём как нам путешествовать, что бы найти необходимые данные

   KDSoapValue diffgram=res.any();
   KDSoapValue valuteData=res.any().childValues().at(0);
   KDSoapValue usaDollar= valuteData.childValues().at(10);

   QList<KDSoapValue> atributes= usaDollar.childValues().attributes();

   qDebug()<<"id"<<atributes.at(0).value().toString();
   qDebug()<<"rowOrder"<<atributes.at(1).value().toString();
   qDebug()<<"Vname"<<usaDollar.childValues().at(0).value().toString();
   qDebug()<<"Vnom"<<usaDollar.childValues().at(1).value().toString();
   qDebug()<<"Vcurs"<<usaDollar.childValues().at(2).value().toString();
   qDebug()<<"Vcode"<<usaDollar.childValues().at(3).value().toString();
   qDebug()<<"VchCode"<<usaDollar.childValues().at(4).value().toString();
   qDebug()<<"Статья написана pavelk.ru, надеюсь было понятно=)";

}

void SoapClient::onGetCursOnDateError(const KDSoapMessage& fault)
{
   qDebug()<<"Error!";
}

Дальше в main.cpp не забудем подключить и создать класс:

#include "soapclient.h"
SoapClient * client = new SoapClient(0);

Запускаем и смотрим вывод =)

Надеюсь всё заработало и стало теперь понятно как написать SOAP клиент на Qt5.

Views :

1948

KDSoap + Qt5 сборка под Windows

KDSOAP , пожалуй, лучшая на сегодняшний день библиотека  для обмена через  SOAP протокол, которая работает с Qt5 без лишних костылей (в отличии от QtSOAP и gSOAP)

Обновил для Qt 5.9

Подробнее про KDSoap (на английском)

Для сборки потребуется:

  • git (при установке отметьте Use git from the windows command promt)
  • python2 (именно 2 а не 3! При установке в списке включите add python.exe to Path)
  • perl
  • Qt5
  • OpenSSL (Качаете Win32 OpenSSL v1.0.2L Light, при установке выбираете копировать в директорию Windows)

P.S. Если у Вас что-то уже установлено естественно переустанавливать не надо.

Теперь открываем консольку винды и переходим в каталог в котором будем собирать KDSoap, у меня это C:\Projects\kdsoap  и клонируем гит репозиторий: https://github.com/KDAB/KDSoap.git

cd C:\Projects\kdsoap
git clone https://github.com/KDAB/KDSoap.git .

Дальше нужно в Path добавить месторасположения qmake и mingw32-make. У себя замените на свой путь.

set PATH=C:\Qt\5.8\mingw53_32\bin;%PATH%
set PATH=C:\Qt\Tools\mingw530_32\bin;%PATH%

Дальше начинаем непосредственно собирать KDSoap:

git submodule update --init
python autogen.py -shared -debug
set PATH=C:\Projects\kdsoap\bin;%PATH%
set LIB=C:\Projects\kdsoap\lib;%LIB%
mingw32-make
mingw32-make install
Возможные варианты сборки:
python autogen.py -shared -debug
python autogen.py -shared -release
python autogen.py -static -debug
python autogen.py -static -release
Надеюсь понятно для чего какие параметры
Если python autogen.py   начнёт ругаться на perl unable to remap,
то  убедитесь, что Perl идёт после Git в переменной Path (echo %PATH%) и обновите Git, но, впринципе, это не должно повлиять на сборку.

Установка должна успешно завершиться =)
Сейчас собрали дебажную версию. Аналогично собирается релизная.

Примеры можно открыть в QtCreator из каталога: C:\Projects\kdsoap\examples\

 

 

Views :

1486

Правильный способ конвертирования cv::Mat в QImage

Некогда рассказывать почему так, но это реально работает =)

QImage Camera::mat2Qimg(const Mat &src) {
    cv::Mat temp;
    cvtColor(src, temp,CV_BGR2RGB);
    QImage dest((uchar*) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
    QImage dest2(dest);
    dest2.detach();
    return dest2;
}
Views :

1145