DroidScript
DroidScript
учимся и разрабатываем

QML Loader - консоль для запуска qml-файлов

30.01.2018

Написать программу для просмотра qml-файлов не составляет большого труда и сделать это можно несколькими способами, но хотелось бы получить простое и удобное решение - запуск файла после его выбора. Для этого создадим приложение (сервис без интерфейса и даже без консольного окна), а после укажем его в качестве программы, запускаемой при выборе файлов с расширением qml. Получится сервис для запуска локальных qml-файлов. Если потребуется открывать удалённые файлы, то это можно осуществить в коде локального qml-файла.

Откроем Qt Creator и создадим пустое приложение Qt Quick (Qt Quick Controls 2). Данный шаблон выбран для более удобного вывода сообщений и логов на экран при возникновении ошибок. После создания проекта в папке ресурсов появится файл main.qml, который и будет использоваться для этого.

Код главного файла проекта main.cpp выглядеть как-то так:

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;
        

Нам необходимо вместо "qrc:/main.qml" указать путь к открываемому файлу.

Файл передаётся сервису в виде параметра командной строки и в Windows это выгладит очень просто. Проверяем количество параметров в командной строке и загружаем файл, полный путь к которому указан во втором параметре:

if(argc==2){
	engine.load(argv[1]);
}

Если параметр не указан (сервис вызван напрямую и количество аргументов равно 1) то можно вывести сообщение о необходимости указания второго параметра. Для взаимодействия между Qt С++ и Qml создаётся класс С++ с нужными свойствами и методами, а затем производится связь контекстов. Добавим к проект новый класс Utils. Тогда связь будет выглядеть так:

Utils ut;
engine.rootContext()->setContextProperty("qtc", &ut); // "qtc" - свойство Qml, &ut - ссылка на объект класса.

После этого открытые методы класса Utils будут доступны через объект qtc. Добавьте в класс свойство для обмена сообщениями мижду C++ и Qml.

Для отображения командной строки на вкладке "Проекты" выберите для заданного комплекта сборки опцию "Запуск". Создайте тестовый qml-файл, укажите в этой командной строке путь к нему запустите сервис для проверки его работы.

Получение параметров запуска на Android выглядит на java так:

	Intent intent = getIntent();
	Uri data = intent.getData();
	String path = data.getPath();
    

Для доступ к Java из Qt служит интерфнйс JNI - Java Native Interface, который предоставляет объект QAndroidJniObject. Воспользуемся им для получения эквивалентного кода:

    QAndroidJniObject activity = QtAndroid::androidActivity();
    if (activity.isValid()) {
        QAndroidJniObject intent = activity.callObjectMethod("getIntent", "()Landroid/content/Intent;");
        if (intent.isValid()) {
            QAndroidJniObject data = intent.callObjectMethod("getData", "()Landroid/net/Uri;");
            if (data.isValid()) {
                QAndroidJniObject path = data.callObjectMethod("getPath", "()Ljava/lang/String;");
                if (path.isValid()){
                    ut.engine.load("file://"+ut.getPath());
                }
            }
        }
    }
    

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

#ifdef Q_OS_WIN
// код для работы в среде Windows
#endif

#ifdef Q_OS_ANDROID
// код для работы в среде Android
#endif

Если в процессе работы сервиса или открытия файла возникнет ошибка, то приложение закроется с кодом -1 и будет непонятно, ошибка возникла при работе сервиса или связана с открытием файла. Для отслеживания этого потребуется дополнительный код:

Пытаемся открыть qml-файл. Если он не загружается (в сервисе или файле возникла ошибка), то открываем заведомо исправный файл ресурса main.qml и пробуем загрузить qml-файл в нём при помощи блока Loader. Если ресурсный файл main.qml не открывается - ошибка при работе сервиса. Если же не выполняется содержимое qml-файла, то ошибка в его коде.

Для реализации этого в main.cpp добавим код:

if (engine.rootObjects().isEmpty()){
	engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
}
if (engine.rootObjects().isEmpty())
	return -1;
    

Для загрузки файла в Qml нужно передать путь к нему. Для этого в класс Utils добавим методы setPath(QString path) и getPath(), а коде Qml вызовем его методом qtc.getPath()

Для запуска сервиса на Android при открытии файла qml необходимо дополнить манифест сервиса:

<intent-filter>  
	<action android:name="android.intent.action.MAIN"/>
	<action android:name="android.intent.action.VIEW"/>
	<category android:name="android.intent.category.LAUNCHER"/>
	<category android:name="android.intent.category.DEFAULT"/>
	<data android:mimeType="text/*.qml"/>
</intent-filter>

Для генерации файла манифеста перейдите на вкладку "Проекты", далее выберите опцию "Сборка" для комплекта сборки под Android, на панели перейдите в раздел "Собрать Android APK" и нажмите кнопку "Создать шаблоны". В проекте появится новая папка "Другие файлы", в которой и находится файл манифеста AndroidManifest.xml

Исходный код можно загрузить здесь.

© 2016-2024 
actech