9

In QML I want to be able to define a set of font properties for simple semantic re-use. For example, instead of:

Text {
  text: "This is a header"
  font { family:'Encode Sans'; weight:Font.Black; italic:false; pointSize:24 }
}

I want to be able to write:

Text {
  text: "This is a header"
  font: headerFont
}

How can I make a single font value that I can assign like this?


I know that I make a component, like:

# Header.qml
Text {
  font { family:'Encode Sans'; weight:Font.Black; italic:false; pointSize:24 }
}

# main.qml
Header { text:"This is a header" }

However, this does not work for when I want to use the same font settings for a Label or other place where a font is needed.

I also know that I can use the answers to this question to, for example:

// style.js    
.pragma library
var header = {
  family: 'Encode Sans',
  weight: Font.Black, // is this legal?
  italic: false,
  size:   24
};
// main.qml
import "style.js" as Style

Text {
  text: "This is a header"
  font {
    family: Style.header.family
    weight: Style.header.weight
    italic: Style.header.italic
    pointSize: Style.header.size
  }
}

While this does single-source the values, it is, as shown, painfully verbose.


I tried this...

Font {
  id: header
  family: 'Encode Sans'
  weight: Font.Black
  italic: false
  pointSize: 24
}

Text {
  text: "This is a header"
  font: header
}

...but it errors "Element is not creatable" on the Font { line.

Community
  • 1
  • 1
Phrogz
  • 296,393
  • 112
  • 651
  • 745
  • Most of non-trivial QML puzzles make me to ask Qt support. – Alexander V May 27 '16 at 15:59
  • http://stackoverflow.com/questions/36848185/is-there-any-way-to-set-a-property-attribute-for-some-all-sub-items/36848272#36848272 http://stackoverflow.com/questions/36806326/how-to-create-a-custom-grouping-of-properties-and-apply-them-to-different-contro/36810566#36810566 – dtech May 27 '16 at 20:03
  • @ddriver Thank you. I mentioned that option in my question (it's in the middle) and am looking for a better answer, that works across multiple different types. – Phrogz May 27 '16 at 20:04

2 Answers2

22

This answer covers exactly what I needed. I can use Qt.font() method to create a font value with the properties I need. Wrapped in a QtObject with a global ID, I can then:

### main.qml
QtObject {
    id: theme
    property font headerFont: Qt.font({
        family: 'Encode Sans',
        weight: Font.Black,
        italic: false,
        pointSize: 24
    })
}

### AnyOther.qml
Text {
    text: "This is a header"
    font: theme.headerFont
}
Community
  • 1
  • 1
Phrogz
  • 296,393
  • 112
  • 651
  • 745
0

Well, it's really not obvious topic.. I will put it as an answer, however it's probably not a direct answer to your question, though I hope it might be a help..

.pragma is a way to go, until you are not using qtquickcompiler or using a QT > 5.6, .pragma library is broken on Qt 5.5 then using a qtquickcompiler, so it wasn't a solution on our case.

We had a fight with QML fonts for several months, trying to get a proper, well looking fonts in our application, actually goal was to get a QML application having fonts looking exactly the same as other fonts in the OS (I am talking about WinXX).. so Arial font in QML application looks exactly the same as Arial in any Windows application.

First we had to switch from QTRenderer to Native, as FreeType renderer looks far worse on WinXX platform then a native fonts, at least it's a way to make an application looking much more close to a native one. Actually from this point chars looking in the same way as character in OS, but..

Then we faced a lot of issues with a wrong spacings between chars (especially on non English letters), kerning, etc etc etc..

Other issue is that you can't change many of QFont properties in QML, however they are available then you returning prebuild QFont object from C++ exported object..

What we end up with is following C++ code skeleton:

QFont GlobalObject::createFont(const QString & family, int pixelSize, bool isBold, bool bKerning) const {
    QFont ft = QFont(family);
    ft.setFamily(family);
    ft.setBold(isBold);
    ft.setPixelSize(pixelSize);
    ft.setKerning(bKerning);

    return ft;
}

You can apply any caching for ft, so you will have a subsets by name, whatever you can think appropriate. This works perfectly fine, with a proper native rendering, and it was an only way to get a pixel-wise same looking fonts on WinXX in QML application

So my view on an answer (from my experience) is to handle QFont objects inside C++ if you want to have a proper fine-tuning on how things look like, rather then trying to play with it inside QML code.

Phrogz
  • 296,393
  • 112
  • 651
  • 745
evilruff
  • 3,947
  • 1
  • 15
  • 27
  • FWIW, see the answer that I accepted, which shows how you can create a `font` value directly in QML using `Qt.font()` method. – Phrogz May 30 '16 at 00:41
  • Problem is that QFont itself has much more fine tuning options, like kerning control which are not available via QML version you suggested. I mean as soon as you don't have to sort this issues your method is definitely cleaner, as it's native QML, however my way is better to workaround some rendering bugs.. – evilruff May 30 '16 at 08:07