QFont::setFamilies()

2025-06-06

この関数は、単一のフォントファミリーではなく、フォントファミリーのリストを受け取ります。リスト内のフォントは、指定された順序で優先的に使用されます。つまり、システムがリストの最初のフォントを利用できる場合はそれを使用し、利用できない場合はリストの次のフォントを試す、というように動作します。

なぜ複数のフォントファミリーを指定するのか?

これは、アプリケーションのフォント表示の**堅牢性(ロバストネス)**を高めるためです。

  1. フォントの可用性
    ユーザーのシステムに特定のフォントがインストールされていない場合があります。setFamilies()を使用することで、代替フォントを複数指定し、どのシステムでも意図した通りの見た目に近い表示を保証できます。
  2. デザインの柔軟性
    特定のフォントが見つからない場合でも、デザインの意図をある程度維持できるような代替フォントを指定することで、レイアウトの崩れなどを防ぐことができます。

C++での使用例は以下のようになります。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QStringList> // QStringList を使う場合
// または #include <QVector> // QVector<QString> を使う場合

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

    QLabel label("Qt プログラミングのフォント設定");

    QFont font;
    QStringList families; // または QVector<QString> families;

    // 優先順位が高い順にフォントファミリーを追加
    families << "Meiryo UI"     // Windows のメイリオ UI
             << "Yu Gothic UI"  // Windows の游ゴシック UI
             << "Hiragino Sans GB" // macOS のヒラギノ角ゴシック GB (中国語向けだが代替として)
             << "Arial"         // 英語圏の標準フォント
             << "sans-serif";   // 一般的なサンセリフフォント(最終的な代替)

    font.setFamilies(families); // フォントファミリーのリストを設定
    font.setPointSize(16);      // フォントサイズを設定

    label.setFont(font);
    label.show();

    return app.exec();
}

この例では、"Meiryo UI", "Yu Gothic UI", "Hiragino Sans GB", "Arial", "sans-serif" の順でフォントが試されます。もしユーザーのシステムに "Meiryo UI" があればそれが使われ、なければ "Yu Gothic UI" が試される、といった具合です。最終的にどのフォントも見つからない場合は、システムが提供する汎用的なサンセリフフォントが使用されます。



指定したフォントが適用されない (または意図しないフォントが適用される)

これは最もよくある問題です。

原因

  • Qtバージョン間の挙動の違い (特にQt 5からQt 6)
    過去のQtバージョン(特にQt 5)では、QFont::setFamily() にカンマ区切りのフォント名を渡すと、内部的に setFamilies() と同様に扱われることがありました。しかし、Qt 6ではこの挙動は廃止され、カンマを含む文字列は単一のフォントファミリー名として解釈されます。そのため、Qt 5からの移行でフォントが適用されない場合は、明示的に setFamilies() を使用する必要があります。
  • フォントの属性の不一致
    QFont オブジェクトには、ファミリー名以外にもサイズ、太さ、イタリックなどの属性があります。特定のフォントがこれらの属性の一部に対応していない場合、Qt は類似のフォントを選択したり、属性の一部を無視したりすることがあります。
  • フォントの優先順位
    setFamilies() に渡すリストの順序が重要です。リストの最初に指定したフォントが最も優先されます。意図しないフォントが適用されている場合、それがリストの早い段階にあり、かつシステムに存在している可能性があります。
  • フォントがシステムにインストールされていない
    指定したフォントがユーザーのシステムに存在しない場合、Qt はリストの次のフォントを試すか、最終的にはデフォルトのフォント(例: "sans-serif" やシステム標準フォント)を使用します。
  • フォント名の間違い
    フォントファミリー名が正確でない場合、システムはそのフォントを見つけられません。大文字・小文字、スペース、ハイフンなどの表記が少しでも異なると認識されないことがあります。

トラブルシューティング

  • Qt 5 から Qt 6 への移行時の注意
    • もし QFont::setFamily("MyFont, AnotherFont"); のように単一の文字列で複数のフォントファミリーを指定していた場合、Qt 6ではこれが動作しなくなります。
    • 代わりに QStringList families; families << "MyFont" << "AnotherFont"; font.setFamilies(families); のように setFamilies() を使用するようにコードを修正してください。
  • QFontDatabase を使用したフォントの存在確認
    特定のフォントがシステムに存在するかどうかは QFontDatabase::hasFamily() で確認できます。
    if (QFontDatabase::hasFamily("Meiryo UI")) {
        qDebug() << "Meiryo UI is available.";
    } else {
        qDebug() << "Meiryo UI is NOT available.";
    }
    
  • 代替フォントの確認
    setFamilies() のリストに、確実に存在する汎用的なフォント(例: "sans-serif", "serif", "monospace" など)を末尾に追加して、最終的な代替フォントが機能するか確認します。
  • フォント名の確認
    • システムにインストールされているフォントの正確な名前を確認します(OSのフォント設定画面など)。
    • フォント名を文字列として直接指定するのではなく、QFontDatabase::families() などで利用可能なフォントリストを取得し、そこから選択する方が確実です。
    • qDebug() << font.family();qDebug() << font.families(); を使って、実際に QFont オブジェクトに設定されているフォントファミリーを確認します。

カスタムフォントの適用がうまくいかない

アプリケーションに独自のフォントファイル(.ttf, .otfなど)を含めて使用したい場合に発生します。

原因

  • ファイルパスの間違い
    フォントファイルのパスが間違っている、またはリソースファイルとして組み込んでいる場合はリソースパスが間違っている。
  • フォントがQtのフォントデータベースに登録されていない
    QFontDatabase::addApplicationFont() でフォントファイルを登録する必要があります。

トラブルシューティング

  • リソースパスの確認
    .pro ファイルに RESOURCE += my_resources.qrc のようにリソースファイルが正しく含まれているか確認します。また、.qrc ファイル内のエイリアスも確認します。

フォントの表示がシステムによって異なる (クロスプラットフォームの問題)

Windows、macOS、Linux など、異なるOSで実行するとフォントの見た目が変わる。

原因

  • フォールバックの挙動
    setFamilies() で指定したフォントが利用できない場合、各OSは異なるフォールバックメカニズムやデフォルトフォントを使用します。
  • フォントのヒンティングとアンチエイリアシング
    OSやグラフィックドライバーによって、フォントのヒンティング(小さなサイズでの文字のクリアさ)やアンチエイリアシング(文字の滑らかさ)の処理が異なります。
  • OS間のフォントの違い
    同じフォント名でも、OSによってフォントのバージョン、レンダリングエンジン、デフォルトのグリフが異なります。

トラブルシューティング

  • テスト環境の多様化
    開発環境だけでなく、異なるOSや解像度の環境で実際にアプリケーションをテストすることが重要です。
  • QFont::setStyleStrategy() の使用
    QFont::PreferAntialiasQFont::NoAntialias などを設定することで、レンダリングの挙動を調整できる場合があります。ただし、これはシステムの設定やグラフィックドライバーによって挙動が変わる可能性があります。
  • OS固有のフォントをリストに含める
    特定のOSで最適な表示を望む場合は、そのOSで広く利用されているフォントを setFamilies() のリストに含めます。
    QStringList families;
    #ifdef Q_OS_WIN
        families << "Yu Gothic UI" << "Meiryo UI";
    #elif defined(Q_OS_MAC)
        families << "Hiragino Sans" << "Apple Color Emoji"; // 絵文字フォントの例
    #elif defined(Q_OS_LINUX)
        families << "Noto Sans CJK JP" << "DejaVu Sans";
    #endif
    families << "sans-serif"; // 最終的なフォールバック
    font.setFamilies(families);
    
  • 一般的なフォントの選択
    多くのOSで一般的に利用可能なフォント(例: Arial, Times New Roman, Courier New など)を優先的に使用することで、ある程度の統一感を保てます。

QFont オブジェクトが正しくウィジェットに適用されない

フォントを設定したのに、ウィジェットの表示が変わらない。

原因

  • スタイルシートとの競合
    ウィジェットにQtスタイルシート(QSS)が適用されている場合、スタイルシートのフォント設定が setFont() で設定したフォントを上書きする可能性があります。
    • QSSでフォントが設定されていないか確認する。
    • QSSで設定されている場合は、QSS側でフォントファミリーを調整するか、setFont() よりもQSSを優先するかを検討する。
  • ポインタの間違い
    QLabel::setFont(QFont *font) のようにポインタを渡そうとして、参照渡しを期待する関数シグネチャと合わない場合。
    // 誤った例 (コンパイルエラーになるか、意図しない動作)
    // QFont *font = new QFont();
    // label->setFont(font);
    
    // 正しい例
    QFont font;
    label->setFont(font); // QFont オブジェクトを直接渡す
    // または
    // label->setFont(*font); // ポインタの場合、デリファレンスする
    
  • setFont() の呼び出し忘れ
    QFont オブジェクトを作成して setFamilies() を呼び出しただけでは、ウィジェットにフォントは適用されません。必ず対象の QWidgetQApplication オブジェクトの setFont() メソッドを呼び出す必要があります。
    QLabel *label = new QLabel("Hello");
    QFont font;
    QStringList families;
    families << "Arial";
    font.setFamilies(families);
    label->setFont(font); // これが重要
    

多数のフォントを頻繁に生成・設定すると、アプリケーションの起動や描画が遅くなることがあります。

原因

  • フォントオブジェクトの頻繁な生成
    必要以上に QFont オブジェクトを生成したり、同じフォント設定を何度も適用したりすると、オーバーヘッドが発生します。
  • 必要な場合にのみフォントを設定
    ウィジェットのフォントが変更されない限り、何度も setFont() を呼び出す必要はありません。
  • フォントオブジェクトの再利用
    一度作成した QFont オブジェクトを使い回すようにします。特にアプリケーション全体で共通のフォント設定を使う場合は、シングルトンパターンなどで管理することも有効です。


基本的な使用例

最も基本的な例として、いくつかのフォントファミリーを優先順位をつけて設定し、QLabel に適用するコードを示します。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QStringList> // フォントファミリーリストに QStringList を使用

int main(int argc, char *argv[])
{
    // QApplication インスタンスは QFont を使用する前に必要です
    QApplication app(argc, argv);

    QLabel label("Hello, Qt! こんにちは、Qt!");

    QFont font;
    QStringList preferredFamilies;

    // 優先順位の高い順にフォントファミリーを追加
    // 1. システムにインストールされている可能性が高い日本語フォント
    preferredFamilies << "游ゴシック" // Windows
                      << "Yu Gothic UI" // Windows (新しいバージョン)
                      << "メイリオ" // Windows
                      << "Meiryo UI" // Windows (新しいバージョン)
                      << "Hiragino Sans" // macOS (ヒラギノ角ゴシック)
                      << "Noto Sans CJK JP" // Linuxなど(オープンソースの多言語フォント)
                      // 2. 汎用的なフォント(どのOSでも代替として存在)
                      << "Arial"
                      << "sans-serif"; // 最終的なフォールバック(ゴシック系)

    font.setFamilies(preferredFamilies); // リストをフォントに設定
    font.setPointSize(18);               // フォントサイズを設定
    font.setBold(true);                  // 太字に設定

    label.setFont(font); // QLabel にフォントを適用
    label.show();

    return app.exec();
}

解説

  • label.setFont(font); で、設定したフォントを QLabel に適用します。
  • font.setFamilies(preferredFamilies); で、作成したリストを QFont オブジェクトに設定します。
  • preferredFamilies << "フォント名"; の形式で、優先したい順にフォント名を追加します。
  • QStringList preferredFamilies; で、フォントファミリー名を格納するためのリストを作成します。

OSごとに異なるフォントを設定する例

クロスプラットフォームアプリケーションでは、OSごとに最適なフォントを選択したい場合があります。その場合、プリプロセッサマクロを使用して条件分岐を行うことができます。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QStringList>

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

    QLabel label("クロスプラットフォーム対応のフォント設定の例");

    QFont font;
    QStringList families;

    // OSごとにフォントファミリーを条件分岐
#ifdef Q_OS_WIN // Windowsの場合
    families << "Meiryo UI" << "Yu Gothic UI" << "メイリオ" << "游ゴシック" << "Arial" << "sans-serif";
#elif defined(Q_OS_MAC) // macOSの場合
    families << "Hiragino Sans" << "ヒラギノ角ゴ ProN W3" << "Apple Color Emoji" << "Arial" << "sans-serif";
#elif defined(Q_OS_LINUX) // Linuxの場合
    families << "Noto Sans CJK JP" << "TakaoGothic" << "VL PGothic" << "DejaVu Sans" << "sans-serif";
#else // その他のOS (Qtがサポートする任意のOS)
    families << "sans-serif"; // 汎用フォント
#endif

    font.setFamilies(families);
    font.setPointSize(16);
    font.setItalic(true); // イタリック体に設定

    label.setFont(font);
    label.show();

    return app.exec();
}

解説

  • "Apple Color Emoji" のような絵文字フォントを macOS で指定することで、絵文字を含むテキストも正しく表示されるようにすることができます。
  • これにより、各OSでよりネイティブな見た目や、そのOSで一般的に利用可能なフォントを優先的に使用できます。
  • #ifdef Q_OS_WIN#elif defined(Q_OS_MAC)#elif defined(Q_OS_LINUX) のように、Qt が提供するプラットフォーム依存のマクロを使用してコンパイル時にコードを分岐させます。

QFont::setFamilies() はあくまで「要求」であり、実際にどのフォントが適用されたかはシステムに依存します。QFontInfo クラスを使用すると、実際に使用されたフォントの情報を取得できます。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QStringList>
#include <QFontInfo> // QFontInfo を使用

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

    QLabel label("フォント情報の確認");

    QFont font;
    QStringList families;
    families << "存在しないフォント名" // わざと存在しないフォント名
             << "Meiryo UI"
             << "Arial"
             << "sans-serif";

    font.setFamilies(families);
    font.setPointSize(20);
    font.setBold(true);

    label.setFont(font);
    label.show();

    // 実際に適用されたフォントの情報を取得
    QFontInfo fontInfo(label.font()); // QLabel に適用されたフォントから QFontInfo を作成

    qDebug() << "要求されたフォントファミリーリスト:" << font.families();
    qDebug() << "実際に使用されたフォントファミリー:" << fontInfo.family();
    qDebug() << "実際に使用されたフォントサイズ:" << fontInfo.pointSize();
    qDebug() << "実際に太字か:" << fontInfo.bold();
    qDebug() << "完全に一致したか:" << fontInfo.exactMatch(); // 設定したフォントと完全に一致したか

    return app.exec();
}

解説

  • fontInfo.exactMatch() は、QFont オブジェクトで要求したすべての属性(ファミリー、サイズ、太さなど)が完全に一致するフォントがシステムで見つかった場合に true を返します。
  • fontInfo.family() は、実際にQtがレンダリングに使用しているフォントのファミリー名を返します。
  • QFontInfo fontInfo(label.font()); のように、QWidget::font() などで取得した QFont オブジェクトから QFontInfo を作成します。

この例では、最初に存在しないフォント名を指定していますが、qDebug() の出力で実際にどのフォントが使用されたかを確認できます。これにより、意図しないフォントが適用されている場合のデバッグに役立ちます。



QFont::setFamily() を使用する

最も基本的な方法で、単一のフォントファミリーを設定します。

// 例: 単一のフォントファミリーを設定
QFont font;
font.setFamily("Arial"); // 単一のフォントファミリーを設定
font.setPointSize(12);
label->setFont(font);

特徴と使い分け

  • 用途
    • システムに確実に存在する標準フォント(例: "Arial", "Times New Roman")を使用する場合。
    • カスタムフォントを QFontDatabase::addApplicationFont() で登録した後、そのフォントファミリー名が確実に一意であると分かっている場合。
    • 厳密なフォールバック制御が必要なく、シンプルさを重視する場合。
  • フォールバックなし
    setFamilies() のように自動的なフォールバック(代替フォントの選択)は行われません。指定したフォントがシステムに存在しない場合、Qt はシステムが提供するデフォルトのフォント(例: "sans-serif" やOSの標準フォント)を使用します。
  • シンプルさ
    特定のフォントを確実に使いたい場合に最も単純な方法です。

Qt スタイルシート (QSS) を使用する

HTML/CSS のように、Qt ウィジェットの外観をスタイルシートで設定できます。フォントの設定も可能です。

// 例: スタイルシートでフォントを設定
QLabel *label = new QLabel("スタイルシートの例");
// スタイルシートでフォントを設定
label->setStyleSheet("QLabel { font-family: 'Yu Gothic UI', 'Meiryo UI', 'sans-serif'; font-size: 16pt; font-weight: bold; }");
// またはアプリケーション全体に適用する場合
// QApplication::setApplicationStateSheet("QLabel { font-family: ... }");

特徴と使い分け

  • 注意点
    スタイルシートでフォントを設定すると、QWidget::setFont() でプログラム的に設定したフォントよりも優先される場合があります。両方を併用する際は注意が必要です。
  • 用途
    • UI のテーマ設定やブランド統一を図る場合。
    • デザイナーが UI の外観を直接制御したい場合。
    • 特定のウィジェットタイプ(例: すべての QPushButton)に一貫したスタイルを適用したい場合。
  • 階層的
    親ウィジェットから子ウィジェットへのスタイルの継承を制御できます。
  • フォールバック
    font-family プロパティにカンマ区切りで複数のフォントファミリーを指定することで、setFamilies() と同様のフォールバック動作を実現できます。これは Qt スタイルシートの機能であり、内部的に setFamilies() と似た処理が行われます。
  • 柔軟な適用範囲
    特定のウィジェット、タイプ、クラス、またはアプリケーション全体に適用できます。
  • 宣言的
    UI の見た目をコードから分離して、より視覚的に管理できます。

QFontDatabase クラスは、システムにインストールされているフォントに関する情報を提供したり、アプリケーション固有のフォントをロードしたりするための機能を提供します。

a. システムフォントの利用可能性を確認する

#include <QFontDatabase>
#include <QDebug>

// 例: システムに特定のフォントがあるか確認
if (QFontDatabase::hasFamily("Yu Gothic UI")) {
    qDebug() << "Yu Gothic UI is available on this system.";
    QFont font;
    font.setFamily("Yu Gothic UI");
    // ... フォントを使用
} else {
    qDebug() << "Yu Gothic UI is NOT available.";
}

// 例: 利用可能なすべてのフォントファミリー名を取得
QStringList availableFamilies = QFontDatabase::families();
qDebug() << "Available font families:" << availableFamilies;

b. アプリケーション固有のフォントをロードする

外部のフォントファイル(.ttf, .otf など)をアプリケーションに含め、システムにインストールされていなくても使用できるようにする場合に非常に役立ちます。

#include <QFontDatabase>
#include <QApplication>
#include <QLabel>

// 例: カスタムフォントをロードして使用
int main(int argc, char *argv[])
{
    QApplication app(argc, argv);

    // カスタムフォントをリソースファイルから追加 (事前に .qrc ファイルで定義)
    // 例えば、:/fonts/MyCustomFont.ttf
    int fontId = QFontDatabase::addApplicationFont(":/fonts/MyCustomFont.ttf");
    QStringList fontFamilies;
    if (fontId != -1) {
        fontFamilies = QFontDatabase::applicationFontFamilies(fontId);
        qDebug() << "Loaded custom font families:" << fontFamilies;
    } else {
        qWarning() << "Failed to load custom font.";
    }

    QLabel label("カスタムフォントの例");
    QFont font;
    if (!fontFamilies.isEmpty()) {
        // ロードしたフォントのファミリー名を優先
        font.setFamilies(fontFamilies); // setFamilies() を使用する良い例
    } else {
        // ロードに失敗した場合の代替フォント
        font.setFamily("Arial");
    }
    font.setPointSize(24);
    label.setFont(font);
    label.show();

    return app.exec();
}