文字化けにサヨナラ!QtのQFont::substitutes()と代替フォント設定

2025-06-06

QStringList QFont::substitutes() とは

QFont::substitutes() は、Qtの QFont クラスに属する静的関数 (static function) です。この関数は、特定のフォントファミリー名に対して設定された代替フォントファミリー名のリストQStringList として返します。

関数のシグネチャ

この関数には主に2つのオーバーロードがあります。

  1. static QStringList QFont::substitutes(const QString &familyName)
    • 引数に familyName (フォントファミリー名) を指定することで、そのフォントファミリーに設定されている代替フォントのリストを取得します。
  2. static QStringList QFont::substitutions()
    • 引数なしで呼び出すと、Qtアプリケーション内で現在登録されているすべての代替フォントファミリーのリストをソートされた形で返します。

何のために使うのか?

QFont::substitutes() は、主にフォントの「代替 (substitution)」メカニズムを管理するために使用されます。これは以下のようなシナリオで役立ちます。

  • フォントのエイリアス/別名
    あるフォントを別の名前で参照したい場合に、代替を設定することで実現できます。
  • フォントが存在しない場合の代替
    あるフォントファミリーがシステムにインストールされていない場合、または利用できない場合に、代わりにどのフォントを使うかを指定することができます。

代替フォントの登録方法

QFont::substitutes() は代替フォントのリストを取得するための関数ですが、実際に代替フォントを設定するには、以下の静的関数を使用します。

  • static void QFont::removeSubstitution(const QString &familyName)
    • familyName に設定されたすべての代替フォントを削除します。
  • static void QFont::insertSubstitutions(const QString &familyName, const QStringList &substituteNames)
    • familyName に対して substituteNames のリストを代替フォントとして追加します。
  • static void QFont::insertSubstitution(const QString &familyName, const QString &substituteName)
    • familyName に対して substituteName を代替フォントとして1つ追加します。

具体的な使用例

例えば、「MyCustomFont」というフォントがシステムにない場合に、「Arial」と「Meiryo」を代替フォントとして使いたい場合を考えます。

#include <QApplication>
#include <QFont>
#include <QFontDatabase>
#include <QStringList>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    // "MyCustomFont" に代替フォントを設定
    QStringList substitutes;
    substitutes << "Arial" << "Meiryo";
    QFont::insertSubstitutions("MyCustomFont", substitutes);

    // "MyCustomFont" の代替フォントリストを取得
    QStringList retrievedSubstitutes = QFont::substitutes("MyCustomFont");

    qDebug() << "代替フォントリスト for 'MyCustomFont':" << retrievedSubstitutes;
    // 出力例: 代替フォントリスト for 'MyCustomFont': ("Arial", "Meiryo")

    // 存在しないフォントファミリーの代替を取得しようとすると空のリストが返される
    qDebug() << "代替フォントリスト for 'NonExistentFont':" << QFont::substitutes("NonExistentFont");
    // 出力例: 代替フォントリスト for 'NonExistentFont': ()

    // 登録されている全ての代替フォントファミリー名を取得
    qDebug() << "登録されている全ての代替フォントファミリー名:" << QFont::substitutions();
    // 出力例: 登録されている全ての代替フォントファミリー名: ("MyCustomFont")

    // 代替フォントを削除
    QFont::removeSubstitution("MyCustomFont");
    qDebug() << "代替フォントリスト for 'MyCustomFont' (削除後):" << QFont::substitutes("MyCustomFont");
    // 出力例: 代替フォントリスト for 'MyCustomFont' (削除後): ()

    return a.exec();
}
  • システムにインストールされているフォントの情報を取得したい場合は、QFontDatabase クラスを使用するのが適切です。QFont::substitutes() はあくまでアプリケーション内で設定されたフォントの代替ルールに関する情報を提供します。
  • QFont::substitutes() は、QFont オブジェクトが実際にどのフォントを使用するかを決定するフォントマッチングアルゴリズムに影響を与えます。Qtは、要求されたフォントが見つからない場合に、設定された代替フォントを考慮して最適なフォントを決定しようとします。


QFont::substitutes() 自体は単に代替フォントのリストを返す静的関数なので、この関数呼び出し自体が直接エラーになることは稀です。しかし、その前後の代替フォントの設定 (insertSubstitution, insertSubstitutions) や、フォントの描画プロセスに関連して、期待通りの結果が得られないことがあります。

代替フォントが適用されない、または期待通りのフォントにならない

症状
QFont::insertSubstitution()insertSubstitutions() で代替フォントを設定したにもかかわらず、UI上で表示されるフォントが意図した代替フォントにならない。

原因とトラブルシューティング

  • Qt Style Sheetsとの競合
    QWidget::setStyleSheet() を使用してフォントを設定している場合、スタイルシートの規則がプログラムで設定した QFont オブジェクトのフォント設定を上書きする可能性があります。
    • 対策
      スタイルシートを使用している場合は、スタイルシート内でフォントファミリーと代替フォントを定義するか、プログラムでフォントを設定する際にはスタイルシートとの競合に注意してください。
  • Qtのフォントマッチングアルゴリズムの挙動
    Qtは、要求されたフォントと利用可能なフォントをマッチングさせるための複雑なアルゴリズムを持っています。代替フォントが設定されていても、特定の QFont の属性(太さ、スタイル、ポイントサイズなど)によっては、別のフォントが優先されてしまうことがあります。
    • 対策
      • QFont オブジェクトの他の属性(setWeight(), setStyle(), setPointSizeF() など)が、意図しないフォント選択を招いていないか確認する。
      • QFont::setStyeHint()QFont::setStyleStrategy() を使用して、フォントマッチングのヒントを与えることで、より望ましいフォントが選択されるように試す。
  • フォントのロードタイミング
    QFont::insertSubstitution()insertSubstitutions() は、アプリケーションの起動時など、フォントを使用する前に呼び出す必要があります。後から設定しても、既にロードされて使用されているフォントには影響しない場合があります。
    • 対策
      QApplication オブジェクトが作成された直後など、アプリケーションの初期化段階で代替フォントを設定するようにしてください。
  • 代替フォントがシステムにインストールされていない
    代替として指定したフォントが、実行環境のシステムにインストールされていない場合、その代替フォントは利用できません。Qtはさらに別のフォールバックフォントを探そうとしますが、それでも期待通りのフォントにはならない可能性があります。
    • 対策
      必要な代替フォントがすべてのターゲット環境にインストールされていることを確認するか、より一般的な代替フォント(例: "Sans Serif", "Serif", "Monospace" など)を使用することを検討してください。
  • フォントファミリー名のスペルミス
    設定したいフォントファミリー名 (例: "MyCustomFont") や代替フォントファミリー名 (例: "Arial") のスペルが間違っていると、代替が適用されません。大文字・小文字、スペースなども含めて正確に指定する必要があります。
    • 対策
      QFontDatabase::families() などを使って、システムに存在するフォントの正確な名前を確認しましょう。

QFont::substitutions() が空のリストを返す

症状
QFont::substitutions() を呼び出しても、設定したはずの代替フォントファミリー名が含まれていない空の QStringList が返される。

原因とトラブルシューティング

  • 別のプロセス/スコープでの設定
    代替フォントの設定が、現在のアプリケーションのプロセスやスコープとは異なる場所で行われている可能性があります。
    • 対策
      Qtアプリケーションは通常、単一のプロセスで実行されますが、もし複数のDLLや共有ライブラリでQFont設定をいじっている場合は、それぞれの設定が正しく連携しているか確認してください。
  • 代替フォントが登録されていない
    QFont::insertSubstitution() または insertSubstitutions() がまだ呼び出されていないか、正しく呼び出されていない可能性があります。
    • 対策
      QFont::insertSubstitution() または insertSubstitutions() が、QFont::substitutions() を呼び出す前に実行されていることを確認してください。

QFont::substitutes() が存在しないフォント名を返す (デバッグ時など)

症状
QFont::substitutes("存在しないフォント名") を呼び出すと、空のリストが返されるはずなのに、なぜか別のフォント名がリストに含まれている、または予期せぬ結果になる。



QStringList QFont::substitutes() のプログラミング例

QStringList QFont::substitutes() は、特定のフォントファミリーに設定されている代替フォントのリストを取得するために使用されます。この機能は、フォントが存在しない場合や、特定の文字セットをサポートするフォントが必要な場合に非常に役立ちます。

以下に、代替フォントの設定、取得、およびその情報を表示する具体的なコード例を示します。

基本的な代替フォントの設定と取得

この例では、「MyCustomFont」という架空のフォントに対して「Arial」と「Meiryo」を代替フォントとして設定し、その後 QFont::substitutes() を使ってそのリストを取得します。

#include <QApplication>
#include <QFont>
#include <QFontDatabase> // 利用可能なフォントの確認に便利
#include <QStringList>
#include <QDebug> // デバッグ出力用
#include <QLabel> // GUI表示用
#include <QVBoxLayout> // レイアウト用

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    // ----------------------------------------------------
    // 1. 代替フォントの設定
    // ----------------------------------------------------
    // "MyCustomFont" がシステムにインストールされていない場合に、
    // 代替として使用したいフォントをリストで指定します。
    QStringList myCustomFontSubstitutes;
    myCustomFontSubstitutes << "Arial" << "Meiryo UI"; // ArialとメイリオUIを代替に指定

    // QFont::insertSubstitutions() を使って代替フォントを登録します。
    // これは静的関数であり、アプリケーション全体に影響します。
    QFont::insertSubstitutions("MyCustomFont", myCustomFontSubstitutes);
    qDebug() << "--- 代替フォント設定完了 ---";

    // "JapaneseFont" という別のフォントに対しても代替を設定してみます。
    QFont::insertSubstitution("JapaneseFont", "MS Gothic"); // MS Gothicを代替に指定
    qDebug() << "--- 別の代替フォント設定完了 (JapaneseFont -> MS Gothic) ---";

    // ----------------------------------------------------
    // 2. 代替フォントの取得
    // ----------------------------------------------------

    // "MyCustomFont" に設定された代替フォントリストを取得します。
    QStringList retrievedSubstitutesForMyCustomFont = QFont::substitutes("MyCustomFont");
    qDebug() << "\n'MyCustomFont' の代替フォントリスト:";
    if (retrievedSubstitutesForMyCustomFont.isEmpty()) {
        qDebug() << "  代替フォントは設定されていません。";
    } else {
        for (const QString &substitute : retrievedSubstitutesForMyCustomFont) {
            qDebug() << "  - " << substitute;
        }
    }
    // 期待される出力:
    // 'MyCustomFont' の代替フォントリスト:
    //   - Arial
    //   - Meiryo UI

    // "JapaneseFont" に設定された代替フォントリストを取得します。
    QStringList retrievedSubstitutesForJapaneseFont = QFont::substitutes("JapaneseFont");
    qDebug() << "\n'JapaneseFont' の代替フォントリスト:";
    if (retrievedSubstitutesForJapaneseFont.isEmpty()) {
        qDebug() << "  代替フォントは設定されていません。";
    } else {
        for (const QString &substitute : retrievedSubstitutesForJapaneseFont) {
            qDebug() << "  - " << substitute;
        }
    }
    // 期待される出力:
    // 'JapaneseFont' の代替フォントリスト:
    //   - MS Gothic

    // 代替が設定されていないフォント(例: "NonExistentFont")のリストを取得します。
    QStringList nonExistentFontSubstitutes = QFont::substitutes("NonExistentFont");
    qDebug() << "\n'NonExistentFont' の代替フォントリスト:";
    if (nonExistentFontSubstitutes.isEmpty()) {
        qDebug() << "  代替フォントは設定されていません。";
    } else {
        for (const QString &substitute : nonExistentFontSubstitutes) {
            qDebug() << "  - " << substitute;
        }
    }
    // 期待される出力:
    // 'NonExistentFont' の代替フォントリスト:
    //   代替フォントは設定されていません。

    // ----------------------------------------------------
    // 3. アプリケーション全体に登録されている全ての代替フォントファミリー名を取得
    // ----------------------------------------------------
    // QFont::substitutions() を使うと、代替設定がされている全てのフォントファミリー名を取得できます。
    QStringList allSubstitutedFamilies = QFont::substitutions();
    qDebug() << "\nアプリケーションに登録されている全ての代替フォントファミリー:";
    if (allSubstitutedFamilies.isEmpty()) {
        qDebug() << "  代替フォントファミリーは登録されていません。";
    } else {
        // リストはソートされて返されます
        for (const QString &family : allSubstitutedFamilies) {
            qDebug() << "  - " << family;
        }
    }
    // 期待される出力:
    // アプリケーションに登録されている全ての代替フォントファミリー:
    //   - JapaneseFont
    //   - MyCustomFont


    // ----------------------------------------------------
    // 4. GUIでの表示例
    // ----------------------------------------------------
    // 代替フォントが実際にどのように適用されるかを示す簡単なGUI
    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *label1 = new QLabel("Hello, World! (MyCustomFont)");
    QFont font1("MyCustomFont", 18);
    label1->setFont(font1);
    layout->addWidget(label1);

    QLabel *label2 = new QLabel("こんにちは、世界! (JapaneseFont)");
    QFont font2("JapaneseFont", 18);
    label2->setFont(font2);
    layout->addWidget(label2);

    // フォント情報(実際に使われているフォント)を表示するラベル
    QLabel *fontInfoLabel1 = new QLabel();
    QFontInfo fontInfo1(label1->font());
    fontInfoLabel1->setText(QString("Label 1 Actual Font: %1 (%2)").arg(fontInfo1.family()).arg(fontInfo1.pointSize()));
    layout->addWidget(fontInfoLabel1);

    QLabel *fontInfoLabel2 = new QLabel();
    QFontInfo fontInfo2(label2->font());
    fontInfoLabel2->setText(QString("Label 2 Actual Font: %1 (%2)").arg(fontInfo2.family()).arg(fontInfo2.pointSize()));
    layout->addWidget(fontInfoLabel2);

    window.setWindowTitle("QFont Substitutes Example");
    window.show();

    // ----------------------------------------------------
    // 5. 代替フォントの削除
    // ----------------------------------------------------
    // アプリケーション終了前に代替フォントを削除することも可能です。
    // 通常はアプリケーション終了時に自動的に解放されますが、
    // 必要に応じて明示的に削除できます。
    QFont::removeSubstitution("MyCustomFont");
    QFont::removeSubstitution("JapaneseFont");

    qDebug() << "\n--- 代替フォント削除後 ---";
    qDebug() << "'MyCustomFont' の代替フォントリスト (削除後):" << QFont::substitutes("MyCustomFont");
    qDebug() << "'JapaneseFont' の代替フォントリスト (削除後):" << QFont::substitutes("JapaneseFont");
    qDebug() << "登録されている全ての代替フォントファミリー (削除後):" << QFont::substitutions();

    return a.exec();
}

解説

  1. #include ディレクティブ
    必要なヘッダファイルを含めます。
    • <QApplication>: Qtアプリケーションの基本クラス。
    • <QFont>: フォントを扱うクラス。
    • <QFontDatabase>: システムにインストールされているフォントの情報を提供します。
    • <QStringList>: 文字列のリストを扱うクラス。
    • <QDebug>: デバッグメッセージを出力するためのクラス。
    • <QLabel>: GUIにテキストを表示するためのウィジェット。
    • <QVBoxLayout>: ウィジェットを垂直方向に配置するレイアウト。
  2. QApplication a(argc, argv);
    Qtアプリケーションのインスタンスを作成します。これはGUIアプリケーションでQtの機能を使用するために必須です。
  3. QFont::insertSubstitutions("MyCustomFont", myCustomFontSubstitutes);
    • "MyCustomFont" というフォントファミリー名に対して、myCustomFontSubstitutes リスト内のフォントを代替として登録します。
    • これは静的関数なので、QFont オブジェクトを作成する前に呼び出すことができます。
  4. QStringList retrievedSubstitutesForMyCustomFont = QFont::substitutes("MyCustomFont");
    • ここで QFont::substitutes() を呼び出し、"MyCustomFont" に設定されている代替フォントのリストを取得します。
    • 結果は QStringList で返されます。設定されていない場合は空のリストになります。
  5. QStringList allSubstitutedFamilies = QFont::substitutions();
    • 引数なしの QFont::substitutions() を呼び出すと、アプリケーション内で代替が設定されているすべてのフォントファミリー名がリストで返されます。これは、どのフォントが代替設定を持っているかを俯瞰的に確認するのに便利です。
  6. GUIでの表示例
    • QLabel を作成し、setFont() でフォントを設定します。ここで QFont("MyCustomFont", 18) のように、代替設定をしたフォント名を指定します。
    • QFontInfo を使用して、実際に描画に使われているフォントの情報を取得・表示します。これにより、代替が正しく機能しているかを確認できます。もし「MyCustomFont」がシステムに存在しない場合、fontInfo1.family() は「Arial」または「Meiryo UI」のどちらか、あるいはQtが選択した別のフォールバックフォント名を表示するはずです。
  7. QFont::removeSubstitution("MyCustomFont");
    • 特定のフォントファミリーに対する代替設定を削除します。通常、アプリケーション終了時に自動的にクリーンアップされますが、実行中に動的に代替を変更する必要がある場合などに使用します。

上記のコードを実行すると、コンソールには以下のような出力(環境によってフォント名や順序は異なる場合があります)が表示され、GUIウィンドウが開きます。

--- 代替フォント設定完了 ---
--- 別の代替フォント設定完了 (JapaneseFont -> MS Gothic) ---

'MyCustomFont' の代替フォントリスト:
  - Arial
  - Meiryo UI

'JapaneseFont' の代替フォントリスト:
  - MS Gothic

'NonExistentFont' の代替フォントリスト:
  代替フォントは設定されていません。

アプリケーションに登録されている全ての代替フォントファミリー:
  - JapaneseFont
  - MyCustomFont

--- 代替フォント削除後 ---
'MyCustomFont' の代替フォントリスト (削除後): ()
'JapaneseFont' の代替フォントリスト (削除後): ()
登録されている全ての代替フォントファミリー (削除後): ()


Qtで QStringList QFont::substitutes() を使用することは、特定のフォントファミリーに対する明示的な代替フォントを設定・取得する直接的な方法です。しかし、Qtのフォントシステムには、より広範なフォントの選択やフォールバックメカニズムを制御するための他の方法も存在します。これらは QFont::substitutes() の直接的な代替というよりも、フォントの選択とレンダリングをより詳細に制御するための補完的な方法と考えることができます。

QFont::setStyleHint() と QFont::setStyleStrategy()

これは、フォントが利用できない場合にQtがフォールバックフォントを選択する方法に影響を与える最も重要な方法の一つです。

  • QFont::setStyleHint(QFont::StyleHint hint, QFont::StyleStrategy strategy = QFont::PreferDefault):
    • QFont::StyleHint: 要求されたフォントファミリーが見つからない場合に、Qtがどのような種類のフォントを優先して代替として探すかを指定します。例えば、QFont::SansSerif (ゴシック体)、QFont::Serif (明朝体)、QFont::Monospace (等幅フォント) などがあります。これにより、特定のフォントが存在しない場合でも、視覚的に近いスタイルのフォントが選ばれやすくなります。
    • QFont::StyleStrategy: フォントマッチングの戦略をより細かく制御します。
      • QFont::PreferDefault: デフォルトの戦略。
      • QFont::NoFontMerging: 指定したフォントに特定の文字のグリフがない場合でも、Qtが自動的に別のフォントからグリフを「マージ」して表示する機能を無効にします。これは、テキストの一部が意図しないフォントで表示されるのを防ぎたい場合に有用ですが、文字化けのリスクも伴います。
      • QFont::PreferQuality / QFont::PreferMatch: フォントの品質や、要求されたサイズにどれだけ正確にマッチするかを優先するかどうかを指定します。

使用例

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QVBoxLayout>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // ----------------------------------------------------
    // StyleHintとStyleStrategyを使った代替方法
    // ----------------------------------------------------

    // 存在しないフォントを要求し、SansSerifをヒントとして与える
    QLabel *label1 = new QLabel("Hello, World! (NonExistentFont with SansSerif hint)");
    QFont font1("NonExistentFont", 18);
    font1.setStyleHint(QFont::SansSerif); // ゴシック体を代替として優先
    label1->setFont(font1);
    layout->addWidget(label1);
    qDebug() << "Label 1 (SansSerif hint) Actual Font:" << QFontInfo(label1->font()).family();

    // 存在しないフォントを要求し、Serifをヒントとして与える
    QLabel *label2 = new QLabel("Hello, World! (NonExistentFont with Serif hint)");
    QFont font2("NonExistentFont", 18);
    font2.setStyleHint(QFont::Serif); // 明朝体を代替として優先
    label2->setFont(font2);
    layout->addWidget(label2);
    qDebug() << "Label 2 (Serif hint) Actual Font:" << QFontInfo(label2->font()).family();

    // 日本語フォントの例 (Noto Sans Japanese がない場合に汎用ゴシックを使用)
    QLabel *label3 = new QLabel("こんにちは、世界! (Noto Sans Japanese with SansSerif hint)");
    QFont font3("Noto Sans Japanese", 18);
    // Noto Sans Japanese がインストールされていない可能性を考慮し、SansSerif をヒントに
    font3.setStyleHint(QFont::SansSerif);
    font3.setStyleStrategy(QFont::PreferAntialias); // アンチエイリアスを優先
    label3->setFont(font3);
    layout->addWidget(label3);
    qDebug() << "Label 3 (Japanese, SansSerif hint) Actual Font:" << QFontInfo(label3->font()).family();


    window.setWindowTitle("QFont StyleHint/Strategy Example");
    window.show();

    return a.exec();
}

解説
QFont::setStyleHint() は、Qtがフォントを解決する際の「一般的なルール」を設定します。これにより、特定のフォントファミリーが見つからなくても、その目的に合った(例: 等幅、セリフなしなど)フォントが自動的に選択される可能性が高まります。QFont::substitutes() は特定のフォントファミリー名に対して別のフォントファミリー名を直接マッピングするのに対し、setStyleHint() はより抽象的な「スタイル」に基づいてフォントを決定します。

QFontDatabase クラスの活用

QFontDatabase は、システムにインストールされているフォントに関する情報を提供します。これを使うことで、利用可能なフォントを動的に検索し、アプリケーションの要件に基づいてフォントを選択できます。

  • QFontDatabase::addApplicationFont() / addApplicationFontFromData(): アプリケーションのリソースとしてフォントファイルを組み込み、システムにインストールされていなくてもそのフォントを使用できるようにします。
  • QFontDatabase::has</span><span style="font-family: Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; font-size: 1em; line-height: 1.5; padding: 0px 4px; border-radius: 4px; background-color: rgb(238, 238, 238);">Family(const QString &family): 特定のフォントファミリーがシステムに存在するかどうかを確認します。
  • QFontDatabase::families(): システムにインストールされているすべてのフォントファミリー名を取得します。

使用例

特定のフォントがシステムに存在しない場合に、別のフォントをプログラムで選択するロジックを実装します。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QFontDatabase>
#include <QVBoxLayout>
#include <QDebug>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // ----------------------------------------------------
    // QFontDatabase を使った代替フォントの選択
    // ----------------------------------------------------

    QString desiredFont = "MySuperCoolFont"; // 存在しない可能性のあるフォント
    QString fallbackFont = "Arial";          // 第一候補の代替フォント
    QString lastResortFont = "Noto Sans";    // 最終的な代替フォント

    QFont chosenFont;
    if (QFontDatabase::hasFamily(desiredFont)) {
        chosenFont.setFamily(desiredFont);
        qDebug() << "使用フォント:" << desiredFont;
    } else if (QFontDatabase::hasFamily(fallbackFont)) {
        chosenFont.setFamily(fallbackFont);
        qDebug() << "使用フォント: (代替)" << fallbackFont;
    } else if (QFontDatabase::hasFamily(lastResortFont)) {
        chosenFont.setFamily(lastResortFont);
        qDebug() << "使用フォント: (最終代替)" << lastResortFont;
    } else {
        // システムに存在する汎用フォントを選ぶ
        chosenFont.setFamily(QFontDatabase::systemFont(QFontDatabase::GeneralFont).family());
        qDebug() << "使用フォント: (システム汎用)" << chosenFont.family();
    }
    chosenFont.setPointSize(20);

    QLabel *label = new QLabel("This text uses a dynamically chosen font.");
    label->setFont(chosenFont);
    layout->addWidget(label);

    // 日本語テキストに適切なフォントを選択する例
    QString japaneseText = "これは日本語のテキストです。";
    QString japaneseDesiredFont = "UD デジタル 教科書体 N-B"; // あるかもしれない日本語フォント
    QString japaneseFallback1 = "Meiryo UI"; // Windowsの一般的な日本語フォント
    QString japaneseFallback2 = "IPA Gothic"; // オープンソースの日本語フォント

    QFont japaneseChosenFont;
    if (QFontDatabase::hasFamily(japaneseDesiredFont)) {
        japaneseChosenFont.setFamily(japaneseDesiredFont);
        qDebug() << "日本語使用フォント:" << japaneseDesiredFont;
    } else if (QFontDatabase::hasFamily(japaneseFallback1)) {
        japaneseChosenFont.setFamily(japaneseFallback1);
        qDebug() << "日本語使用フォント: (代替1)" << japaneseFallback1;
    } else if (QFontDatabase::hasFamily(japaneseFallback2)) {
        japaneseChosenFont.setFamily(japaneseFallback2);
        qDebug() << "日本語使用フォント: (代替2)" << japaneseFallback2;
    } else {
        // 日本語をサポートするシステムフォントを探す
        // QFontDatabase::systemFont() は、OSのデフォルトフォントを取得する
        // QFont::AnyScript で、任意のスクリプトをサポートするフォントを探すヒント
        japaneseChosenFont.setFamily(QFontDatabase::systemFont(QFontDatabase::FixedFont).family());
        qDebug() << "日本語使用フォント: (システムフォールバック)" << japaneseChosenFont.family();
    }
    japaneseChosenFont.setPointSize(16);

    QLabel *japaneseLabel = new QLabel(japaneseText);
    japaneseLabel->setFont(japaneseChosenFont);
    layout->addWidget(japaneseLabel);


    window.setWindowTitle("QFontDatabase Example");
    window.show();

    return a.exec();
}

解説
QFontDatabase を使用する方法は、より明示的にフォントの存在を確認し、それに基づいてプログラムでフォントを選択するロジックを組む場合に適しています。これは QFont::substitutes() が提供する「暗黙的な代替ルール」とは異なり、開発者がフォント選択の優先順位を詳細に制御できるため、特定のフォント環境に依存するアプリケーションで信頼性を高めることができます。

GUIのフォント設定をCSSライクなスタイルシートで行う場合、フォントファミリーのリストを指定することで、Qtが自動的に代替フォントを探すようにできます。これはウェブブラウザのCSS font-family プロパティと非常に似ています。

  • font-family: "Desired Font", "Fallback Font 1", "Fallback Font 2", sans-serif;

使用例 (C++ でスタイルシートを適用)

#include <QApplication>
#include <QLabel>
#include <QWidget>
#include <QVBoxLayout>

int main(int argc, char *argv[]) {
    QApplication a(argc, argv);

    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *label1 = new QLabel("Hello, Style Sheet World!");
    // スタイルシートでフォントを指定。最初のフォントがなければ次のフォントを試す。
    // 最後の 'serif' は汎用フォントファミリーのヒント。
    label1->setStyleSheet("font-family: 'NonExistentSerifFont', 'Times New Roman', 'Noto Serif', serif; font-size: 20px;");
    layout->addWidget(label1);

    QLabel *label2 = new QLabel("日本語スタイルシートの例!");
    label2->setStyleSheet("font-family: 'MyCustomJapaneseFont', 'Meiryo UI', 'IPA Gothic', sans-serif; font-size: 18px;");
    layout->addWidget(label2);

    window.setWindowTitle("Qt Style Sheet Font Fallback");
    window.show();

    return a.exec();
}

解説
スタイルシートを使う方法は、GUIの見た目をXML/CSS形式で定義したい場合に非常に強力です。これは QFont::substitutes() のようなコードベースでの代替設定とは異なり、より宣言的なアプローチです。Qtのレンダリングエンジンは、スタイルシートに指定されたフォントリストを左から順に評価し、利用可能な最初のフォントを使用します。

QStringList QFont::substitutes() は特定のフォントファミリーに直接的な代替を定義するのに便利ですが、Qtのフォントシステムはそれ以外にも様々な方法でフォントのフォールバックや選択を扱います。

  • Qt Style Sheets
    UIの見た目を宣言的に定義したい場合、特に動的なフォントの選択ロジックが不要で、CSSライクなフォールバックリストで十分な場合に便利です。
  • QFontDatabase
    システムに存在するフォントを動的にクエリし、プログラムのロジックに基づいて最適なフォントを選択する、より細粒度の制御が必要な場合に適しています。アプリケーションにカスタムフォントを組み込む際にも使われます。
  • QFont::setStyleHint() / setStyleStrategy()
    フォントの一般的な「種類」に基づいて、Qtが最適なフォールバックフォントを選択するように誘導したい場合に有効です。特定のフォント名ではなく、より広範なスタイルのマッチングを行います。
  • QFont::substitutes() (と関連する insertSubstitution など)
    プログラムで特定のフォントファミリー名を別のファミリー名にマッピングする、直接的かつグローバルな代替ルールを設定する場合に最適です。