Последнее обновление:
January 16, 2018

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

Использование интерфейсов классов в Qt и QML

Привет!

Порою удобнее в QML работать именно с интерфейсом класса, а так же иметь возможность засунуть его в QVariant.  

Разумеется простым способом в «лоб» не получится, т.к. Qt в QML работает с QObject, а мы от него не унаследовались и никакой информации для метасистемы не дали.

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

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

Пишем:

#ifndef IINTERFACE_H
#define IINTERFACE_H

#include <QObject>


class IInterface {
public:
    virtual QString myProperty() const =0;
    virtual void setMyProperty(QString myProperty) =0;
    virtual void myPropertyChanged(QString myProperty) =0;
};

Q_DECLARE_INTERFACE(IInterface, "pavelk.iinterface")


#endif // IINTERFACE_H

Обратите внимание на строку с «Q_DECLARE_INTERFACE» — тем самым мы даём понять метаобъектной системе Qt, что это интерфейс, что бы он прописал необходимые функции по получению исходного класса.

Ну и сам класс:

#ifndef MYCLASS_H
#define MYCLASS_H

#include <QObject>

#include "iinterface.h"

class MyClass : public QObject, public IInterface
{
    Q_OBJECT
    Q_INTERFACES(IInterface)
    Q_PROPERTY(QString myProperty READ myProperty WRITE setMyProperty NOTIFY myPropertyChanged)
public:
    explicit MyClass(QObject *parent = nullptr);

    QString myProperty() const;

signals:
    void myPropertyChanged(QString myProperty);

public slots:
    void setMyProperty(QString myProperty);

private:
    QString m_myProperty;
};

#endif // MYCLASS_H

Обратите внимание на строку с «Q_INTERFACES(IInterface)» — тем самым мы даём знать Qt как именно преобразовывать этот класс к указанному интерфейсу. Кстати, можно наследоваться сразу от нескольких интерфейсов — просто пропишите через пробел их все.

Ну и теперь самое интересное. Преобразовываем класс к интерфейсу и передаём этот интерфейс в QML

   MyClass * myClass = new MyClass(0);
   IInterface * interface = myClass;
   engine.rootObjects().at(0)->setProperty("myClassInterface", qVariantFromValue( dynamic_cast<QObject*>(interface) ));

Напрямую в QVariant интерфейс засовывать нельзя, т.к. он не знает необходимой информации, поэтому преобразовываем сначала в QObject*, а благодаря тому, что мы прописал Q_DECLARE_INTERFACE метасистема знает как работать с этим интерфейсом.

Полный код примера тут:  https://github.com/Riflio/QMLInterfaces

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

Views :

50

NGINX location alias + php + rewrite (try_files)

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

Прописываем в секции server {}:

location /bareos-webui/ {
    alias /usr/share/bareos-webui/public/;
    autoindex on;
    try_files $uri $uri/ /bareos-webui//bareos-webui//index.php?$query_string;
    location ~ \.php$ {
        fastcgi_split_path_info ^(.+?\.php)(/.*)?$;
        fastcgi_pass unix:/run/php/php7.0-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $request_filename;
        fastcgi_index index.php;
        include fastcgi_params;
    }
}

Вся проблема оказалась в том, что как-то странно работает try_files вместе с alias…, т.е. нужно два раза повторить адрес из location.

Угробил бля 3 часа на эксперименты… Видимо баг самого NGINX.

Views :

23

AVFrame(AVPicture) конвертация в OpenCV::Mat

Понадобилось тут мне сконвертировать  AVFrame в Mat для дальнейших издевательст с помощью OpenCV, загуглил я это дело, и нашёл кучу способов.

Вот один из них:

void AVFrameToMat(const AVFrame * frame, Mat& image)
{
    int width = frame->width;
    int height = frame->height;
    image = Mat(height, width, CV_8UC3);
    int cvLinesizes[1];
    cvLinesizes[0] = image.step1();
    SwsContext* conversion = sws_getContext(width, height, (AVPixelFormat) frame->format, width, height, PIX_FMT_BGR24, SWS_FAST_BILINEAR, NULL, NULL, NULL);
    sws_scale(conversion, frame->data, frame->linesize, 0, height, &image.data, cvLinesizes);
    sws_freeContext(conversion);
}

Мне одному кажется, что столько преобразований излишни?  Ведь OpenCV напрямую позволяет работать со всеми форматами и можно сделать преобразование напрямую! 

В моём случае я работаю с форматом видео YUV420P.

if ( m_picture->format == AV_PIX_FMT_YUV420P ) {
    int numBytes=avpicture_get_size(AV_PIX_FMT_YUV420P, m_picture->width, m_picture->height);        
    uint8_t * buffer = reinterpret_cast<uint8_t *>(av_malloc(numBytes));
    avpicture_layout( ( AVPicture*)m_picture, AV_PIX_FMT_YUV420P, m_picture->width, m_picture->height, buffer, numBytes); //av_image_copy_to_buffer() в новом API


    Mat yuv = Mat(m_picture->height+m_picture->height/2, m_picture->width, CV_8UC1, buffer );
    Mat gray = Mat(m_picture->height, m_picture->width, CV_8UC1, buffer ); //-- Если нужно получить сразу в градациях серого (формат YUV содержит в первом канале как раз в градациях серого кадр)

    Mat rgb = Mat(m_picture->height, m_picture->width, CV_8UC3);
    cvtColor(yuv, rgb, CV_YUV420p2RGB);

    imshow("RGB", rgb);
    imshow("GRAY", gray);
}

ВАЖНО: Не забудьте очистить память из под buffer, так как после удаления Mat она не очищается самостоятельно!

В вашем случае замените форматы на те, с которыми работаете.

Вот как-то так…

 

 

Views :

18

Компиляция libav для поддержки h264 видео.

Привет! 

Понадобилось мне в одном из проектов декодировать h264 поток, думал обойдусь без сторонних либ, глянул спеку на 300 страниц и передумал, нашёл библиотеку libav, у которой очень много фич по декодированию аудио и видео. 

Ок, компилируем:

sudo apt-get install libx264-148 libx264-dev #148 замените на актуальную версию
cd ~/Projects/libav
git clone git://git.libav.org/libav.git
./configure --enable-libx264 --enable-gpl --disable-x86asm --enable-shared
make
make install

Вот как-то так, думал будет труднее =)

Views :

7

Печатаем из Qt на онлайн фискальнике ККТ PAYONLINE-01-ФА

В связи с очередным злоебучим ёбаным (по моему мнению) законом 54-ФЗ пришлось клиентам резко обновлять кассы и выкидывать из своего кармана 40 штук, что бы поменять шило на полноценный анальный зонд.

Я бы да же этому был бы рад из-за возможности заработать на обновлении, но вот что-то радоваться чужому горю вообще не фонтан.

В общем, подключаем приблуду по микро USB (ком-порта у меня в ноуте нет), заходим на оф. сайт, качаем и драйвер «USB VCOM«.

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

С драйвером мы будем работать через ActiveX (старовато, ну а хули делать. Радует немного, что Qt поддерживает эту технологию).

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

C:\Projects\KKT-PAYONLINE-01-FA\KKT-PAYONLINE-01-FA\activex
C:\Qt\5.9.2\mingw53_32\bin\dumpcpp DrvFR.dll

Пути замените на свои. Кстати, в путях не используйте кириллицу. Если есть пробелы, то возьмите в кавычки. 

В папке должно появится два файла: «drvfrlib.h» и «drvfrlib.cpp» — они то нам и нужны, добавляем их в проект.

В настройках проекта («*.pro» файле) подключаем пару модулей 

QT += axcontainer widgets

Они нам нужны для работы с ActiveX.

Наша цель сейчас подключиться к фискальнику, проверить кассовую смену (если истекла — печатаем z-отчёт, если закрыта — открываем, иначе нам ничего не сделать больше), делаем продажу, отключаемся.

Код с комментами, надеюсь ясно, «main.cpp«:

#include <QCoreApplication>
#include <QApplication>
#include <QDebug>

#include "activex/drvfrlib.h" //-- Подключаем заголовочник либы
using namespace DrvFRLib; //-- Сразу задаём в каком пространстве имён будем работать

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    qDebug()<<"Started!";

    DrvFR * fr = new DrvFR(0, 0); //-- Создаём класс драйвера

    //-- Подключаемся к поебени
    fr->SetConnectionType(0); //-- Метод её подключения к нам, 0-локально
    fr->SetProtocolType(0); //-- Вервия протокола, 0-стандартная
    fr->SetComputerName("HCSTerminal"); //-- Задаём имя, под которым она нас будет знать
    fr->SetTimeout(0); //-- Сколько будет ждать ответа (рекомендую 0, иначе будут сюрпризы)
    fr->SetComNumber(3); //-- Устанавливаем на каком com-порту висит (COM3 - в моём случае)
    fr->SetBaudRate(115200); //-- Устанавливаем скорость подключения (115200 - дефолтная)
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ по дефолту)
    qDebug()<<"Connect"<<fr->Connect();


    //-- Проверим состояние
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    qDebug()<<"EcrStatus"<< fr->GetECRStatus();
    qDebug()<<"EcrMode"<< fr->ECRMode(); //-- Подробнее на стр. 64. Сейчас нас интересует: 4-смена закрыта, 3-смена открыта, но кончилась (нужно напечатать Z-отчёт с гашением)
    qDebug()<<fr->ECRModeDescription();



    //-- Печатаем z-отчёт с гашением
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    fr->PrintReportWithCleaning();
  
      //-- Откроем новую смену
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    fr->OpenSession(); //-- открывает смену
    

    //-- Начинаем формирование нового чека
    fr->SetCheckType(0); //-- Устанавливаем тип нового чека, 0-продажа
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    qDebug()<<"OpenCheck"<<fr->OpenCheck();
    qDebug()<<"Result"<<fr->ResultCode()<<fr->ResultCodeDescription();
    
    //-- Добавляем позиции продажи
    fr->SetQuantity(1.0); //-- Устанавливаем количество
    fr->SetPrice(3); //-- Устанавливаем цену
    fr->SetStringForPrinting("Проверка печати"); //-- Описание товара
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    fr->SetDepartment(1); //-- Задаём отдел продажи (если хуёвин несколько, что бы отличать)
    qDebug()<<"Sale result"<<fr->Sale();


    //-- Завершаем формирование чека, после закрытия выйдет на печать
    fr->SetSumm1(3); //-- Сумма оплаты наличными, если несколько типов оплат, то соответственно fr->setSumm2(); Если сумма по всем позициям будет не совпадать, то на чеке автоматически будет выведена сдача.
    fr->SetStringForPrinting("==="); //-- В чеке будет двойная линия
    fr->SetPassword(30); //-- Задаём пароль оператора (30 - админ)
    qDebug()<<"Check status"<<fr->CloseCheck();
    
    //-- Отключаемся
    fr->Disconnect();

    delete fr;

    qDebug()<<"Ended!";
    return a.exec();
}

Вот как-то так выглядит алгоритм печати чека (продажи). Если какой-то метода вернёт что-то отличное от 0, значит произошла ошибка. Разумеется каждый раз печатать z-отчёт и открывать смену не нужно, как и писал выше, нужно проверять сначала, но для примера не стал (лень). 

Если будет ругаться на «enum TBarcodePrintType«, то просто закомментите в двух местах.

А вот теперь попробуем  продать товар с ценой, где есть копейки:

....
fr->SetPrice(3.23);
....
fr->SetSumm1(3.23);
....

Облом, да? Дробная часть у цена откинулась наглухо. А дело в том, что в документации у цены стоит тип «Cyrrency» (Денежный).

Какого хуя их не устраивало просто хранить в копейках для меня загадка (впрочем, ничего нового, скорее всего разработчики не на плюсах).
В C++ разумеется такого идиотского типа нет, поэтому dumpcpp нам его заменил на qlonglong, но вот про извращения с дробной частью он не знал.

Придётся ему рассказать, а следовательно перекомпилировать модуль ActiveQt, по пути: «C:\Qt\5.9.2\Src\qtactiveqt\src\activeqt».  Сам виновник: container/qaxbase.cpp».

Надеюсь, отметили установку исходников. Если нет, то запускаете UpdateManager и выкачиваете исходники.

Открываем «container/qaxbase.cpp», в районе строки 2002 находим:

case VT_CY:
        str = "qlonglong";

Меняем на:

case VT_CY:
        str = "double";

Немного не правильно, но лучшего решения я не вижу, предлагайте в комментах.

Компилим:

cd C:\Qt\5.9.2\Src\qtactiveqt\src\activeqt
set PATH=C:\Qt\5.9.2\mingw53_32\bin;%PATH%
set PATH=C:\Qt\Tools\mingw530_32\bin;%PATH%
qmake
mingw32-make
mingw32-make install

Пути не забудьте на свои поменять.

После этого заново генерируем исходник и заголовочный из ActiveX.

Вот как-то так.

Views :

46

QEventLoop and connect/disconnect lambda function

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

Кому некогда, можно сразу прыгнуть в конец к итогу.

Бывают ситуации, когда нужно синхронно дождаться завершения асинхронного действия, при этом не подвешивая основной поток (например, не продолжать выполнение функции, пока ответ в QTCPSocket onReadyRead от сервера не придёт).   

В нашем случае для примера давайте подождём с выполнением функции, пока таймер не досчитает до 5. 

Делаем основу:

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>
#include <QTimer>
#include <QGuiApplication>
#include <QDebug>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr): QObject(parent)
    {
        _timer = new QTimer(this);
        _timer->setSingleShot(true); //-- Срабатывать только один раз

    }

    void waitFunction()
    {
        qDebug()<<"Timer BEGIN";
        _timer->start(5000); //-- 5 секунд в миллисекундах


        qDebug()<<"Timer END";
    }

signals:

public slots:

private:
    QTimer * _timer;
};

#endif // APPCORE_H

Но если мы запустим так, то вывод  «Timer END» произойдёт без какой-либо задержки, т.к. таймер ведёт отсчёт асинхронно в другом потоке.

Решением в «лоб» было бы подписаться на событие срабатывания таймера, объявить флаг срабатывания и в бесконечном цикле отслеживать его, как-то так, например:

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QGuiApplication>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr): QObject(parent)
    {
        _timer = new QTimer(this);
        _timer->setSingleShot(true); //-- Срабатывать только один раз
        connect(_timer, &QTimer::timeout, this, &AppCore::onTimeOut);

    }

    void waitFunction()
    {
        qDebug()<<"Timer BEGIN";
        _timer->start(5000); //-- 5 секунд в миллисекундах

        while (true) {
            if (_timeOut) {
                break;
            }
            QGuiApplication::processEvents();
        }

        qDebug()<<"Timer END";
    }

public slots:
    void onTimeOut()
    {
        _timeOut = true;
    }

private:
    QTimer * _timer;
    bool _timeOut=false;
};

#endif // APPCORE_H

Кстати, если бы мы не указали «QGuiApplication::processEvents();«, то слот «onTimeOut()» не вызвался бы никогда, т.к. цикл у нас бесконечный, а так мы заставляем всё таки обработать события, а заодно и не подвешивать сильно интерфейс. 

Но решение это слишком топорное и не красивое. Что бы не использовать бесконечные циклы у Qt есть QEventLoop.  Выполнение функции приостанавливается методом «exec()» и QEventLoop ждёт, пока не будет вызван метод «exit()» и лишь потом продолжается.

Делаем:

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QGuiApplication>
#include <QEventLoop>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr): QObject(parent)
    {
        _timer = new QTimer(this);
        _timer->setSingleShot(true); //-- Срабатывать только один раз
        connect(_timer, &QTimer::timeout, this, &AppCore::onTimeOut);

    }

    void waitFunction()
    {
        qDebug()<<"Timer BEGIN";

        _timer->start(5000); //-- 5 секунд в миллисекундах
        _loop.exec(); //-- Ждём, пока будет вызван exit();

        qDebug()<<"Timer END";
    }

public slots:
    void onTimeOut()
    {
        _loop.exit();
    }

private:
    QTimer * _timer;
    QEventLoop _loop;
};

#endif // APPCORE_H

Стало чуть-чуть красивее, но у нас всё ещё висит одноразовый слот «onTimeOut()» и одноразовая переменная «_loop«.  Это сейчас она одна, а если в нашем классе нужно в 5 разных местах дожидаться ответов? Как-то по 5 одноразовых слотов и переменных иметь некрасиво…

Благо в Qt начиная с 5 версии появилась возможность при соединении сигнал-слота вместо слота использовать лямбда-функцию, этой фишкой мы и воспользуемся, что бы избавиться он объявления глобального слота «onTimeOut()» и переменной «_loop»

Делаем: 

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QGuiApplication>
#include <QEventLoop>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr): QObject(parent)
    {
        _timer = new QTimer(this);
        _timer->setSingleShot(true); //-- Срабатывать только один раз
    }

    void waitFunction()
    {
        qDebug()<<"Timer BEGIN";

        QEventLoop _loop;

        connect(_timer, &QTimer::timeout, [&](){
            _loop.exit();
        });

        _timer->start(5000); //-- 5 секунд в миллисекундах
        _loop.exec(); //-- Ждём, пока будет вызван exit();

        qDebug()<<"Timer END";
    }

private:
    QTimer * _timer;

};

#endif // APPCORE_H

Запускаем и ровно через 5 секунд после «Timer BEGIN» у нас выведется «Timer END»  и вроде бы добились чего хотели, но тут есть одна тонкость. Для наглядности я в лямбду добавлю вывод информации о срабатывании, вот так теперь она выглядит::

connect(_timer, &QTimer::timeout, [&_loop](){
    qDebug()<<"TIME OUT!";
    _loop.exit();
});

Допустим нам нужно в нескольких местах ждать ответа, и мы два раза вызываем функцию:

    ....
    waitFunction();
    waitFunction();
    ....

Вывод будет такой:

Timer BEGIN
TIME OUT!
Timer END
<br>Timer BEGIN
TIME OUT!
TIME OUT!
Timer END

Как видите, «TIME OUT» после второго вызова вывелось два раза! А если бы мы функцию «waitFunction()» вызвали 10 раз, то соответственно «TIME OUT» вывелось бы то же 10 раз подряд.  Так явно не должно быть! В чём дело?  А дело в том, что лямбда функция автоматически не отключается! Если забыть про эту фишку можно нарваться в том числе и на «SIGSEGV Segmentation fault», сегфолт короче. 

Решение — это не забывать отключать (disconnect signal lambda) сигнал от лямбды, но просто так это сделать не получится, т.к. это всё таки лямбда, нужно запоминать информацию, которую возвращает метод «QMetaObject::Connection conn = connet(….)«, а по ней отключать «disconnect(conn)«. 

Делаем:

void waitFunction()
{
    qDebug()<<"Timer BEGIN";

    QEventLoop _loop;

    QMetaObject::Connection conn = connect(_timer, &QTimer::timeout, [&_loop](){
        qDebug()<<"TIME OUT!";
        _loop.exit();
    });

    _timer->start(5000); //-- 5 секунд в миллисекундах
    _loop.exec(); //-- Ждём, пока будет вызван exit();

    disconnect(conn);

    qDebug()<<"Timer END";
}

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

Timer BEGIN
TIME OUT!
Timer END

Timer BEGIN
TIME OUT!
Timer END

Но об  «disconnect(….)»  можно забыть, поэтому предлагаю использовать умные указатели, а именно QSharedPointer, но у него нужно не забыть реализовать отключение, т.к. сам по себе он это делать не умеет, а так как писанины получается многовато, поэтому предлагаю запилить макрос.

Итоговый код:

#ifndef APPCORE_H
#define APPCORE_H

#include <QObject>
#include <QTimer>
#include <QDebug>
#include <QGuiApplication>
#include <QEventLoop>
#include <QSharedPointer>

class AppCore : public QObject
{
    Q_OBJECT
public:
    explicit AppCore(QObject *parent = nullptr): QObject(parent)
    {
        _timer = new QTimer(this);
        _timer->setSingleShot(true); //-- Срабатывать только один раз
    }

    #define AutoDisconnect(l) \
        QSharedPointer<QMetaObject::Connection> l = QSharedPointer<QMetaObject::Connection>(\
            new QMetaObject::Connection(), \
            [](QMetaObject::Connection * conn) { /*QSharedPointer сам по себе не производит отключения при удалении*/ \
                QObject::disconnect(*conn);\
            }\
        ); *l //-- Use AutoDisconnect(conn1) = connect(....);

    void waitFunction()
    {
        qDebug()<<"Timer BEGIN";

        QEventLoop _loop;

        AutoDisconnect(conn) = connect(_timer, &QTimer::timeout, [&_loop](){
            qDebug()<<"TIME OUT!";
            _loop.exit();
        });

        _timer->start(5000); //-- 5 секунд в миллисекундах
        _loop.exec(); //-- Ждём, пока будет вызван exit();

        qDebug()<<"Timer END";
    }

private:
    QTimer * _timer;

};

#endif // APPCORE_H

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

P.S. Макросы не зло, нужно просто уметь их готовить 😉

Views :

54

Layout.fillWidth: true и Layout.preferredWidth/Layout.minimumWidth зависимость (очередная хитрость)

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

Так вот, задача: нужно три колонки одинаковой ширины.

Делаем:

import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QMLTips&Tricks24")

    RowLayout {
        anchors.fill: parent
        spacing: 0

        Rectangle {
            color: "blue"
            Layout.fillHeight: true
            Layout.fillWidth: true            
        }

        Rectangle {
            color: "orange"
            Layout.fillHeight: true
            Layout.fillWidth: true
        }


        Rectangle{
            color: "green"
            Layout.fillHeight: true
            Layout.fillWidth: true            
        }

    }
}

Соответственно на выходе получаем:

Получилось как и задумывали.

Обновим задачу:  Оранжевая колонка должна иметь предпочтительную ширину 200 пикселей.
На тот случай, если мы не будем ставить Layout.fillWidth в true, ну что бы он занимал какое-то место по умолчанию.

Делаем:

Rectangle {
    color: "orange"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 200
}

Получаем:

Что-то не то, да..? 

Вот тут начинается самое интересное.

Дело в том, что Layout.prefferedWidth (а так же Layout.minimumWidth) управляет пропорционально шириной относительно соседей, когда задано Layout.fillWidth: true

Соответственно что бы поведение пришло в норму, мы должны у соседей  — синего и зелёного прямоугольника то же прописать желаемую ширину.

Делаем:

Rectangle {
    color: "blue"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 200
}

Rectangle {
    color: "orange"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 200
}

Rectangle{
    color: "green"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 200
}

Получаем:

То есть как и задумывали, три одинаковые колонки.

Теперь наглядный пример насчёт пропорционально соседям изменяемости размеров. Если мы у синего прямоугольника зададим желаемую ширину в 50, а у зелёного 100, то соответственно синий будет в 4 раза меньше оранжевого (200/50=4), а зелёный буде в два раза меньше оранжевого (200/100=2). 

То есть родитель Layout (RowLayout/ColumnLayout/GridLayout) берёт от потомков наибольший желаемый размер и относительно него пропорционально выставляет ширину всем потомкам.
Повторюсь, что так QML себя ведёт, только когда задано Layout.fillWidth: true

Делаем:

Rectangle {
    color: "blue"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 50
}

Rectangle {
    color: "orange"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 200
}

Rectangle{
    color: "green"
    Layout.fillHeight: true
    Layout.fillWidth: true
    Layout.preferredWidth: 100
}

Получаем:

Надеюсь, теперь больше с этим проблем не возникнет.

Кстати, такое же поведение будет если у компонента задано свойство implicitWidth или implicitHeight, потому что если мы не задали явно Layout.preferredWidth или  Layout.fillHeight, то берутся как раз они. Наверное вы спрашиваете: как быть, если это не просто прямоугольник, а какой-то компонент? То всё просто — оберните его в Item или Rectangle или задайте явно Layout.preferredWidth

Кстати, вот документация на лэйауты: тынц.

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

Views :

21

Конвертер картинок для Arduino LCD OLED 128×64 I2C дисплея

Пришёл вот такой дисплейчик:

Но вот нигде не нашёл для него генератора, что бы модно было конвертировать jpg/png/bmp картинку в код. 
Неспешно накалякал, выбираете любой jpg/bmp файл и получаете на выходе код:

Тестовый скетч:

#include <OLED_I2C.h>  

OLED  myOLED(A4, A5, A4); 

extern uint8_t SmallFont[];

//--PASTE GENERATED CODE HERE

void setup()
{
    myOLED.begin();
    myOLED.setFont(SmallFont);    
}

void loop() 
{
    myOLED.clrScr(); 
    myOLED.drawBitmap(0, 0, icon1, 21, 21); //-- X, Y, IMG, Width, Height 
    myOLED.update();
    delay(150);
}

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

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

Библиотека OLED_I2C.

 

Views :

160

Компиляций libusb из исходников на Windows

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

Качаем MSYS2, ставим, запускаем  C:\msys32\mingw32.exe

pacman -Syu
pacman -Su
pacman -S git
pacman -S base-devel 
pacman -S libtool
pacman -S mingw-w64-i686-toolchain

touch /e/LibUSB2
cd /e/LibUSB2/
git clone https://github.com/libusb/libusb .
./autogen.sh
touch build-Win32
cd build-Win32
touch bin
../configure --prefix=/e/LibUSB2/build-Win32/bin --build=i686-w64-mingw32 --host=i686-w64-mingw32
make -j4
make install

Вся либа будет в /e/LibUSB2/build-Win32/bin.

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

Views :

72

Кросскомпиляция Qt 5.7, Qt 5.8 для Raspberry Pi 1,2,3 под Windows

В общем на Ubuntu скомпилили, открываем пост и компилим теперь под Windows.

1. Качаем актуальную версию Raspbian Jessie  и с помощью WinFLASHTool  пишем её на сд карточку.

2. так же.

3.

Качаем msys2, ставим в папку C:\SysGCC\msys2\

Качаем MinGW 4.9.2, распаковываем в папку C:\SysGCC\mingw32

Качаем Python 2.7.x

Запускаем C:\SysGCC\msys2\mingw32.exe,

pacman -Syu #попросит закрыть - закрываем, запускаем вновь и прописываем далее: 
pacman -Su 
pacman -S openssh 
pacman -S rsync
pacman -S make 
pacman -S perl 
pacman -S python
pacman -S python2
pacman -S wget
pacman -S patch
pacman -S pkg-config 
pacman -S diffutils

и остальное прописываем так же

4.  Качаем тулчейн и ставим в C:\SysGCC\Raspberry

5. Запускаем C:\SysGCC\Raspberry\TOOLS\UpdateSysroot.bat, нажимаем select, подключаемся к малине (пользователь «pi» пароль «raspberry») и в список синхронизации дописываем

/opt/vc/

6. Пропускаем, за нас это сделал шаг 5.

7.

cd /c/SysGCC/Raspberry
git clone --recursive https://github.com/qt/qt5 -b 5.7 Qt57Sources
cd Qt57Sources
BASEPATH=/c/SysGCC/Raspberry
PATH=$PATH:/c/SysGCC/Raspberry/bin
PATH=$PATH:/c/SysGCC/mingw32/bin
./configure -skip wayland -c++std 11 -skip webkit -release -opengl es2 -device linux-rasp-pi-g++ -device-option CROSS_COMPILE=$BASEPATH/bin/arm-linux-gnueabihf- -sysroot $BASEPATH/arm-linux-gnueabihf/sysroot -opensource -confirm-license -platform win32-g++ -xplatform linux-arm-gnueabihf-g++ -skip qtscript -make libs -prefix $BASEPATH/qt5pi -extprefix $BASEPATH/qt5pi -hostprefix $BASEPATH/qt5 -v
make -j 4
make install

Здесь компилится для Raspberry Pi 1, для 2 и 3 в исходном посте.

Для Qt 5.7 нужно применить патчик:

wget http://pavelk.ru/wp-content/uploads/qt57raspberrypi.patch
patch -p1 < qt57raspberrypi.patch

8. так же

9. так же

10. так же

11. так же

12. так же

12.1. так же

12.2. Путь C:\SysGCC\Raspberry\bin\arm-linux-gnueabihf-g++

12.3. Путь C:\SysGCC\Raspberry\bin\arm-linux-gnueabihf-gdb
           для qmake путь C:\SysGCC\Raspberry\qt5\bin\qmake

12.4. так же

12.5. так же

14. так же

15. ????

16. PROFIT!

Views :

1073