How to get the font file path with QFont in Qt?
Asked Answered
S

3

13

I would like to retrieve the font file path with its extension (for example "arial.ttf").

The QFont::rawname() method always returns "unknown".

Is there another way to obtain the name and the extension of a font?

Here is the code we use:

    bool ok = true;
    QFont font = QFontDialog::getFont(&ok, this);
    if(ok)
    {
    QString fontpath = "/Library/Fonts/" + font.family()+".ttf";//Using font file path in the application
    }
Sihonn answered 30/9, 2013 at 15:46 Comment(6)
which os are you on??Cia
I'm on Mac OSX 10.7.5Sihonn
You can use QDesktopServices to return the path of user fonts. I think the system fonts paths are a bit more tricky as they vary so much between systems.Ahab
You dont necessarily need the absolute path to set fonts in most cases.Cia
What's the result of _stripView->setFont(fontpath)? Does it throw an error message?Roulers
No problem with the setFont(fontpath). I removed it from the post but it is still in the code.Sihonn
P
5

A QFont is a request for a font, not a description of an actual font that matched; the latter is QFontInfo. See my other answer. Unfortunately, QFontInfo does not give you rawName(). There is a roundabout way to get it if at all, you're not guaranteed that it will work on all platforms.

QFont myFont;
QFontInfo info(myFont);
QFont realFont(info.family());
QString rawName = realFont.rawName(); 

If you're looking for standard locations of things such as fonts, then in Qt 5 you'd use QStandardPaths::standardLocations with FontsLocation. In Qt 4, you'd use QDesktopServices::storageLocation.

Playhouse answered 30/9, 2013 at 23:34 Comment(5)
Thank you for your answer, but unfortunately the first solution does not work for me. It still returns unknown when I display the rawName. I will try to work with the QStandardPaths.Sihonn
There's no guarantee it will work. It's basically an unsupported API, for all practical purposes. What do you need the font path for anyway?Rosenthal
I use a setFont(QString fontpath) method that needs the font pathSihonn
Yes it's not a Qt method. It uses SDL_ttf and it needs the .ttf file to load the font.Sihonn
Understood. It looks like you'll need platform-specific ways of doing it, or you can render your text into a QImage and pass that into SDL. There's a lot of SDL functionality that overlaps Qt.Rosenthal
O
2

I've needed to do the same thing, although I'm working in Python. I'm using PyQt interface to pick the font, but using PIL to draw text, and PIL needs the font's file path (or at least, the file name) to use it. So far, I only have a general partial answer - hopefully what I have you can adapt.

What you can do is first get the path to where the fonts are via QStandardPaths - then using QFontDatabase, iterate through the files at the font path and load it into the database via addApplicationFont. If it loads, you'll get an index; which you then feed to the database's applicationFontFamilies function. This only gives you the font family name(s) but you can then use that to map the name to the file path.

You can't distinguish between exact fonts through this method (C:/Windows/Fonts/HTOWERT.TTF and C:/Windows/Fonts/HTOWERTI.TTF both return the same family name but the second one is italic) so this isn't a one-to-one mapping, and I'm not sure it even works for non true-type fonts (.ttf), but it's a start at least.

Here's what it might look like in Python:

from PySide2.QtCore import QStandardPaths
from PySide2.QtGui import QFontDatabase
from PySide2.QtWidgets import QApplication
import sys, os

def getFontPaths():
    font_paths = QStandardPaths.standardLocations(QStandardPaths.FontsLocation)

    accounted = []
    unloadable = []
    family_to_path = {}

    db = QFontDatabase()
    for fpath in font_paths:  # go through all font paths
        for filename in os.listdir(fpath):  # go through all files at each path
            path = os.path.join(fpath, filename)

            idx = db.addApplicationFont(path)  # add font path
            
            if idx < 0: unloadable.append(path)  # font wasn't loaded if idx is -1
            else:
                names = db.applicationFontFamilies(idx)  # load back font family name

                for n in names:
                    if n in family_to_path:
                        accounted.append((n, path))
                    else:
                        family_to_path[n] = path
                # this isn't a 1:1 mapping, for example
                # 'C:/Windows/Fonts/HTOWERT.TTF' (regular) and
                # 'C:/Windows/Fonts/HTOWERTI.TTF' (italic) are different
                # but applicationFontFamilies will return 'High Tower Text' for both
    return unloadable, family_to_path, accounted

>>> app = QApplication(sys.argv)
>>> unloadable, family_to_path, accounted = getFontPaths()
>>> family_to_path['Comic Sans MS']
'C:/Windows/Fonts\\comic.ttf'

I'm finding it a bit strange that there's no real way to map the fonts to their locations. I mean, at some point Qt needs to know where a font is in order to use it, right?

Odette answered 7/11, 2020 at 15:58 Comment(0)
B
0

You can retrieve the font file that you want based on the font family of the QFont object

in order to do this you can use the matplotlib library by installing it from pip:

pip install matplotlib

then you can use the font_manager module from the library and access its find_font function that takes in the font family as a string accessed by:

Python:

from PyQt6 import QtGui
#QtGui.QFont() should be replaced with your QFont Object

QtGui.QFont().family()

C++ (equivelant)

QFont::family()

Next you would get the font family from the QFont object and put it in the font_manager.find_font() method:

from matplotlib import font_manager

x = QtGui.QFont().family()  #this is now a string
font_manager.find_font(x) 
#this method now converted the font family string into the file path of the font

all in all the code looks like this:

from PyQt6 import QtGui
from matplotlib import font_manager

#QtGui.QFont() should be replaced with your QFont Object

QtGui.QFont().family()

x = QtGui.QFont().family()  #this is now a string
font_manager.find_font(x) 
#this method now converted the font family string into the file path of the font

Here is a real life example of this in PyQt6:

from PyQt6 import QtGui, QtWidgets, QtCore
import os
#import matplotlib.font_manager as font_manager
from matplotlib import font_manager

class Ui_MainWindow(object):
    def setupUi(self, MainWindow):
        MainWindow.setObjectName("MainWindow")
        MainWindow.resize(800, 600)
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.centralwidget.setObjectName("centralwidget")
        self.fontComboBox = QtWidgets.QFontComboBox(self.centralwidget)
        self.fontComboBox.setGeometry(QtCore.QRect(210, 220, 338, 32))
        self.fontComboBox.setObjectName("fontComboBox")
        MainWindow.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(MainWindow)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 30))
        self.menubar.setObjectName("menubar")
        MainWindow.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(MainWindow)
        self.statusbar.setObjectName("statusbar")
        MainWindow.setStatusBar(self.statusbar)

        self.retranslateUi(MainWindow)
        QtCore.QMetaObject.connectSlotsByName(MainWindow)

    def retranslateUi(self, MainWindow):
        _translate = QtCore.QCoreApplication.translate
        MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))

def your():
    print(font_manager.findfont(ui.fontComboBox.currentFont().family()))

if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.setupUi(MainWindow)
    MainWindow.show()
    your()
    sys.exit(app.exec())

I know that you might not know python as you are using C++ but you can research how to use the open() function in python to write a text file containing the file path (or make a jason file, its up to you).

I hope I helped you in some way, feel free to ask me any question about this. Even if it may seem basic, don't let that discourage you. No matter what others say!

Barbarese answered 23/11, 2022 at 3:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.