papyros / qml-material

:book: Material Design implemented in QtQuick
GNU Lesser General Public License v2.1
2.57k stars 476 forks source link

New Intended Way of Usage #441

Closed alexhochreiter closed 8 years ago

alexhochreiter commented 8 years ago

So whats the new intended way of usage/inclusion since the project structure changed? A simple myQmlEngine->addImportPath("/path/to/qml-material/src/"); is just resulting in some module \"Material\" is not installed module \"Material.ListItems\" is not installed\ So what's the updated guide/intention on that?

itay-grudev commented 8 years ago

How did you include the library? Which installation method did you choose?

itay-grudev commented 8 years ago

If you went with the "Per-project installation using git submodules" all you need to do is ass the following code in your .pro project file:

OPTIONS += roboto
DEFINES += QPM_INIT
include(material/material.pri)

And in your main.cpp:

QQmlApplicationEngine engine( &app );
engine.addImportPath( "qrc:///" );
alexhochreiter commented 8 years ago

Which is pretty bad when i don't want it packed into the application statically. Anyways, thank you, i ll gibe it a try!

alexhochreiter commented 8 years ago

Works like a charm, so thank you! Would be nice to still have n option to load it the "old fashioned qml include" way.

itay-grudev commented 8 years ago

You could do that if you add the QML files in corresponding directories according to the prefix specified in the resource files. Make sure that the qmldir file is there too. Add the directory that contains the Material directory to your import path. Then you will have to add the following files to your project:

src/core/device.h
src/core/device.cpp
src/core/units.h
src/core/units.cpp

include the headers in your main and register the components:

// in your main before the QQmlApplicationEngine initialization
qmlRegisterSingletonType<Device>(uri, 0, 1, "Device", Device::qmlSingleton);
qmlRegisterUncreatableType<Units>(uri, 0, 3, "Units", QStringLiteral("Units can only be used via the attached property."));

You will need the #include <QtQml> header for that.

This will work too. But as you can see the library isn't really meant to be used that way. But then again including all of the qml-material elements statically won't increase the size of your app with more than a few hundred kilobytes. It's barely worth mentioning.

P.S. If this solves your issue close it so we don't bother the authors.

alexhochreiter commented 8 years ago

Thank you kindly for the detailed guide, would be awesome to have something like that in the readme! One last question though, I packed qml-material into a custom QtPlugin (because i need special plugin-interfaces) and tried to initialize alle the qrc files and register the qml types from there, which resulted in a

\"Material\" is ambiguous. Found in qrc://///Material/ and in qrc://///Material/\n

Where this is basically the code:

inline void initResources() {
    Q_INIT_RESOURCE(material);
    Q_INIT_RESOURCE(components);
    Q_INIT_RESOURCE(controls);
    Q_INIT_RESOURCE(core);
    Q_INIT_RESOURCE(extras);
    Q_INIT_RESOURCE(listitems);
    Q_INIT_RESOURCE(popups);
    Q_INIT_RESOURCE(styles);
    Q_INIT_RESOURCE(window);
    Q_INIT_RESOURCE(core_icons);
    Q_INIT_RESOURCE(fonts);
}

bool QmlMaterialLib::initialize(QQmlEngine *qmlEngine) {
    initResources();
    qmlRegisterSingletonType<Device>("Material", 0, 1, "Device", Device::qmlSingleton);
    qmlRegisterUncreatableType<Units>("Material", 0, 3, "Units", QStringLiteral("Units can only be used via the attached property."));
    qmlEngine->addImportPath( "qrc:///" );
    return true;
}

The plugin is built with the instruction you posted above,

OPTIONS += roboto
DEFINES += QPM_INIT
include(material/material.pri)
HEADERS -= $$_PRO_FILE_PWD_/qml-material/src/plugin.h
SOURCES -= $$_PRO_FILE_PWD_/qml-material/src/plugin.cpp

I also tried different variations, like not defining "QPM_INIT" and finally ended up with a question about:

qmlRegisterSingletonType<Device>("Material", 0, 1, "Device", Device::qmlSingleton);

is "Material" the right uri?

itay-grudev commented 8 years ago

It should be. You would like those to be available under the Material namespace in QML. If you define QPM_INIT, the MaterialRegisterHelper in src/plugin.cpp should register those for you, but you have removed them so there is no need to use it.

alexhochreiter commented 8 years ago

I was already afraid of that, removed the QPM_INIT define and registered everything as stated above. Through some more research i found this related bug: https://bugreports.qt.io/browse/QTBUG-27645 which pretty much matches the situation. Using the "named import" workaround resolved the problem pretty much, but it's still a workaround and might be of interest when the developers want people to be able to create plugins containing/distributing qml-material.

alexhochreiter commented 8 years ago

Following your issue #442, i renamed the prefixes in the qrc files to /qml-material/Material (except for core_icons.qrc) This actually resolves the issue, but now i'm getting tons of different

qrc://///qml-material/Material/Icon.qml:54:5: QML Image: Cannot open: qrc:/icons/action/favorite.svg
qrc://///qml-material/Material/Icon.qml:54:5: QML Image: Cannot open: qrc:/icons/action/build.svg

messages. And actually ... there are only a few svgs in this repo's ./icons/ directory. So are we forced now to download all the svgs from the google material design icon collection on ourselfs, or is the FontAwesome method the new favourite way to? If FontAwesome IS the new way, are there any usage examples? Last but not least, even with the guide you wrote and the implementation excerp i wrote, i still get these messages:

ReferenceError: Units is not defined

Does the Device and Units class need any special treatment other then just registering their types with qmlRegisterSingletonType and qmlRegisterUncreatableType ? The qmlRegisterUncreatableType's last argument should be thrown when i try something like this in qml:

Units {
}

But instead of the intended error message "Units can only be used via the attached property.", i get: Units is not a type

itay-grudev commented 8 years ago

Put all your icon names in a file called icons.yml. Follow the structure of the icons.yml in the root of the repo. Then call the scripts/icons.py which will download all of the specified icons and bundle them in your repo. This is all documented in the README.

As for the ReferenceError: Units is not defined apparently you haven't registered the Units class under the correct prefix.

P.S. Given how little documentation is available you should at least read it. I am referring to the README.md.

alexhochreiter commented 8 years ago

Thanks for the guide on the icons issue! I thought we settled on "Material" beeing the right prefix? So what's wrong with qmlRegisterUncreatableType<Units>("Material", 0, 3, "Units", QStringLiteral("Units can only be used via the attached property.")); then ?

itay-grudev commented 8 years ago

Nothing. Did you include that in your code before you initialize the QQmlApplicationEngine?

alexhochreiter commented 8 years ago

I'm not using QQmlApplicationEngine - just QQmlEngine as it is. I'm registering all things before the first qml file evaluation, while an instance of an QQmlEngine already exists at that point, all other registered types don't seem to have any problem with this. I'm also checking their typeId which is beeing returned by qmlRegisterUncreatableType and qmlRegisterSingletonType and equals to -1 when they could not be registered; neither is -1.

itay-grudev commented 8 years ago

When you changed the prefixes to /qml-material/Material did you do the same for the Units? Also my issue #442 has nothing to do with the resource files prefixes. It has to do with the filenames.

alexhochreiter commented 8 years ago

What exactly should i change there? I thought we registered the Units type via c++? In case you meant the UnitsHelper.qml, located in src/core, src/core.qrc, there sould be no additional steps necessary as the file has been moved to the /qml-material/ prefix with the other files, which are imported just fine.

itay-grudev commented 8 years ago

No I meant the Units type which you registered from C++. Now that you changed the prefix of the resource files of qml-material, did you change the uri of the Unit's type?

alexhochreiter commented 8 years ago

I am sorry, but i don't see the link between the prefix change and the Unit type's uri. I changed the addImportPath url from qrc:/// to qrc:///qml-material as the Units type is not an actual qml component, the uri should not change though.

itay-grudev commented 8 years ago

Try it.

alexhochreiter commented 8 years ago

And to what exactly?

itay-grudev commented 8 years ago

qml-material/Material

alexhochreiter commented 8 years ago
qmlRegisterUncreatableType<Units>("qml-material/Material", 0, 3, "Units", QStringLiteral("Units can only be used via the attached property."));
qmlRegisterUncreatableType<Units>("qrc:///qml-material/Material", 0, 3, "Units", QStringLiteral("Units can only be used via the attached property."));

Both resulted in the same as before.

itay-grudev commented 8 years ago

Publish your code somewhere.

alexhochreiter commented 8 years ago

See my post number 4 - i ain't touchin qml-material any differently from the c++ side. Even with a clear/fresh proof of concept app the Units type is unkown.

In this case i didn't even apply the qml-material prefix for the qrc files.

qmlmaterialtest.pto

TEMPLATE = app
QT += qml quick
CONFIG += c++11
SOURCES += main.cpp
RESOURCES += qml.qrc
include(deployment.pri)
OPTIONS += roboto
#DEFINES += QPM_INIT
include(/Users/alex/git/qml-material/material.pri)

changes to material.pri

HEADERS += \ #$$PWD/src/plugin.h \
           $$PWD/src/core/device.h \
           $$PWD/src/core/units.h

SOURCES += \ #$$PWD/src/plugin.cpp \
           $$PWD/src/core/device.cpp \
           $$PWD/src/core/units.cpp

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QtQml>
#include <QDebug>
#include </Users/alex/git/qml-material/src/core/device.h>
#include </Users/alex/git/qml-material/src/core/units.h>

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);
    qDebug() << qmlRegisterSingletonType<Device>("Material", 0, 1, "Device", Device::qmlSingleton);
    qDebug() << qmlRegisterUncreatableType<Units>("Material", 0, 3, "Units", QStringLiteral("Units can only be used via the attached property."));
    QQmlApplicationEngine engine;
    engine.addImportPath( "qrc:///" );
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    return app.exec();
}

Registering the types before QGuiApplication app(argc, argv); does not make a difference.

main.qml

import QtQuick 2.5
import QtQuick.Window 2.2
import Material 0.2
ApplicationWindow {
    visible: true

    MouseArea {
        anchors.fill: parent
        onClicked: {
            Qt.quit();
        }
    }

    Text {
        text: qsTr("Hello World")
        anchors.centerIn: parent
    }

    Component.onCompleted: {
       Units.dp(2) // should not throw error, but does
    }

    Units {
        // should throw "Units can only be used via the attached property." error
        // actually throws "Units is not a type"
    }
}
alexhochreiter commented 8 years ago

Update: Using import Material 0.3 instead of 0.2 would have made total sense when registering the Units type for Material 0.3 anyways. Now to the explaination of all the strange behaviours: looks like the Singleton type Units, Device etc is not available when creating components dynamically (eg Loader {}). Is this some QML issue, or an QML-Material bug?

iBelieve commented 8 years ago

Hi guys, I'm really sorry that the new usage wasn't better documented. I've added more detailed documentation. There are three ways you can use QML Material:

So to be clear, you can statically include it or install it globally, depending on what you want. App developers for Android, OS X, or Windows will likely find the static installation method the easiest to work with. For Linux developers, the best option is to use the global installation method, preferably with a distro-specific package. This is also the best option for packaging using Flatpack, as dynamically linked/loaded libraries and QML modules will be deduped during download and locally on user's systems.

Please reopen this if anything isn't clear or you need further help. Thanks!