Search code examples
pythonfontspyqtexternalpreview

How to use QFontDialog to preview non-system fonts


I'd like to use a QFontDialog widget to preview external fonts before installing them. However, by default, QFontDialog apparently only lists installed system fonts.

  • Is there a way to specify a custom font folder for QFontDialog?
  • If not, is there any other widget that is better suited as a font previewer?

Solution

  • You can't specify custom font folders, but it is possible to add individual fonts using the QFontDatabase class. So all you need to do is iterate over the files in a given folder and add any font files it contains. The documentation notes these limitations:

    Currently only TrueType fonts, TrueType font collections, and OpenType fonts are supported.

    Note: Adding application fonts on Unix/X11 platforms without fontconfig is currently not supported.

    Once all the valid font files have been added, they will show up immediately in the font-dialog. Here is a simple demo (only tested on Linux):

    import sys, os, glob
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Window(QtWidgets.QWidget):
        def __init__(self):
            super(Window, self).__init__()
            self.button1 = QtWidgets.QPushButton('Open Font Folder')
            self.button1.clicked.connect(self.handleButton1)
            self.button2 = QtWidgets.QPushButton('Show Font Dialog')
            self.button2.clicked.connect(self.handleButton2)
            self.fontList = QtWidgets.QListWidget()
            layout = QtWidgets.QVBoxLayout(self)
            layout.addWidget(self.fontList)
            layout.addWidget(self.button1)
            layout.addWidget(self.button2)
    
        def handleButton1(self):
            path = QtWidgets.QFileDialog.getExistingDirectory(self)
            if path:
                fonts = set()
                self.fontList.clear()
                db = QtGui.QFontDatabase()
                db.removeAllApplicationFonts()
                for filename in glob.glob(os.path.join(path, '*.ttf')):
                    fontid = db.addApplicationFont(os.path.join(path, filename))
                    if fontid >= 0:
                        fonts.update(db.applicationFontFamilies(fontid))
                self.fontList.addItems(sorted(fonts))
                self.fontList.setCurrentRow(0)
    
        def handleButton2(self):
            font = QtGui.QFont()
            item = self.fontList.currentItem()
            if item is not None:
                font.setFamily(item.text())
            QtWidgets.QFontDialog.getFont(font, self)
    
    if __name__ == '__main__':
    
        app = QtWidgets.QApplication(sys.argv)
        window = Window()
        window.setGeometry(600, 100, 200, 200)
        window.show()
        sys.exit(app.exec_())