Qt開発者必見:QFont::stretch()のよくある落とし穴と効果的なフォント調整術

2025-06-06

QtプログラミングにおけるQFont::stretch()は、フォントの幅(横方向)の伸縮率を設定・取得するための関数です。

QFont::stretch() とは

QFont::stretch()は、QFontクラスのメンバー関数で、以下の2つの用途があります。

  1. フォントの伸縮率を取得する: int stretch() const 現在のフォントに設定されている伸縮率(整数値)を返します。

  2. フォントの伸縮率を設定する: void setStretch(int factor) フォントの伸縮率をfactorで指定された値に設定します。

伸縮率(Stretch Factor)について

stretchの値は、フォントの文字幅に対する比率を表します。標準の文字幅は 100 とされ、これを基準に伸縮率を調整します。

  • factorが100より大きい場合: 文字幅が拡大されます。例えば、200は非常に拡大された(UltraExpanded)フォントになります。
  • factorが100より小さい場合: 文字幅が縮小されます。例えば、50は非常に凝縮された(UltraCondensed)フォントになります。
  • factorが100の場合: 標準の文字幅です。伸縮は行われません(QFont::Unstretched)。

Qtでは、CSSのフォントの伸縮率の命名規則に合わせた以下のような定義済み定数も提供されています。

  • QFont::UltraExpanded (200)
  • QFont::ExtraExpanded (150)
  • QFont::Expanded (125)
  • QFont::SemiExpanded (112)
  • QFont::Unstretched (100)
  • QFont::SemiCondensed (87)
  • QFont::Condensed (75)
  • QFont::ExtraCondensed (62)
  • QFont::UltraCondensed (50)

使用例

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

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

    QLabel label;
    label.setText("Qt Font Stretch Example");

    QFont font = label.font(); // 現在のフォントを取得

    // フォントの幅を2倍に拡大 (UltraExpanded)
    font.setStretch(QFont::UltraExpanded); 
    // または font.setStretch(200);

    label.setFont(font); // フォントをラベルに設定
    label.show();

    return a.exec();
}

この例では、QLabelに表示されるテキストのフォントの幅を、通常の2倍に拡大しています。

  • 特定のフォントサイズでの制限: 一部の環境やQtのバージョンでは、特定の大きなフォントサイズ(例:48pt以上)でsetStretch()が期待通りに機能しないという報告もあります。その場合は、QPaintersetTransform()を使って描画時にスケール変換を適用するなどの代替手段を検討することもできます。
  • Qt 5.8以降のQFont::AnyStretch: Qt 5.8以降では、QFont::AnyStretch (0)という値も追加されており、これは他のQFontプロパティを使ってマッチした任意のストレッチを受け入れることを意味します。
  • 他のフォント設定との関連: stretchはフォントの幅に影響を与えますが、文字間隔(letter spacing)や単語間隔(word spacing)とは異なります。これらはそれぞれsetLetterSpacing()setWordSpacing()で個別に設定できます。
  • 実際の表示: QFont::stretch()で設定した伸縮率は、基となるフォントがその伸縮率をサポートしているか、またはQtのレンダリングエンジンがその伸縮率を適用できるかに依存します。必ずしも指定した通りの伸縮が保証されるわけではありません。特に、ビットマップフォントの場合、文字のサイズは変わらず文字間のスペースが広がるだけになることがあります。


エラー:設定したストレッチが適用されない(フォントの幅が変わらない)

これは最もよくある問題です。setStretch() を呼び出しても、見た目に変化がないことがあります。

考えられる原因とトラブルシューティング

  • 原因 1-4: 値が極端すぎる、または効果が目立たない

    • 説明
      stretch の値が 100 (Unstretched) に近い場合、見た目の変化は非常に小さいです。また、極端な値 (例: 20) を設定しても、フォントがそれに対応できない場合は効果が出ません。
    • トラブルシューティング
      • QFont::UltraCondensed (50) や QFont::UltraExpanded (200) のような極端な値で試して、効果が全くないのか、それとも小さいだけなのかを確認します。
  • 原因 1-3: UI 要素がフォントの変更を更新していない

    • 説明
      setFont() を呼び出した後、UI 要素が再描画されていない可能性があります。特に、ウィジェットのサイズが固定されている場合などです。
    • トラブルシューティング
      • update()repaint() を呼び出して、ウィジェットの再描画を強制します。
      • レイアウトを使用している場合は、レイアウトが更新されることでウィジェットのサイズが調整され、フォントの変更が反映されやすくなります。
      • adjustSize() を呼び出して、ウィジェットのサイズをコンテンツに合わせて調整してみます。
  • 原因 1-2: Qt のレンダリングエンジンの限界

    • 説明
      Qt はフォントのレンダリングをシステムに依存する場合があり、特定のOSやQtのバージョン、あるいはバックエンドのグラフィックライブラリの制限により、stretch が完全にサポートされないことがあります。
    • トラブルシューティング
      • Qt のバージョンアップ
        最新の Qt バージョンにアップグレードすることで、レンダリングの問題が改善される場合があります。
      • OS の確認
        異なる OS (Windows, macOS, Linux) で同じコードを試して、OS固有の問題かどうかを確認します。
      • フォントエンジン(Fontconfig など)の設定
        Linux 環境では、Fontconfig の設定がフォントの選択やレンダリングに影響を与えることがあります。
    • 説明
      全てのフォントが、指定されたあらゆる伸縮率をサポートしているわけではありません。特に、ビットマップフォントや、デザイン時に特定の幅しか持たないように作られたフォントでは、stretch() が無視されるか、期待通りにレンダリングされないことがあります。
    • トラブルシューティング
      • 別のフォントを試す
        Arial, Helvetica, Noto Sans CJK など、様々なウェイトや幅を持つように設計されたフォント(OpenType/TrueType などのアウトラインフォント)で試してみてください。
      • フォントの情報確認
        フォントビューアなどで、そのフォントが「Condensed」「Expanded」などのファミリを持っているか確認します。
      • フォントフォールバックの確認
        システムが指定したフォントを見つけられず、代替フォント(フォールバック)を使用している可能性があります。その代替フォントが stretch をサポートしていないかもしれません。QFontInfo を使用して、実際に使用されているフォントの情報を確認してください。

エラー:文字間隔が不自然になる(文字が重なる、または離れすぎる)

stretch() は文字自体の幅を調整しますが、必ずしも完璧なカーニング(文字間隔調整)を提供するわけではありません。

考えられる原因とトラブルシューティング

  • 原因 2-2: アンチエイリアシング/レンダリングの問題

    • 説明
      低解像度ディスプレイや特定のレンダリング設定において、文字の境界がぼやけたり、重なって見えたりすることがあります。
    • トラブルシューティング
      • QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); など、DPIスケーリング関連の設定を確認します。
      • QPainter::setRenderHint(QPainter::Antialiasing); を使用してアンチエイリアシングが有効になっていることを確認します。
  • 原因 2-1: フォントのカーニング情報が不足している

    • 説明
      多くのフォントは特定のウェイト(例:Regular, Bold)に対してカーニング情報を持っていますが、極端にストレッチされた状態でのカーニングは考慮されていない場合があります。
    • トラブルシューティング
      • QFont::setLetterSpacing() を併用する
        QFont::stretch() で全体的な幅を調整した後、QFont::setLetterSpacing(QFont::AbsoluteSpacing, value) を使って手動で文字間隔を微調整することを検討してください。ただし、これはグローバルな設定なので、全ての文字間隔に影響します。
      • 別のフォントを試す
        より高品質なフォント、または可変フォント(Variable Fonts)を検討します。可変フォントは、様々な軸(ウェイト、幅など)に沿ってフォントを調整でき、より洗練されたレンダリングが期待できます。

エラー:パフォーマンスの問題(特に大量のテキストやアニメーションで)

stretch() の適用自体が直接パフォーマンスに大きな影響を与えることは稀ですが、フォントの再レンダリングやレイアウトの再計算が頻繁に行われる場合、問題となることがあります。

考えられる原因とトラブルシューティング

  • 原因 3-1: 頻繁なフォント変更
    • 説明
      アニメーションなどでフォントの stretch 値を毎フレーム変更している場合、その都度フォントの再計算や再描画が発生し、負荷が高くなります。
    • トラブルシューティング
      • キャッシュの利用
        可能な場合は、変更後の QFont オブジェクトをキャッシュして使い回します。
      • QTextLayout の活用
        大量のテキストを表示する場合、QTextLayout を使用してテキストのレイアウトを最適化することを検討します。QTextLayout は、テキストブロックのレイアウト計算を効率的に行います。
      • 描画の最適化
        QPainter で直接描画している場合、QPainter::drawText() の呼び出し回数を減らす、あるいは QGraphicsScene を使用してアイテムベースの描画に切り替えることを検討します。

エラー:プラットフォーム間の表示の不一致

同じ stretch 値を設定しても、Windows、macOS、Linux で見た目が異なることがあります。

考えられる原因とトラブルシューティング

  • 原因 4-1: システムフォントレンダリングの違い
    • 説明
      各 OS は独自のフォントレンダリングエンジンとフォントの代替(フォールバック)メカニズムを持っています。これにより、同じフォントファミリが指定されていても、実際に使用されるフォントやそのレンダリング方法が異なる可能性があります。
    • トラブルシューティング
      • Web フォントのような組み込みフォントの利用
        アプリケーションに特定のフォントファイル(例:qrc リソースとして)を組み込み、それを使用することで、プラットフォーム間の依存性を減らすことができます。
      • QFontDatabase の活用
        QFontDatabase::addApplicationFont() を使用してフォントを追加し、QFontDatabase::applicationFontFamilies() で利用可能なフォントファミリを確認します。
      • デザインレビュー
        各プラットフォームで実際にテストを行い、許容できる範囲の差異かどうかを判断します。必要に応じて、プラットフォームごとにフォント設定を調整します。


例1: QLabel のテキストの幅を調整する基本的な例

この例では、QLabel ウィジェットに表示されるテキストのフォントの伸縮率を変更します。

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

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

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

    // 通常のフォント
    QLabel *normalLabel = new QLabel("Normal Text");
    QFont normalFont = normalLabel->font();
    normalFont.setPointSize(24);
    normalLabel->setFont(normalFont);
    layout->addWidget(normalLabel);

    // 縮小されたフォント (Condensed)
    QLabel *condensedLabel = new QLabel("Condensed Text");
    QFont condensedFont = condensedLabel->font();
    condensedFont.setPointSize(24);
    condensedFont.setStretch(QFont::Condensed); // QFont::Condensed = 75
    condensedLabel->setFont(condensedFont);
    layout->addWidget(condensedLabel);

    // さらに縮小されたフォント (UltraCondensed)
    QLabel *ultraCondensedLabel = new QLabel("Ultra Condensed Text");
    QFont ultraCondensedFont = ultraCondensedLabel->font();
    ultraCondensedFont.setPointSize(24);
    ultraCondensedFont.setStretch(QFont::UltraCondensed); // QFont::UltraCondensed = 50
    ultraCondensedLabel->setFont(ultraCondensedFont);
    layout->addWidget(ultraCondensedLabel);

    // 拡大されたフォント (Expanded)
    QLabel *expandedLabel = new QLabel("Expanded Text");
    QFont expandedFont = expandedLabel->font();
    expandedFont.setPointSize(24);
    expandedFont.setStretch(QFont::Expanded); // QFont::Expanded = 125
    expandedLabel->setFont(expandedFont);
    layout->addWidget(expandedLabel);

    // さらに拡大されたフォント (UltraExpanded)
    QLabel *ultraExpandedLabel = new QLabel("Ultra Expanded Text");
    QFont ultraExpandedFont = ultraExpandedLabel->font();
    ultraExpandedFont.setPointSize(24);
    ultraExpandedFont.setStretch(QFont::UltraExpanded); // QFont::UltraExpanded = 200
    ultraExpandedLabel->setFont(ultraExpandedFont);
    layout->addWidget(ultraExpandedLabel);

    window.setWindowTitle("QFont::stretch() Example");
    window.resize(400, 300);
    window.show();

    return app.exec();
}

解説

  1. QLabel に対して QFont オブジェクトを作成またはコピーします。
  2. QFont::setStretch() メソッドに、QFont::Stretch 列挙型で定義されている定数(QFont::Condensed, QFont::Expanded など)または直接整数値(50, 100, 200 など)を渡して、伸縮率を設定します。
    • 100 が標準の幅を表します。
    • 100 より小さい値は文字を縮小します。
    • 100 より大きい値は文字を拡大します。
  3. 変更した QFont オブジェクトを QLabel::setFont() でウィジェットに適用します。

例2: スライダーで動的にフォントのストレッチを調整する例

この例では、QSlider を使ってリアルタイムでフォントの伸縮率を変更できるようにします。

#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QSlider>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFont>

class StretchDemo : public QWidget {
    Q_OBJECT // シグナル/スロットを使用する場合に必要

public:
    StretchDemo(QWidget *parent = nullptr) : QWidget(parent) {
        QVBoxLayout *mainLayout = new QVBoxLayout(this);

        // 表示するテキスト
        m_label = new QLabel("Sample Text for Stretch Demo");
        m_label->setAlignment(Qt::AlignCenter);
        m_font = m_label->font();
        m_font.setPointSize(36); // 大きめのフォントサイズ
        m_label->setFont(m_font);
        mainLayout->addWidget(m_label);

        // スライダーの設定
        m_slider = new QSlider(Qt::Horizontal);
        m_slider->setRange(50, 200); // ストレッチの範囲 (UltraCondensed から UltraExpanded)
        m_slider->setValue(100); // 初期値はUnstretched
        m_slider->setTickPosition(QSlider::TicksBoth);
        m_slider->setTickInterval(25);
        mainLayout->addWidget(m_slider);

        // 現在のストレッチ値を表示するラベル
        m_stretchValueLabel = new QLabel("Stretch: 100");
        m_stretchValueLabel->setAlignment(Qt::AlignCenter);
        mainLayout->addWidget(m_stretchValueLabel);

        // スライダーの値を変更したときにフォントを更新する
        connect(m_slider, &QSlider::valueChanged, this, &StretchDemo::onSliderValueChanged);

        setWindowTitle("Dynamic QFont::stretch() Demo");
        resize(600, 300);
    }

private slots:
    void onSliderValueChanged(int value) {
        m_font.setStretch(value);
        m_label->setFont(m_font);
        m_stretchValueLabel->setText(QString("Stretch: %1").arg(value));
    }

private:
    QLabel *m_label;
    QFont m_font;
    QSlider *m_slider;
    QLabel *m_stretchValueLabel;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    StretchDemo demo;
    demo.show();
    return app.exec();
}

#include "main.moc" // mocツールで生成されるファイル

解説

  1. StretchDemo クラスを QWidget から継承し、UI を構築します。
  2. QLabel に初期フォントを設定します。
  3. QSlider を作成し、setRange(50, 200) でスライダーの最小値と最大値を設定します。これは QFont::UltraCondensed から QFont::UltraExpanded までの範囲に対応します。
  4. スライダーの valueChanged シグナルを onSliderValueChanged スロットに接続します。
  5. onSliderValueChanged スロット内で、スライダーの現在の値を取得し、それを m_font.setStretch(value) でフォントに適用します。
  6. 最後に、更新されたフォントを m_label->setFont(m_font)QLabel に設定し、m_stretchValueLabel で現在のストレッチ値を表示します。

ビルド時の注意点

このコードはシグナル/スロットを使用しているため、main.cpp などのソースファイル名の末尾に .moc ファイルを含める必要があります。

  • qmake を使用する場合 (Qt 5)
    .pro ファイルに以下を追加します。

    QT += widgets
    SOURCES += main.cpp
    HEADERS += main.h # もしクラスを別のヘッダーファイルに分割している場合
    

    qmake は .pro ファイルから自動的に moc ファイルの生成とコンパイルを処理します。上記の例では、main.cpp の中にクラス定義を直接書いているため、通常は main.moc を手動でインクルードする必要はありません(コンパイラが自動的に行うか、ビルドシステムが処理します)。しかし、慣例的にクラスをヘッダーファイル (.h) に定義する場合は、そのヘッダーファイルをmoc処理する必要があります。

  • CMake を使用する場合
    CMakeLists.txt に以下を追加します。

    cmake_minimum_required(VERSION 3.14)
    project(StretchDemo LANGUAGES CXX)
    
    set(CMAKE_AUTOUIC ON)
    set(CMAKE_AUTOMOC ON)
    set(CMAKE_AUTORCC ON)
    
    find_package(Qt6 COMPONENTS Widgets REQUIRED) # Qt5 の場合は Qt5 Widgets
    qt_standard_project_setup(StretchDemo)
    
    add_executable(StretchDemo main.cpp)
    target_link_libraries(StretchDemo PRIVATE Qt6::Widgets) # Qt5 の場合は Qt5::Widgets
    

    CMAKE_AUTOMOC ON を設定することで、main.moc のインクルードやmocファイルの生成が自動的に行われます。

例3: QML で font.stretch を使用する場合(QML 開発者向け)

QML では、Text 要素の font プロパティを通じて stretch を直接設定することはできません。QFontstretch プロパティは QML には直接公開されていません。そのため、C++ のヘルパークラスを介してフォントを操作する必要があります。

main.cpp (C++ ヘルパークラスの定義)

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext> // QQmlContext をインクルード
#include <QFont>
#include <QObject> // QObject をインクルード

class FontHelper : public QObject {
    Q_OBJECT
public:
    explicit FontHelper(QObject *parent = nullptr) : QObject(parent) {}

    Q_INVOKABLE QFont changeStretchFont(const QFont &font, int factor) {
        QFont fn = font; // 既存のフォントをコピー
        fn.setStretch(factor); // stretch を設定
        return fn; // 新しいフォントを返す
    }
};

int main(int argc, char *argv[]) {
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    // ヘルパークラスのインスタンスを作成し、QMLに公開する
    FontHelper fontHelper;
    engine.rootContext()->setContextProperty("fontHelper", &fontHelper);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 // QSlider のために必要

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("QML Font Stretch Example")

    ColumnLayout {
        anchors.fill: parent
        anchors.margins: 20

        Text {
            id: myText
            text: "Hello QML Font Stretch!"
            font.family: "Arial" // 例としてArialを指定
            font.pointSize: 48
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter
            Layout.fillWidth: true
            Layout.fillHeight: true

            // コンポーネントが完了したときに初期ストレッチを設定
            Component.onCompleted: {
                myText.font = fontHelper.changeStretchFont(myText.font, 100); // 初期値はUnstretched
            }
        }

        Slider {
            id: stretchSlider
            from: 50
            to: 200
            value: 100 // 初期値
            onValueChanged: {
                // スライダーの値が変更されたら、C++のヘルパー関数を使ってフォントを更新
                myText.font = fontHelper.changeStretchFont(myText.font, stretchSlider.value);
            }
        }

        Text {
            text: "Stretch Factor: " + stretchSlider.value
            font.pointSize: 18
            horizontalAlignment: Text.AlignHCenter
            Layout.fillWidth: true
        }
    }
}

解説

  1. C++ ヘルパークラス (FontHelper):
    • QObject を継承し、QML から呼び出せる Q_INVOKABLE メソッド changeStretchFont を定義します。
    • このメソッドは既存の QFont と新しい factor を受け取り、setStretch() を適用した新しい QFont を返します。
  2. main.cpp:
    • FontHelper のインスタンスを作成し、QQmlApplicationEngine::rootContext()->setContextProperty() を使って "fontHelper" という名前で QML 環境に公開します。
  3. main.qml:
    • Text 要素の font プロパティは直接 stretch を持たないため、fontHelper.changeStretchFont() を呼び出して、新しい QFont オブジェクトを myText.font に代入します。
    • Slider を使って stretch の値を動的に変更できるようにします。

この QML の例は、QFont::stretch() が QML に直接公開されていない場合の一般的な回避策を示しています。



ここでは、QFont::stretch() が使えない場合や、別の目的でテキストの幅や見た目を調整したい場合に検討できる代替方法をいくつか紹介します。

QFont::setLetterSpacing() を使用する

QFont::stretch() は文字自体の幅を伸縮させるのに対し、setLetterSpacing()文字と文字の間の間隔を調整します。文字そのものの形は変わりませんが、テキストブロック全体の幅を広げたり狭めたりする効果があります。

  • 用途
    • 文字の形をそのままに、テキストブロックの幅を調整したい場合。
    • 読みやすさのために文字間隔を微調整したい場合。
    • タイトルなどで文字を詰めて見せたい、あるいはゆったりと見せたい場合。
  • メソッド
    void QFont::setLetterSpacing(SpacingType type, qreal percentOrValue)
    • SpacingType:
      • QFont::PercentageSpacing: 現在のフォントサイズに対するパーセンテージで間隔を調整(例: 100 で標準、150 で1.5倍の間隔)。
      • QFont::AbsoluteSpacing: 絶対ピクセル値で間隔を調整。


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

int main(int argc, char *argv[]) {
    QApplication app(argc; argv);
    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *normalLabel = new QLabel("Normal Letter Spacing");
    QFont normalFont = normalLabel->font();
    normalFont.setPointSize(24);
    normalLabel->setFont(normalFont);
    layout->addWidget(normalLabel);

    // 文字間隔を広げる (50% 広げる)
    QLabel *wideSpacingLabel = new QLabel("Wide Letter Spacing");
    QFont wideSpacingFont = wideSpacingLabel->font();
    wideSpacingFont.setPointSize(24);
    wideSpacingFont.setLetterSpacing(QFont::PercentageSpacing, 150); // 1.5倍の間隔
    wideSpacingLabel->setFont(wideSpacingFont);
    layout->addWidget(wideSpacingLabel);

    // 文字間隔を狭める (75% の間隔)
    QLabel *tightSpacingLabel = new QLabel("Tight Letter Spacing");
    QFont tightSpacingFont = tightSpacingLabel->font();
    tightSpacingFont.setPointSize(24);
    tightSpacingFont.setLetterSpacing(QFont::PercentageSpacing, 75); // 0.75倍の間隔
    tightSpacingLabel->setFont(tightSpacingFont);
    layout->addWidget(tightSpacingLabel);

    window.setWindowTitle("Letter Spacing Example");
    window.resize(500, 300);
    window.show();

    return app.exec();
}

QFont::setWeight() でより細い/太いフォントファミリーを選択する

フォントには「Regular」「Bold」「Light」「Semi-Bold」などの「ウェイト(太さ)」がありますが、一部のフォントファミリーには、これらに加えて「Condensed」「Expanded」といった「幅(width)」のバリエーションが提供されている場合があります。

  • より直接的な方法としては、QFont のコンストラクタや setFamily() で、明示的に幅のバリエーションを持つフォントファミリー名を指定することです。
  • QFont::setWeight() は太さを設定しますが、フォントファミリーによっては、太さの変化に伴って幅も暗黙的に変わるものがあります。


例えば、「Arial」フォントには「Arial Narrow」という幅の狭いバリエーションがあります。

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

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *arialLabel = new QLabel("Arial Regular");
    QFont arialFont("Arial", 24); // Arialの標準
    arialLabel->setFont(arialFont);
    layout->addWidget(arialLabel);

    QLabel *arialNarrowLabel = new QLabel("Arial Narrow");
    QFont arialNarrowFont("Arial Narrow", 24); // Arial Narrow (幅が狭い)
    arialNarrowLabel->setFont(arialNarrowFont);
    layout->addWidget(arialNarrowLabel);

    // ヒント: フォントに'Condensed'や'Expanded'のサブファミリがあれば、それらを試す
    // 例: "MyFont Condensed", "MyFont Expanded"
    // ただし、フォントシステムがそれらを別々のフォントとして認識している必要あり
    QLabel *customFontVariantLabel = new QLabel("Custom Font Variant (if available)");
    QFont customFontVariant("Roboto Condensed", 24); // 例: Roboto Condensed
    customFontVariantLabel->setFont(customFontVariant);
    layout->addWidget(customFontVariantLabel);


    window.setWindowTitle("Font Family Variant Example");
    window.resize(500, 300);
    window.show();

    return app.exec();
}

利点
フォントデザイナーが意図した、より自然な幅のバリエーションを使用できます。 欠点: 全てのフォントにこのようなバリエーションがあるわけではありません。利用可能なフォントに依存します。

QPainter::scale() を使用して描画時にスケーリングする

これは、テキストの描画時に描画コンテキスト自体をスケールする方法です。QFont オブジェクト自体は変更せず、描画される結果が伸縮されます。

  • 注意点
    • テキストが拡大・縮小されるため、ピクセルパーフェクトな表示が必要な場合は、アンチエイリアシングの品質に注意が必要です。特に極端な拡大・縮小では、文字がギザギザになったり、ぼやけたりする可能性があります。
    • テキストが歪む可能性があります(幅方向のみスケールすると、縦横比が崩れるため)。縦横比を維持して全体を拡大縮小する方が自然に見えることが多いです。
  • 用途
    • カスタム描画ウィジェット (paintEvent をオーバーライドする QWidgetQGraphicsItem) でテキストを描画する場合。
    • テキストだけでなく、関連する他の描画要素も一括して伸縮させたい場合。
    • QFont::stretch() がうまく機能しない場合の最終手段。


#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QFont>

class ScaledTextWidget : public QWidget {
public:
    ScaledTextWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("QPainter::scale() Text Example");
        resize(600, 200);
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing); // アンチエイリアシングを有効にする

        QFont font("Arial", 40);
        painter.setFont(font);

        // 元のテキスト
        painter.setPen(Qt::black);
        painter.drawText(20, 50, "Normal Text");

        // 幅方向に1.5倍にスケールしたテキスト
        painter.save(); // 現在の変換行列を保存
        painter.translate(20, 120); // 描画開始位置を移動
        painter.scale(1.5, 1.0); // 幅を1.5倍、高さを1.0倍にスケール
        painter.setPen(Qt::blue);
        painter.drawText(0, 0, "Wide Text (Scaled)"); // drawTextの座標はスケール後の座標系になる
        painter.restore(); // 変換行列を元に戻す

        // 幅方向に0.7倍にスケールしたテキスト
        painter.save();
        painter.translate(20, 170);
        painter.scale(0.7, 1.0); // 幅を0.7倍、高さを1.0倍にスケール
        painter.setPen(Qt::red);
        painter.drawText(0, 0, "Condensed Text (Scaled)");
        painter.restore();
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    ScaledTextWidget widget;
    widget.show();
    return app.exec();
}

解説

  1. QPainter::save()QPainter::restore() で変換行列の状態を管理します。
  2. QPainter::translate() で描画の原点を移動し、テキストの位置を調整します。
  3. QPainter::scale(sx, sy) で、X軸方向 (sx) とY軸方向 (sy) にスケーリングを適用します。ここでは、幅だけを変更するため sy1.0 にしています。
  4. drawText() の座標は、scale() 後の新しい座標系で指定します。

フォントファイルを動的にロードする (QML の場合など)

特定のストレッチを持つフォントファミリーがシステムにインストールされていない場合でも、アプリケーションにフォントファイルをバンドルし、実行時にロードすることで使用できます。

  • QML でのロード
    FontLoader 要素
  • C++ でのロード
    QFontDatabase::addApplicationFont()

例 (C++)

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QFontDatabase> // QFontDatabase をインクルード
#include <QVBoxLayout>
#include <QWidget>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    // (必要であれば) フォントファイルをリソースに含める:
    // .proファイル: RESOURCES += myfonts.qrc
    // myfonts.qrc: <RCC><qresource prefix="/fonts"><file>path/to/MyFont-Condensed.ttf</file></qresource></RCC>

    // フォントファイルをロード
    int fontId = QFontDatabase::addApplicationFont(":/fonts/MyFont-Condensed.ttf"); // リソースパスを指定
    QStringList fontFamilies = QFontDatabase::applicationFontFamilies(fontId);

    if (!fontFamilies.isEmpty()) {
        QLabel *label = new QLabel("Custom Condensed Font");
        QFont customFont(fontFamilies.first(), 24); // ロードしたフォントファミリーを使用
        label->setFont(customFont);
        layout->addWidget(label);
    } else {
        QLabel *errorLabel = new QLabel("Failed to load custom font or font family not found.");
        layout->addWidget(errorLabel);
    }

    window.setWindowTitle("Load Custom Font Example");
    window.resize(400, 200);
    window.show();

    return app.exec();
}

例 (QML)

import QtQuick 2.15
import QtQuick.Window 2.15

Window {
    visible: true
    width: 400
    height: 200
    title: qsTr("QML FontLoader Example")

    // フォントファイルをロード
    FontLoader {
        id: myCondensedFont
        source: "qrc:/fonts/MyFont-Condensed.ttf" // リソースパスを指定
    }

    Text {
        text: "Text with Custom Condensed Font"
        font.family: myCondensedFont.name // ロードされたフォントの名前を使用
        font.pointSize: 24
        horizontalAlignment: Text.AlignHCenter
        verticalAlignment: Text.AlignVCenter
        anchors.centerIn: parent
    }
}

利点
アプリケーションが実行される環境に依存せず、特定のフォントのバリエーションを確実に使用できます。 欠点: アプリケーションのバイナリサイズが増加します。ライセンスにも注意が必要です。

可変フォント(Variable Fonts)の使用(Qt 6 以降でサポート強化)

可変フォントは、複数の「軸」(ウェイト、幅、傾きなど)に沿って連続的に変化するフォントです。これにより、単一のフォントファイルで、非常に多様なスタイルを表現できます。

  • QFont::setVariationAxis() を使用して、可変フォントの特定の軸(例: wdth (width), wght (weight))の値を設定できます。
  • Qt 6 からは、可変フォントのサポートが強化されており、QFont でこれらの軸をより細かく制御できるようになっています。

例 (概念的なコード、具体的なフォントと軸名に依存)

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

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QWidget window;
    QVBoxLayout *layout = new QVBoxLayout(&window);

    QLabel *label = new QLabel("Variable Font Demo");
    QFont font("Path To Your Variable Font.ttf", 36); // 可変フォントのパスまたはインストールされた名前

    // 可変フォントの「幅」軸 ('wdth') を設定
    // 軸の名前と値の範囲はフォントによって異なる
    // 一般的な「幅」軸は 'wdth'、値は 0-1000 など
    font.setVariationAxis("wdth", 800); // 800は例の値、フォントによる
    font.setVariationAxis("wght", 600); // ウェイト軸も調整可能

    label->setFont(font);
    layout->addWidget(label);

    window.setWindowTitle("Variable Font Example (Qt 6)");
    window.resize(600, 300);
    window.show();

    return app.exec();
}

利点

  • 補間により、滑らかなトランジションが可能。
  • ファイルサイズを抑えつつ、多様な視覚的効果を実現。
  • 単一のフォントファイルで非常に柔軟なフォントのスタイル調整が可能。

欠点

  • 使用する可変フォントの軸の名前や値の範囲を理解する必要がある。
  • 全てのフォントが可変フォントではない。

QFont::stretch() が最良の選択肢でない場合、以下の点を考慮して代替方法を選びます。

  • より高度な柔軟性と最適化されたファイルサイズが必要か? → 可変フォント (QFont::setVariationAxis())
  • 特定のフォントファイルをアプリケーションにバンドルしたいか?QFontDatabase::addApplicationFont() / FontLoader
  • カスタム描画でテキスト以外も伸縮させたいか? stretch() が機能しないか?QPainter::scale()
  • フォントファミリーに既存の幅バリエーションがあるか? → 特定のフォントファミリー名を指定
  • 文字間のスペースを調整したいだけか?QFont::setLetterSpacing()