QFont::letterSpacing()

2025-06-06

文字間隔とは、テキスト中の各文字と次の文字との間に挿入される追加のスペースのことです。この値を調整することで、テキストの見た目をより引き締まったり、ゆったりさせたりすることができます。

QFont::letterSpacing() の使い方

QFont::letterSpacing() には、主に以下の2つの使い方があります。

  1. 現在の文字間隔の値を取得する: qreal QFont::letterSpacing() const この関数は、現在設定されている文字間隔の値をqreal型(浮動小数点数)で返します。

  2. 文字間隔を設定する: void QFont::setLetterSpacing(QFont::SpacingType type, qreal spacing) この関数は、フォントの文字間隔を設定します。

    • type: 文字間隔の計算方法を指定します。以下の2つのタイプがあります。
      • QFont::PercentageSpacing: spacingの値は、文字の幅に対するパーセンテージで指定されます。例えば、100は通常の文字間隔、200は通常の2倍の文字間隔となります。
      • QFont::AbsoluteSpacing: spacingの値は、ピクセル単位で指定されます。正の値は文字間隔を広げ、負の値は文字間隔を狭めます。
    • spacing: 文字間隔の具体的な値です。typeによって解釈が変わります。

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

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

    QLabel label;
    QFont font("Arial", 24); // Arialフォント、サイズ24ポイント

    // 1. パーセンテージで文字間隔を広げる (通常の150%)
    font.setLetterSpacing(QFont::PercentageSpacing, 150);
    label.setFont(font);
    label.setText("Qt での文字間隔");
    label.show();

    QLabel label2;
    QFont font2("Arial", 24);

    // 2. ピクセルで文字間隔を狭める (-2ピクセル)
    font2.setLetterSpacing(QFont::AbsoluteSpacing, -2);
    label2.setFont(font2);
    label2.setText("Qt での文字間隔");
    label2.move(0, 50); // 位置をずらして表示
    label2.show();

    // 現在の文字間隔の値を取得
    qreal currentSpacing = font.letterSpacing();
    qreal currentSpacing2 = font2.letterSpacing();
    qDebug() << "Label 1 letter spacing (percentage):" << currentSpacing;
    qDebug() << "Label 2 letter spacing (absolute):" << currentSpacing2;


    return app.exec();
}

この例では、2つのQLabelを作成し、それぞれ異なる方法で文字間隔を設定しています。一つはパーセンテージで文字間隔を広げ、もう一つはピクセルで文字間隔を狭めています。

  • 文字間隔の調整は、フォントの種類やサイズ、表示されるコンテキストによって最適な値が異なります。
  • QFont::SpacingTypeによって、spacing引数の解釈が変わる点に注意が必要です。
  • QFont::letterSpacing()は、主にテキストの視覚的な調整に役立ちます。


    • 原因: QFontオブジェクトをsetLetterSpacing()で変更した後に、そのQFontオブジェクトをウィジェット(例: QLabelQPushButtonなど)に再設定していない場合。
    • 対策: QFontオブジェクトの変更後には、必ずそのフォントを使用するウィジェットに対してQWidget::setFont(font)のようにフォントを再設定してください。
      QFont font = label->font(); // 現在のフォントを取得
      font.setLetterSpacing(QFont::AbsoluteSpacing, 5); // 文字間隔を設定
      label->setFont(font); // フォントをラベルに再設定
      
    • 原因: スタイルシート(CSS)を使用している場合、スタイルシートのフォント設定がQFontの設定を上書きしている可能性があります。
    • 対策: スタイルシートでfont-familyfont-sizeなど、フォントに関する設定を行っている場合は、letter-spacingプロパティもスタイルシートで指定することを検討してください。ただし、QtのスタイルシートはすべてのCSSプロパティをサポートしているわけではないため、letter-spacingが効かない場合もあります。その場合は、C++コードでsetLetterSpacingを使用する必要があります。
  1. 意図しない文字の重なりや、広すぎる間隔

    • 原因: QFont::AbsoluteSpacingで負の値を設定しすぎると、文字が重なって判読不能になることがあります。また、正の値を大きくしすぎると、文字間隔が不自然に広がりすぎることもあります。
    • 対策:
      • 適切なspacing値を試行錯誤して見つける必要があります。フォントの種類やサイズによって最適な値は異なります。
      • 特にAbsoluteSpacingでは、文字の平均的な幅を考慮して値を設定することが重要です。QFontMetricsを使って文字の幅を測定することも検討してください。
  2. QFontMetricsとの挙動の不一致

    • 原因: QFontMetricsでテキストのサイズを計算した場合と、実際に描画されたテキストの見た目が異なることがあります。QFontMetricsは、フォントの基本的なメトリクスに基づいて計算するため、letterSpacingなどの描画時の微調整が完全に反映されない場合があります。
    • 対策: テキストを正確な領域に収めたい場合は、QPainter::boundingRect()を使用するなど、実際に描画されるテキストの境界ボックスを取得する関数を利用することが推奨されます。


基本的な使用例

最も基本的な例は、QLabel などのウィジェットに表示されるテキストの文字間隔を変更することです。

#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QVBoxLayout> // レイアウトのために追加
#include <QWidget>     // 親ウィジェットのために追加

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

    // メインウィンドウを作成
    QWidget *window = new QWidget;
    QVBoxLayout *layout = new QVBoxLayout(window);

    // -----------------------------------------------------
    // 例1: デフォルトの文字間隔 (変更なし)
    QLabel *label1 = new QLabel("Qt での文字間隔の例 (デフォルト)");
    QFont font1("メイリオ", 18); // Windowsならメイリオ、macOSならヒラギノ角ゴなど
    label1->setFont(font1);
    layout->addWidget(label1);

    // -----------------------------------------------------
    // 例2: 絶対値 (ピクセル) で文字間隔を広げる
    QLabel *label2 = new QLabel("Qt での文字間隔の例 (広げる)");
    QFont font2 = font1; // font1からコピー
    // 5ピクセル文字間隔を広げる
    font2.setLetterSpacing(QFont::AbsoluteSpacing, 5.0);
    label2->setFont(font2);
    layout->addWidget(label2);

    // -----------------------------------------------------
    // 例3: 絶対値 (ピクセル) で文字間隔を狭める
    QLabel *label3 = new QLabel("Qt での文字間隔の例 (狭める)");
    QFont font3 = font1; // font1からコピー
    // 2ピクセル文字間隔を狭める (文字が重なる可能性あり)
    font3.setLetterSpacing(QFont::AbsoluteSpacing, -2.0);
    label3->setFont(font3);
    layout->addWidget(label3);

    // -----------------------------------------------------
    // 例4: パーセンテージで文字間隔を広げる
    QLabel *label4 = new QLabel("Qt での文字間隔の例 (パーセンテージで広げる)");
    QFont font4 = font1; // font1からコピー
    // デフォルトの文字幅の150% (つまり50%追加)
    font4.setLetterSpacing(QFont::PercentageSpacing, 150.0);
    label4->setFont(font4);
    layout->addWidget(label4);

    // -----------------------------------------------------
    // 例5: 現在の文字間隔を取得
    // font2の現在の文字間隔を取得
    qreal currentSpacing = font2.letterSpacing();
    QLabel *label5 = new QLabel(QString("現在の文字間隔 (絶対値): %1").arg(currentSpacing));
    label5->setFont(font1); // フォントはデフォルトでOK
    layout->addWidget(label5);

    window->setWindowTitle("QFont::letterSpacing() 例");
    window->show();

    return app.exec();
}

解説

  1. #include <QApplication> など: Qtアプリケーションの実行に必要なヘッダーファイルと、QLabelQFont、レイアウトのためのヘッダーを含めます。
  2. QApplication app(argc, argv);: Qtアプリケーションを開始するための必須オブジェクトです。
  3. QWidget *window = new QWidget;: ウィジェットを配置するメインのウィンドウを作成します。
  4. QVBoxLayout *layout = new QVBoxLayout(window);: ウィジェットを縦に並べるためのレイアウトを作成し、メインウィンドウに設定します。
  5. label1->setFont(font1);: QLabel にフォントを設定します。ここが重要です。QFont オブジェクトを変更したら、必ずウィジェットに再設定する必要があります。
  6. font2.setLetterSpacing(QFont::AbsoluteSpacing, 5.0);: QFont::AbsoluteSpacing を使用して、文字間に5ピクセルの追加スペースを挿入します。これは文字の幅に関係なく、固定のピクセル値でスペースを調整します。正の値は間隔を広げ、負の値は間隔を狭めます。
  7. font3.setLetterSpacing(QFont::AbsoluteSpacing, -2.0);: AbsoluteSpacing で負の値を指定すると、文字間隔が狭まります。値を大きくしすぎると文字が重なって見えにくくなることがあります。
  8. font4.setLetterSpacing(QFont::PercentageSpacing, 150.0);: QFont::PercentageSpacing を使用して、文字のデフォルト幅に対するパーセンテージで文字間隔を調整します。100 がデフォルト(変更なし)、150 は文字幅の50%を追加します。これは異なるフォントサイズでも比較的一貫した見た目を提供しやすい方法です。
  9. qreal currentSpacing = font2.letterSpacing();: letterSpacing() を引数なしで呼び出すことで、現在設定されている文字間隔の値を取得できます。これは通常、qreal 型(浮動小数点数)で返されます。
  10. window->show();: 作成したウィンドウを表示します。
  11. return app.exec();: アプリケーションのイベントループを開始します。

ウィジェットではなく、カスタムペイントイベント内で QPainter を使ってテキストを描画する場合も、QFont::letterSpacing() を利用できます。

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

class CustomTextWidget : public QWidget {
public:
    CustomTextWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("Custom Text Widget with Letter Spacing");
        resize(400, 300);
    }

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

        // デフォルトのフォント
        QFont defaultFont("Arial", 20);
        painter.setFont(defaultFont);
        painter.drawText(20, 50, "Default Spacing Text");

        // 絶対値で文字間隔を広げる
        QFont wideSpacingFont = defaultFont;
        wideSpacingFont.setLetterSpacing(QFont::AbsoluteSpacing, 8.0); // 8ピクセル広げる
        painter.setFont(wideSpacingFont);
        painter.drawText(20, 100, "Wide Spacing Text");

        // パーセンテージで文字間隔を狭める
        QFont narrowSpacingFont = defaultFont;
        narrowSpacingFont.setLetterSpacing(QFont::PercentageSpacing, 70.0); // 70% (30%狭める)
        painter.setFont(narrowSpacingFont);
        painter.drawText(20, 150, "Narrow Spacing Text");

        // 日本語での例
        QFont japaneseFont("メイリオ", 20); // 環境に合わせて適切な日本語フォントに
        painter.setFont(japaneseFont);
        painter.drawText(20, 200, "日本語のデフォルト文字間隔");

        QFont japaneseWideFont = japaneseFont;
        japaneseWideFont.setLetterSpacing(QFont::AbsoluteSpacing, 3.0); // 日本語も広げる
        painter.setFont(japaneseWideFont);
        painter.drawText(20, 250, "日本語の広い文字間隔");
    }
};

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

    CustomTextWidget widget;
    widget.show();

    return app.exec();
}
  1. CustomTextWidget クラス: QWidget を継承し、paintEvent をオーバーライドしてカスタム描画を行います。
  2. QPainter painter(this);: paintEvent 内で QPainter オブジェクトを初期化し、このウィジェット上に描画できるようにします。
  3. painter.setFont(font);: QPainter でテキストを描画する前に、使用するフォントを設定します。ここでも、QFont オブジェクトを変更するたびに setFont を呼び出す必要があります。
  4. painter.drawText(...): 指定された位置にテキストを描画します。


スタイルシート (CSS) を利用する

Qtのウィジェットは、CSS (Cascading Style Sheets) に似たスタイルシートを適用できます。もしウィジェットのテキスト表示を制御したいのであれば、スタイルシートでletter-spacingプロパティを使用することができます。

利点

  • アプリケーション全体のスタイルを一元管理しやすい。
  • 見た目の変更をコードから分離できるため、UIデザインの変更が容易。
  • QML開発と親和性が高い。

欠点

  • QFont::AbsoluteSpacingのようなピクセル単位の厳密な制御が難しい場合がある(CSSのempx単位の解釈に依存)。
  • すべてのウィジェットや環境で完璧に動作するわけではない。特に、ネイティブ要素の描画に依存するウィジェットでは適用範囲が限定されることがある。

使用例

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

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

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

    QLabel *label1 = new QLabel("スタイルシートなしのテキスト");
    layout->addWidget(label1);

    QLabel *label2 = new QLabel("スタイルシートで文字間隔を広げたテキスト");
    // CSSのletter-spacingプロパティを使用
    // 2pxだけ文字間隔を広げる
    label2->setStyleSheet("QLabel { font-family: 'メイリオ'; font-size: 18px; letter-spacing: 2px; }");
    layout->addWidget(label2);

    QLabel *label3 = new QLabel("スタイルシートで文字間隔を狭めたテキスト");
    // -1pxだけ文字間隔を狭める
    label3->setStyleSheet("QLabel { font-family: 'メイリオ'; font-size: 18px; letter-spacing: -1px; }");
    layout->addWidget(label3);

    window->setWindowTitle("スタイルシートでの文字間隔");
    window->show();

    return app.exec();
}

QTextLayout を利用する (より高度なテキスト描画)

QTextLayout は、より複雑なテキストレイアウトや、文字ごとの詳細な描画制御が必要な場合に非常に強力なツールです。これを使えば、QFont::letterSpacing() では不可能な、文字ごとの間隔調整や、より柔軟な配置が可能です。

利点

  • カーニングやテキストの方向(LtoR, RtoL)など、高度なタイポグラフィ機能を扱うことができる。
  • カスタム描画 (paintEvent 内など) で、テキストの配置をピクセル単位で正確に制御できる。
  • 文字ごとの詳細なメトリクス情報 (QGlyphRun など) にアクセスできる。

欠点

  • プログラミングが複雑になり、学習コストが高い。
  • QLabel のように単にテキストを表示するだけの用途にはオーバーヘッドが大きい。

使用例

この例では、文字ごとの間隔を計算し、QTextLayoutQPainter を使って描画します。letterSpacing のような一律の調整ではなく、より低レベルでの制御が可能です。

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

class CustomTextLayoutWidget : public QWidget {
public:
    CustomTextLayoutWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("QTextLayout で文字間隔を制御");
        resize(400, 250);
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        // 基本フォント
        QFont font("メイリオ", 24);
        painter.setFont(font);

        // -----------------------------------------------------
        // 例1: QTextLayout でデフォルトの文字間隔 (QFont::letterSpacing() は使用しない)
        QTextLayout layout1("QTextLayout でのテキスト", font);
        layout1.beginLayout();
        // 1行目のレイアウト (改行がないため1行)
        QTextLine line1 = layout1.createLine();
        line1.setTextOption(QTextOption(Qt::AlignLeft)); // 左寄せ
        line1.setLineWidth(width()); // ウィジェット幅に合わせてライン幅を設定
        line1.setPosition(QPointF(20, 50)); // 描画位置
        layout1.endLayout();
        layout1.draw(&painter, QPointF(0, 0)); // layout1の内容を描画

        // -----------------------------------------------------
        // 例2: QTextLayout で文字ごとに間隔を調整 (カスタムレンダリング)
        QString text = "個別の文字間隔";
        QTextLayout layout2(text, font);
        layout2.beginLayout();
        QTextLine line2 = layout2.createLine();
        line2.setTextOption(QTextOption(Qt::AlignLeft));
        line2.setLineWidth(width());
        line2.setPosition(QPointF(20, 150));
        layout2.endLayout();

        // 文字ごとに手動で描画し、間にスペースを挿入
        qreal xOffset = 20; // 開始X座標
        qreal yOffset = 150; // 開始Y座標

        // line2のグリフ情報を使用して文字を個別に描画
        for (int i = 0; i < text.length(); ++i) {
            // 文字の境界ボックスを取得 (フォントメトリクスから概算)
            // QTextLayout は文字ごとの詳細な情報を提供しますが、ここでは簡略化
            qreal charWidth = painter.fontMetrics().horizontalAdvance(text.at(i));

            painter.drawText(QPointF(xOffset, yOffset), text.at(i));

            // 文字の後に5ピクセルのスペースを追加
            xOffset += charWidth + 5;
        }

        painter.drawText(QPointF(20, 200), "上の例は、文字ごとの描画によるカスタム間隔のシミュレーションです。");
    }
};

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

これは、QTextLayoutよりも単純なシナリオで、テキストの描画前に文字の幅を計算し、必要なスペースを手動で加算して描画位置を調整する方法です。

利点

  • 描画するテキストの量が少ない場合に有効。
  • QTextLayoutよりも実装が簡単。

欠点

  • 複数行のテキストには不向き。
  • カーニングや複雑なスクリプト(アラビア語など)には対応できない。
#include <QApplication>
#include <QWidget>
#include <QPainter>
#include <QFont>
#include <QFontMetrics>

class ManualSpacingWidget : public QWidget {
public:
    ManualSpacingWidget(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("QFontMetrics で文字間隔を制御");
        resize(400, 150);
    }

protected:
    void paintEvent(QPaintEvent *event) override {
        Q_UNUSED(event);
        QPainter painter(this);
        painter.setRenderHint(QPainter::Antialiasing);

        QFont font("メイリオ", 24);
        painter.setFont(font);
        QFontMetrics fm(font);

        QString text = "手動で調整";
        qreal x = 20;
        qreal y = 80;
        qreal extraSpacing = 3; // 文字間に3ピクセルの追加スペース

        for (int i = 0; i < text.length(); ++i) {
            QString character = text.at(i);
            painter.drawText(QPointF(x, y), character);
            x += fm.horizontalAdvance(character) + extraSpacing;
        }
    }
};

int main(int argc, char *argv[]) {
    QApplication app(argc_argv);
    ManualSpacingWidget widget;
    widget.show();
    return app.exec();
}
  • 少量のテキストで手動のカスタム描画が必要: QFontMetrics を利用して文字幅を計算し、自分で描画位置を調整します。
  • より複雑なテキストレイアウト、文字ごとの精密な制御、カーニングなど: QTextLayout を使用します。これは最も強力ですが、最も複雑な方法です。
  • 見た目をコードから分離したい、UIデザイナーが関わる: スタイルシートのletter-spacingを検討します。
  • 簡単なUIウィジェットの文字間隔調整: QFont::letterSpacing()が最もシンプルで推奨されます。