Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to have multiple FontLoader objects in one class?

Tags:

qt

qml

I am writing an app for which the client has provided a custom font. The font comes as four separate otf files, one for regular, bold, italic and bold-italic. If I want to use only one of these four fonts in my class, I create the FontLoader like so:

FontLoader { id: clientFontRegular; source: "qrc:/client/fonts/Font-Regular.otf" }

and then I can use it for any control on my page like so:

font.family: clientFontRegular.name

My problem is that I have multiple controls on my page, and I want to use regular for some, bold for some, italics for some others etc. To do this I've added FontLoader objects for the other fonts as well, like so:

FontLoader { id: clientFontBold; source: "qrc:/client/fonts/Font-Bold.otf" }
FontLoader { id: clientFontItalic; source: "qrc:/client/fonts/Font-Italic.otf" }
FontLoader { id: clientFontBoldItalic; source: "qrc:/client/fonts/Font-BoldItalic.otf" }

But this does not work correctly. All four ids (clientFontRegular, clientFontBold, clientFontItalic and clientFontBoldItalic) can be used anywhere in the page (i.e. without crashing or ending up using the system font), but the font used no matter what is the bold font.

I know that all four of my otf files are valid, because if I comment out all but the FontLoader for one file and use only that one, the custom font is rendered correctly. There just seems to be a problem with attempting to define multiple FontLoaders in one class (none of the FontLoader samples I've seen online use more than a single custom font).

Anybody know how to do this?

like image 514
MusiGenesis Avatar asked May 07 '16 00:05

MusiGenesis


2 Answers

I also struggled around with the same issue and wondered why there is nothing about it in the docs. This is how I got it working:

First, I defined a custom Text element (for example Label.qml), where a FontLoader element is used for every single font style, like this:

import QtQuick 2.5

Text {
    FontLoader  { id: loader; source: "fonts/Blogger_Sans.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Italic.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Light.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Medium.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Bold.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Light_Italic.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Medium_Italic.otf"; }
    FontLoader  { source: "fonts/Blogger_Sans-Bold_Italic.otf"; }

    font.family: loader.name;
}

The "trick" is to not dynamically reassign the Text element's font.family property. And this is already enough to control the font style:

Column {
    anchors.centerIn: parent;

    MyLib.Label {
        text: "Blogger_Sans"
    }

    MyLib.Label {
        text: "Blogger_Sans-Italic"
        font.italic: true;
    }

    MyLib.Label {
        text: "Blogger_Sans-Light"
        font.weight: Font.Light;
    }

    MyLib.Label {
        text: "Blogger_Sans-Medium"
        font.weight: Font.Medium;
    }

    MyLib.Label {
        text: "Blogger_Sans-Bold"
        font.weight: Font.Bold;
    }

    MyLib.Label {
        text: "Blogger_Sans-Light_Italic"
        font.weight: Font.Light;
        font.italic: true;
    }

    MyLib.Label {
        text: "Blogger_Sans-Medium_Italic"
        font.weight: Font.Medium;
        font.italic: true;
    }

    MyLib.Label {
        text: "Blogger_Sans-Bold_Italic"
        font.weight: Font.Bold;
        font.italic: true;
    }
}

I am just assuming, but it looks like once fonts are loaded (like in this case by anonymous FontLoaders), they are memorized and become automatically available when specifying them using the available font properties. But it's just guessing.

Edit

As pointed out in the comments by peppe, it's also possible to load custom fonts directly in C++ using QFontDatabase::addApplicationFont:

QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Bold_Italic.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Medium_Italic.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Light_Italic.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Italic.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Bold.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Medium.otf");
QFontDatabase::addApplicationFont(resDir + "fonts/Blogger_Sans-Light.otf");

Now the font and related styles are available in QML:

Text {
    font.family: "Blogger Sans" // note the use of the font family name
    text: "MyText"
    font.bold: true
    font.italic: true
}

The C++ approach just seems cleaner and also allows you to specify fonts without using file paths which is another big advantage.

like image 164
qCring Avatar answered Nov 06 '22 01:11

qCring


I just spent the better part of an hour trial-and-erroring this. Actually, while qCring's answer works, it's actually much simpler. With

FontLoader { id: clientFontBold; source: "qrc:/client/fonts/Font-Bold.otf" }
FontLoader { id: clientFontItalic; source: "qrc:/client/fonts/Font-Italic.otf" }
FontLoader { id: clientFontBoldItalic; source: "qrc:/client/fonts/Font-BoldItalic.otf" }

all FontLoaders end up with the same default name, therefore clientFontBold.name == clientFontItalic.name == clientFontBoldItalic.name and apparently Qt decides that the font that was registered last is mapped. You can easily see this by changing the order so clientFontItalic will be last. Then all your text that uses clientFontBold.name will be italics.

The solution is to of course name them:

FontLoader { id: clientFontBold; name: "MyFontBold"; source: "qrc:/client/fonts/Font-Bold.otf" }
FontLoader { id: clientFontItalic; name: "MyFontItalic"; source: "qrc:/client/fonts/Font-Italic.otf" }
FontLoader { id: clientFontBoldItalic; name: "MyFontBoldItalic"; source: "qrc:/client/fonts/Font-BoldItalic.otf" }

Now clientFontBold.name != clientFontItalic.name != clientFontBoldItalic.name and the proper font will load. I don't know why the fact that unnamed fonts end up with the same name isn't documented anywhere in the examples.

like image 1
FRob Avatar answered Nov 06 '22 00:11

FRob