James Hudson
James Hudson

Reputation: 904

How to initialize a QML singleton?

I have a simple test project at https://github.com/jh3010-qt-questions/font_test which demonstrates the problem.

I have a label defined as:

    Label // #1
    {
      text: "Pack my box with five dozen liquor jugs -- DEFAULT"
    }

which should display with the default font (Art Brewery) defined in qtquickcontrols2.conf, but it is not.

However, if I add the Label:

    Label // #2
    {
      font.family: Fonts.robotoBold.name
      text: "Pack my box with five dozen liquor jugs -- Roboto Bold"
    }

then, Label #1 will be drawn with the Art Brewery font.

What is happening is that the Fonts singleton is not being initialized unless there is at least one reference to it.

My question is: How can I initialize the singleton?

I have tried things like:

qmlRegisterSingletonType( QUrl( "file:///Users/jamesh/depot_qt/questions/font_test/assets/Fonts/Fonts.qml"), "Font", 1, 0, "Font" );

in my main.cpp, but it did not work.

My directory structure looks like:

$ tree font_test

font_test
├── README.md
├── assets
│   └── Fonts
│       ├── Art\ Brewery.ttf
│       ├── Fonts.qml
│       ├── Roboto-Bold.ttf
│       ├── Roboto-BoldItalic.ttf
│       ├── Roboto-Light.ttf
│       ├── Roboto-LightItalic.ttf
│       ├── Roboto-Medium.ttf
│       ├── Roboto-MediumItalic.ttf
│       ├── Roboto-Regular.ttf
│       ├── Roboto-RegularItalic.ttf
│       ├── RobotoMono-Bold.ttf
│       ├── RobotoMono-BoldItalic.ttf
│       ├── RobotoMono-Light.ttf
│       ├── RobotoMono-LightItalic.ttf
│       ├── RobotoMono-Medium.ttf
│       ├── RobotoMono-MediumItalic.ttf
│       ├── RobotoMono-Regular.ttf
│       ├── RobotoMono-RegularItalic.ttf
│       └── qmldir
├── font_test.pro
├── font_test.pro.user
├── main.cpp
├── main.qml
├── qml.qrc
└── qtquickcontrols2.conf

my qtquickcontrols2.conf is

[Controls]
Style=Material

[Material]
Primary=White
Foreground=#444444
Accent=Blue
Theme=Light
Font\Family=Art Brewery

[Universal]
Theme=System

my main.cpp is:

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif

  QGuiApplication app(argc, argv);

  QQmlApplicationEngine engine;

  engine.addImportPath( ":/" );

//  qmlRegisterSingletonType( QUrl( "file:///Users/jamesh/depot_qt/questions/font_test/assets/Fonts/Fonts.qml"), "Font", 1, 0, "Font" );

  const QUrl url(QStringLiteral("qrc:/main.qml"));

  QObject::connect( &engine,
                    &QQmlApplicationEngine::objectCreated,
                    &app,
                    [url](QObject *obj, const QUrl &objUrl )
                    {
                      if (!obj && url == objUrl)
                        QCoreApplication::exit(-1);
                    },
                    Qt::QueuedConnection);

  engine.load(url);

  return app.exec();
}

my qml.qrc file is:

<RCC>
    <qresource prefix="/">
        <file>main.qml</file>
        <file>qtquickcontrols2.conf</file>
    </qresource>
    <qresource prefix="/Fonts">

        <file alias="qmldir">assets/Fonts/qmldir</file>
        <file alias="Fonts.qml">assets/Fonts/Fonts.qml</file>

        <file alias="Art Brewery.ttf">assets/Fonts/Art Brewery.ttf</file>

        <file alias="Roboto-Bold.ttf">assets/Fonts/Roboto-Bold.ttf</file>
        <file alias="Roboto-BoldItalic.ttf">assets/Fonts/Roboto-BoldItalic.ttf</file>
        <file alias="Roboto-Light.ttf">assets/Fonts/Roboto-Light.ttf</file>
        <file alias="Roboto-LightItalic.ttf">assets/Fonts/Roboto-LightItalic.ttf</file>
        <file alias="Roboto-Medium.ttf">assets/Fonts/Roboto-Medium.ttf</file>
        <file alias="Roboto-MediumItalic.ttf">assets/Fonts/Roboto-MediumItalic.ttf</file>
        <file alias="Roboto-Regular.ttf">assets/Fonts/Roboto-Regular.ttf</file>
        <file alias="Roboto-RegularItalic.ttf">assets/Fonts/Roboto-RegularItalic.ttf</file>

        <file alias="RobotoMono-Bold.ttf">assets/Fonts/RobotoMono-Bold.ttf</file>
        <file alias="RobotoMono-BoldItalic.ttf">assets/Fonts/RobotoMono-BoldItalic.ttf</file>
        <file alias="RobotoMono-Light.ttf">assets/Fonts/RobotoMono-Light.ttf</file>
        <file alias="RobotoMono-LightItalic.ttf">assets/Fonts/RobotoMono-LightItalic.ttf</file>
        <file alias="RobotoMono-Medium.ttf">assets/Fonts/RobotoMono-Medium.ttf</file>
        <file alias="RobotoMono-MediumItalic.ttf">assets/Fonts/RobotoMono-MediumItalic.ttf</file>
        <file alias="RobotoMono-Regular.ttf">assets/Fonts/RobotoMono-Regular.ttf</file>
        <file alias="RobotoMono-RegularItalic.ttf">assets/Fonts/RobotoMono-RegularItalic.ttf</file>

    </qresource>
</RCC>

my project file is:

QT += quick

CONFIG += c++11

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH = $$PWD/assets

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

DISTFILES +=

My Fonts.qml file is:

pragma Singleton
import QtQuick 2.12

Item
{  
  readonly property FontLoader robotoBold: FontLoader { source: "qrc:/Fonts/Roboto-Bold.ttf" }
  readonly property FontLoader robotoBoldItalic: FontLoader { source: "qrc:/Fonts/Roboto-BoldItalic.ttf" }
  readonly property FontLoader robotoLight: FontLoader { source: "qrc:/Fonts/Roboto-Light.ttf" }
  readonly property FontLoader robotoLightItalic: FontLoader { source: "qrc:/Fonts/Roboto-LightItalic.ttf" }
  readonly property FontLoader robotoMedium: FontLoader { source: "qrc:/Fonts/Roboto-Medium.ttf" }
  readonly property FontLoader robotoMediumItalic: FontLoader { source: "qrc:/Fonts/Roboto-MediumItalic.ttf" }
  readonly property FontLoader robotoRegular: FontLoader { source: "qrc:/Fonts/Roboto-Regular.ttf" }
  readonly property FontLoader robotoRegularItalic: FontLoader { source: "qrc:/Fonts/Roboto-RegularItalic.ttf" }

  readonly property FontLoader robotoMonoBold: FontLoader { source: "qrc:/Fonts/RobotoMono-Bold.ttf" }
  readonly property FontLoader robotoMonoBoldItalic: FontLoader { source: "qrc:/Fonts/RobotoMono-BoldItalic.ttf" }
  readonly property FontLoader robotoMonoLight: FontLoader { source: "qrc:/Fonts/RobotoMono-Light.ttf" }
  readonly property FontLoader robotoMonoLightItalic: FontLoader { source: "qrc:/Fonts/RobotoMono-LightItalic.ttf" }
  readonly property FontLoader robotoMonoMedium: FontLoader { source: "qrc:/Fonts/RobotoMono-Medium.ttf" }
  readonly property FontLoader robotoMonoMediumItalic: FontLoader { source: "qrc:/Fonts/RobotoMono-MediumItalic.ttf" }
  readonly property FontLoader robotoMonoRegular: FontLoader { source: "qrc:/Fonts/RobotoMono-Regular.ttf" }
  readonly property FontLoader robotoMonoRegularItalic: FontLoader { source: "qrc:/Fonts/RobotoMono-RegularItalic.ttf" }

  readonly property FontLoader artBrewery: FontLoader { source: "qrc:/Fonts/Art Brewery.ttf" }
}

My qmldir inside of the assets/fonts folder is:

singleton Fonts 1.0 Fonts.qml

My main.qml is

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12

import Fonts 1.0
//import "qrc:/Fonts/"

ApplicationWindow {
  width: 640
  height: 480
  visible: true
  title: qsTr("Hello World")

  Column
  {
    spacing: 8

    anchors.fill: parent
    anchors.margins: 20

    Label // #1
    {
      text: "Pack my box with five dozen liquor jugs -- DEFAULT"
    }

//    Label // #2
//    {
//      font.family: Fonts.robotoBold.name
//      text: "Pack my box with five dozen liquor jugs -- Roboto Bold"
//    }

//    Label // #3
//    {
//      font.family: Fonts.robotoMonoRegular.name // Fonts.robotoRegular.name
//      text: "Pack my box with five dozen liquor jugs -- Roboto Mono"
//    }

//    Label // #4
//    {
//      text: "Pack my box with five dozen liquor jugs -- Art Brewery"
//      font.family: Fonts.artBrewery.name
//      font.pixelSize: 36
//    }
  }
}

Upvotes: 2

Views: 2011

Answers (1)

James Hudson
James Hudson

Reputation: 904

I am certain there is a better solution, but one thing that works is to find a way to reference the singleton once so everything is loaded.

I modified main.qml to:

  ...
  ...
  ...
  title: qsTr("Hello World")

  property var fontReference: Fonts.objectName

  Column
  ...
  ...
  ...

I don't care about the fontReference property. I only need some way to get Fonts initialized. I am assuming there is C++ method I can call after the engine instance is created in main.cpp which will accomplish the same thing and may be considered the best practice in this situation.

Upvotes: 1

Related Questions