Reputation: 12942
I have a widget specified through a QML file. This widget contains a top levelRectangle
which contains two Columns
. Each of these Columns
contains many Text
-elements. This QML widget is wrapped in a subclass of QDeclarativeView
in C++.
I want to specify the font for each of these Text
-elements. Today I do this by specifying top-level properties:
property string fontfamily: "Arial"
property bool fontbold: false
property bool fontitalic: false
property int fontpixelsize: 11
property string fontcolor: "White"
and bind each Text
-elements to these properties:
Text
{
color: fontcolor
font.family: fontfamily
font.bold: fontbold
font.italic: fontitalic
font.pixelSize: fontpixelsize
...
}
This isn't very elegant and new fields needs to be added every time I need support for something new (e.g. underlined fonts). I have not been able to declare a property of type font
and bind to this instead (widget is blank and qmlviewer warns about "expected type after property").
Is there a better way to specify a font for all Text
-elements?
Note! I'm handwriting the QML files.
Upvotes: 12
Views: 15609
Reputation: 2364
Necro posting, but I feel it's still missing an up-to-date solution.
FontMetrics
will do the trick without using Qt.font()
. You can declare it in your parent item or in a Singleton
type, and then you can bind the property to it.
Here there's an example
Item {
id: root
FontMetrics {
id: fontMetrics
font.family: "Arial"
font.pixelSize: 24
}
property alias font: fontMetrics.font
Text { font: root.font }
Text { font: root.font }
}
Upvotes: 2
Reputation: 17246
In Qt 5.6 (at least, probably earlier too), you can use Qt.font()
to dynamically allocate a font object and refer to it elsewhere. So, this works:
property font myFont: Qt.font({
family: fontfamily,
bold: fontbold,
italic: fontitalic,
pixelSize: fontpixelsize
});
Text
{
color: fontcolor
font: parent.myFont
}
More info on Qt.font()
here: https://doc.qt.io/qt-5/qml-qtqml-qt.html#font-method
Upvotes: 18
Reputation: 4169
Some useful workarounds here, but I'm stuck being able to define some base fonts while still being able to specify details later, for more than a few fonts. In particular, because:
FontLoader
sets the same name
for every font of the same family. RefQt.font()
(or FontMetrics
) is used, it's all or nothing for the font
property.Text
Components requires one file per font. Update: maybe not true since 5.15.function
is difficult to manage effectively across a whole application.I think there's room for one more solution:
In my main.qml
I used one FontLoader
per font file, but only bothered setting an id
when the family changes:
FontLoader { source: "qrc:/fonts/ITCAvantGardeStd-Bk.otf"; id: flAvantGarde; }
FontLoader { source: "qrc:/fonts/ITCAvantGardeStd-BkObl.otf"; }
FontLoader { source: "qrc:/fonts/ITCAvantGardeStd-BoldCn.otf"; }
FontLoader { source: "qrc:/fonts/ITCAvantGardeStd-Md.otf"; }
FontLoader { source: "qrc:/fonts/ADAM.CG PRO.otf"; id: flAdam; }
and then, and here's the significant part, defined one property var
per base font like so:
property var fontAgBk: { "family": flAvantGarde.name, "styleName": "Book" }
property var fontAgBkObl: { "family": flAvantGarde.name, "styleName": "Book Oblique" }
property var fontAgBoldCn: { "family": flAvantGarde.name, "styleName": "Bold Condensed" }
property var fontAgMd: { "family": flAvantGarde.name, "styleName": "Medium" }
property var fontAdam: { "family": flAdam.name }
The var
is key being able to specify a dictionary that can be defined once, but pulled apart later.
Elsewhere in any qml
, I can do something like:
Text {
id: myText
color: "#123456"
font.family: fontBoldCn.family
font.styleName: fontBoldCn.styleName
font.pixelSize: 24
font.letterSpacing: 5
}
Still requires some repetitive code, but at least the magic strings are only defined once.
Upvotes: 1
Reputation: 2243
One possible solution is to write a function, that iterates over the children
of a passed element (for example a Column
). In this function all the properties can be set:
import QtQuick 1.0
Rectangle {
Row {
spacing: 10
Column {
id: col1
Text {
property bool useStyle: true
text: "Foo1"
}
Text {
property bool useStyle: true
text: "Bar1"
}
Text {
property bool useStyle: true
text: "Baz1"
}
}
Column {
id: col2
Text {
property bool useStyle: true
text: "Foo2"
}
Text {
text: "not styled"
}
Text {
property bool useStyle: true
text: "Baz2"
}
}
}
function setTextStyle(parentElement) {
for (var i = 0; i < parentElement.children.length; ++i) {
console.log("t", typeof parentElement.children[i]);
if (parentElement.children[i].useStyle) { // apply style?
parentElement.children[i].color = "blue";
parentElement.children[i].font.family = "Arial"
parentElement.children[i].font.bold = true;
parentElement.children[i].font.italic = true;
parentElement.children[i].font.pixelSize = 12;
}
}
}
// set style
Component.onCompleted: {
setTextStyle(col1);
setTextStyle(col2);
}
}
Each element, that contains the property useStyle
that is set to true
, gets styled. This is shorter, than assigning the style manually, but you can still define which elements should get styled or not.
Upvotes: 5
Reputation: 2243
Another possibility is to write a new QML component, that inherits from Text
an sets some properties by default:
StyledText.qml
import QtQuick 1.0
Text {
// set default values
color: "blue"
font.family: "Arial"
font.bold: true
font.italic: true
font.pixelSize: 12
}
main.qml
import QtQuick 1.0
Rectangle {
Row {
spacing: 10
Column {
StyledText {
text: "Foo1"
}
StyledText {
text: "Bar1"
}
StyledText {
text: "Baz1"
}
}
Column {
StyledText {
text: "Foo2"
}
StyledText {
text: "Bar2"
}
StyledText {
text: "Baz2"
}
}
}
}
Upvotes: 14