[Interest] How to change QFont::StyleStrategy from QML?

Bo Thorsen bthorsen at ics.com
Tue Jan 21 10:34:13 CET 2014


Den 20-01-2014 19:32, Alexander Ivash skrev:
>
>
>
> 2014/1/20 Bo Thorsen <bthorsen at ics.com <mailto:bthorsen at ics.com>>
>
>     Den 19-01-2014 14:49, ElderOrb skrev:
>      > I have a font which is unfortunately rendered incorrectly unless
>      > QFont::StyleStrategy set to QFont::NoFontMerging. This font is being
>      > loaded via QML Loader and used by many QML controls. Unfortunately
>      > 'QFont::NoFontMerging' is not exposed to QML so I can't change it
>     like the
>      > other font settings. Is there any others ways to set this flag than
>      > creating my own QML wrapper over QFont and passing this QFont to
>     all the
>      > QML elements?
>
>     This really shouldn't happen. There's a bug in either the font or the Qt
>     code. You are going to have to do the workaround, unfortunately.
>
> I suspect the bug is in the Qt code, because some other applications
> don't have such an issue.
>
>     However, it's usually a good idea to centralize things like font, colors
>     etc in a style sheet like object. Then you at least only have to do this
>     once.
>
>     Whether you do this in a javascript file (remember to mark it as a
>     library), a QML object or an exported C++ object, the idea is the same.
>     Make a single object that has a property for each of them and bind your
>     text etc to the font property.
>
>     Bo.
>
> I found a pretty ugly but working way to achieve what I want, but I
> still have some issues.
>
> Here is my approach:
>
> 1.) Utility class allowing to pass 'configured' font to QML
>
> class FontProvider : public QObject
> {
>      Q_OBJECT
>      Q_PROPERTY(QFont font READ font NOTIFY fontChanged)
>
> public:
>      explicit FontProvider(QObject *parent = 0) : QObject(parent) {}
>
>      QFont font() const { return mFont; }
>      void setFont(const QFont &value) { mFont = value; }
>
> signals:
>      void fontChanged();
>
> public slots:
>
>
> private:
>      QFont mFont;
> };
>
> 2.) Configure QFont and pass to QML via 'FontProvider'
>
> int main(int argc, char *argv[])
> {
>      QGuiApplication app(argc, argv);
>
>      QFont font("Verdana");
>      font.setStyleStrategy(QFont::NoFontMerging);
>
>      FontProvider fontProvider;
>      fontProvider.setFont(font);
>
>      QtQuick2ApplicationViewer viewer;
>      viewer.rootContext()->setContextProperty("fontProvider",
> &fontProvider);
>      viewer.setMainQmlFile(QStringLiteral("qml/FontTest/main.qml"));
>      viewer.showExpanded();
>
>      return app.exec();
> }
>
>
> 3.) Use configured font in QML in the following way:
>
> import QtQuick 2.0
>
> Rectangle {
>      width: 360
>      height: 360
>
>      property font smallFont: fontProvider.font
>      property font bigFont: fontProvider.font
>
>      Column {
>          Text {
>              font: smallFont
>              text: qsTr("Hello World")
>          }
>
>          Text {
>              font: bigFont
>              text: qsTr("Hello World")
>          }
>      }
>
>      Component.onCompleted: {
>          smallFont.pixelSize  = 10;
>          bigFont.pixelSize  = 50;
>      }
> }
>
>
>
> The issue with such approach is that I need to create as many different
> 'pre-configured' fonts as many I need in the app.
> I have only 'smallFont' and 'bigFont' in my example which is ok, but
> what if I need lets say 'meduim' or 'bold' or whatever?
>
>
> I tried to achieve it using the following approach:
>
>          Text {
>              font: bigFont
>              font.pixelSize: 50
>              font.bold: true
>              text: qsTr("Hello World")
>          }
>
> .. but unfortunately it just fails to work with the following error:
> "Property has already been assigned a value
>                   font.pixelSize: 50"
>
> Am I missing something?

This almost what I do. I also use C++ objects to have those settings. 
What you're missing (IMHO) is to switch from a single font to bigFont 
and smallFont being separate properties.

In your setFont you should do this:

class FontProvider : public QObject
{
   Q_OBJECT
   Q_PROPERTY(QFont smallFont READ smallFont NOTIFY fontChanged)
   Q_PROPERTY(QFont bigFont READ bigFont NOTIFY fontChanged)
...
   void setFont(QFont f) {
     mSmallFont = f;
     mBigFont = f;
     mSmallFont.setPixelSize(10);
     mBigFont.setPixelSize(50);
     mBigFont.setBold(true);
     emit fontChanged();
   }
...

So your QML code becomes

         Text {
             font: fontProvider.bigFont
             text: qsTr("Hello World")
         }

You can still modify the fonts in the QML code when you want to, but I 
would suggest you don't do it. It's a maintenance issue - it's so hard 
and really boring work to go through a lot of QML lines to find all the 
places where you inlined some UI modifications.

We learned in school that you should separate data from representation. 
That's hard to do in QML, but it doesn't mean we can't do something.

I hope this helps.

Bo.

-- 
Bo Thorsen, European Engineering Manager, ICS
Integrated Computer Solutions. Delivering World-Class Applications
http://ics.com/services



More information about the Interest mailing list