Qt源码那些事儿-Linux下Qt的QFontDataBase字体引擎解析

公众号:Qt那些事儿

公众号

简介

Qt中对于字体处理最常用的三个类

  • QFontDataBase
  • QFont
  • QFontInfo

今天主要讲的是Qt在Linux下字体的基础-QFontDataBase类。

QFontDataBase

QFontDataBase为Qt提供了当前系统所有可用的字体及其信息

Linux平台

Linux平台下,Qt解析字体相关的库使用的是FontConfig。
Fontconfig是用于配置和自定义字体访问的库。

Fontconfig可以:
自动安装时发现新字体,从而消除了常见的配置问题。
执行字体名称替换,以便在缺少字体时可以选择适当的替代字体。
确定完全覆盖一组语言所需的一组字体。
因为使用基于XML的配置文件而构建了GUI配置工具(尽管具有自动发现功能,但我们认为这种需求已最小化)。
即使已安装了数千种字体,也可以在减少内存使用的同时,高效,快速地在已安装的字体集中找到所需的字体。
与X Render Extension和FreeType配合使用,可在显示器上实现高质量,抗锯齿和亚像素渲染的文本。

Fontconfig不会:
自己渲染字体(留给FreeType或其他渲染机制)
以任何方式依赖于X Window系统,因此仅打印机应用程序不具有此类依赖关系

Qt的流程

所以Qt解析字体的一个流程即

使用FontConfig提取字体相关的信息(比如字体名称,风格)。组织成Qt自己的数据结构。然后再提供给QFont,QFontInfo等类来使用。

先上Qt中使用FontConfig解析字体相关信息的代码

//qt-everywhere-src-5.15.0/qtbase/src/platformsupport/fontdatabases/fontconfig/qfontconfigdatabase.cpp
void QFontconfigDatabase::populateFontDatabase()
{
    FcInit();
    FcFontSet  *fonts;

    {
        FcObjectSet *os = FcObjectSetCreate();
        FcPattern *pattern = FcPatternCreate();
        const char *properties [] = {
            FC_FAMILY, FC_STYLE, FC_WEIGHT, FC_SLANT,
            FC_SPACING, FC_FILE, FC_INDEX,
            FC_LANG, FC_CHARSET, FC_FOUNDRY, FC_SCALABLE, FC_PIXEL_SIZE,
            FC_WIDTH, FC_FAMILYLANG,
#if FC_VERSION >= 20297
            FC_CAPABILITY,
#endif
            (const char *)nullptr
        };
        const char **p = properties;
        while (*p) {
            FcObjectSetAdd(os, *p);
            ++p;
        }
        fonts = FcFontList(nullptr, pattern, os);
        FcObjectSetDestroy(os);
        FcPatternDestroy(pattern);
    }

上面代码首先将 字体中需要解析的信息(比如字体名称FC_FAMILY,字体风格FC_STYLEden 等等) 塞到FcObjectSet中,等待解析。然后通过函数FcFontList获取系统中所有的字体信息(上面我们添加的)FcFontSet *fonts

然后开始通过循环解析我们系统中的字体

    for (int i = 0; i < fonts->nfont; i++)
        populateFromPattern(fonts->fonts[i]);

下面开始讲解 populateFromPattern

    if (FcPatternGetString(pattern, FC_FAMILY, 0, &value) != FcResultMatch)
        return;

    familyName = QString::fromUtf8((const char *)value);

    if (FcPatternGetString(pattern, FC_FAMILYLANG, 0, &value) == FcResultMatch)
        familyNameLang = QString::fromUtf8((const char *)value);

通过上面的函数我们得到了字体的名称,跟名称对应的语言。即 FC_FAMILY FC_FAMILYLANG。这里只上了部分代码,其它的函数也是如此获取的字体相关的信息

//xxxxxxxxxxxxxxxxxxxxxxxxxxx
    if (FcPatternGetInteger(pattern, FC_SLANT, 0, &slant_value) != FcResultMatch)
        slant_value = FC_SLANT_ROMAN;
    if (FcPatternGetInteger(pattern, FC_WEIGHT, 0, &weight_value) != FcResultMatch)
        weight_value = FC_WEIGHT_REGULAR;
    if (FcPatternGetInteger(pattern, FC_WIDTH, 0, &width_value) != FcResultMatch)
        width_value = FC_WIDTH_NORMAL;
    if (FcPatternGetInteger(pattern, FC_SPACING, 0, &spacing_value) != FcResultMatch)
        spacing_value = FC_PROPORTIONAL;
    if (FcPatternGetString(pattern, FC_FILE, 0, &file_value) != FcResultMatch)
        file_value = nullptr;
    if (FcPatternGetInteger(pattern, FC_INDEX, 0, &indexValue) != FcResultMatch)
        indexValue = 0;
    if (FcPatternGetBool(pattern, FC_SCALABLE, 0, &scalable) != FcResultMatch)
        scalable = FcTrue;
    if (FcPatternGetString(pattern, FC_FOUNDRY, 0, &foundry_value) != FcResultMatch)
        foundry_value = nullptr;
    if (FcPatternGetString(pattern, FC_STYLE, 0, &style_value) != FcResultMatch)
        style_value = nullptr;
    if (FcPatternGetBool(pattern,FC_ANTIALIAS,0,&antialias) != FcResultMatch)
        antialias = true;

//xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

这样,我们就得到了所有的字体信息,然后最后通过函数放入到Qt中

void qt_registerFont(const QString &familyName, const QString &stylename,
                     const QString &foundryname, int weight,
                     QFont::Style style, int stretch, bool antialiased,
                     bool scalable, int pixelSize, bool fixedPitch,
                     const QSupportedWritingSystems &writingSystems, void *handle)
{
    QFontDatabasePrivate *d = privateDb();
    qCDebug(lcFontDb) << "Adding font: familyName" << familyName << "stylename" << stylename << "weight" << weight
        << "style" << style << "pixelSize" << pixelSize << "antialiased" << antialiased << "fixed" << fixedPitch;
    QtFontStyle::Key styleKey;
    styleKey.style = style;
    styleKey.weight = weight;
    styleKey.stretch = stretch;
    QtFontFamily *f = d->family(familyName, QFontDatabasePrivate::EnsureCreated);
    f->fixedPitch = fixedPitch;

    for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
        if (writingSystems.supported(QFontDatabase::WritingSystem(i)))
            f->writingSystems[i] = QtFontFamily::Supported;
    }

    QtFontFoundry *foundry = f->foundry(foundryname, true);
    QtFontStyle *fontStyle = foundry->style(styleKey, stylename, true);
    fontStyle->smoothScalable = scalable;
    fontStyle->antialiased = antialiased;
    QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
    if (size->handle) {
        QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
        if (integration)
            integration->fontDatabase()->releaseHandle(size->handle);
    }
    size->handle = handle;
    f->populated = true;
}

最后总结下:实际上,Qt在不同的平台,分别调用的当前系统的库函数,来封装成统一的接口提供给开发者,我们不需要自己再引用对应的库了。这才是Qt的理念。
Code Less

公众号:Qt那些事儿

公众号

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在Linux下使用Qt可以很方便地生成一个代码编辑器,下面是基本的步骤: 1. 创建一个新的Qt Widgets应用程序项目并命名为“CodeEditor”。 2. 添加一个QPlainTextEdit控件到主窗口中。这个控件将用于编辑代码。 3. 添加一个QComboBox控件到主窗口中,用于选择代码语言。例如,C++、Python、Java等。 4. 在Resources文件夹中添加一个新的QSS文件“style.qss”,用于设置编辑器的样式。例如,设置字体、颜色、背景等。 5. 在代码中添加以下内容: ```python # 导入必要的模块 from PyQt5.QtCore import QFile, QTextStream from PyQt5.QtGui import QFontDatabase from PyQt5.QtWidgets import QMainWindow, QApplication, QFileDialog, QMessageBox, QComboBox from PyQt5.Qsci import QsciScintilla, QsciLexerCPP, QsciLexerPython, QsciLexerJava # 创建主窗口类 class MainWindow(QMainWindow): def __init__(self): super().__init__() self.initUI() def initUI(self): # 设置窗口标题 self.setWindowTitle("Code Editor") # 添加控件 self.combo_box = QComboBox(self) self.combo_box.addItems(["C++", "Python", "Java"]) self.combo_box.currentIndexChanged.connect(self.changeLanguage) self.setCentralWidget(self.text_edit) # 设置编辑器 self.text_edit = QsciScintilla(self) self.text_edit.setMarginWidth(0, "000") self.text_edit.setMarginLineNumbers(0, True) self.text_edit.setMarginWidth(1, "000") self.text_edit.setTabWidth(4) self.text_edit.setIndentationsUseTabs(False) self.text_edit.setAutoIndent(True) self.text_edit.setBraceMatching(QsciScintilla.SloppyBraceMatch) self.text_edit.setCaretLineVisible(True) self.text_edit.setCaretLineBackgroundColor(Qt.lightGray) self.text_edit.SendScintilla(QsciScintilla.SCI_SETSCROLLWIDTHTRACKING, True) # 设置样式 self.setStyle() # 设置样式 def setStyle(self): fontDatabase = QFontDatabase() font = fontDatabase.font("Monospace", "Regular", 12) self.text_edit.setFont(font) with QFile("style.qss") as file: file.open(QFile.ReadOnly | QFile.Text) stream = QTextStream(file) self.setStyleSheet(stream.readAll()) # 切换语言 def changeLanguage(self, index): if index == 0: lexer = QsciLexerCPP(self.text_edit) elif index == 1: lexer = QsciLexerPython(self.text_edit) elif index == 2: lexer = QsciLexerJava(self.text_edit) self.text_edit.setLexer(lexer) # 创建应用程序对象 app = QApplication([]) app.setApplicationName("Code Editor") # 创建主窗口对象 window = MainWindow() window.resize(800, 600) window.show() # 运行应用程序 app.exec_() ``` 运行代码,就可以看到一个简单的代码编辑器了。可以根据自己的需要改变编辑器的设置和样式。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值