Qtフォントのギモンを解決!pointSize()からピクセルサイズまで
QtプログラミングにおけるQFont::pointSize()
は、フォントのポイントサイズを返します。
ポイントサイズとは?
ポイントサイズは、フォントの大きさを表す一般的な単位です。1ポイントは通常、1/72インチと定義されます。つまり、pointSize()
が返す値は、そのフォントが何ポイントの大きさであるかを示します。
QFont
オブジェクトは、テキストの描画に使用するフォントの様々な属性(フォントファミリー、太さ、イタリックなど)を指定するために使われます。pointSize()
は、そのQFont
オブジェクトに設定されているポイントサイズを取得するための関数です。
設定したはずのフォントサイズが反映されない
これは最もよくある問題です。
QFont::pointSize()
は、設定したポイントサイズを返しますが、実際に描画されるフォントのサイズは、システムにインストールされているフォントやディスプレイの設定によって異なる場合があります。
考えられる原因とトラブルシューティング
-
他のスタイルシートや親ウィジェットのフォント設定によるオーバーライド
CSSのようなQtスタイルシートを使用している場合、または親ウィジェットのフォント設定が子ウィジェットに継承されている場合、明示的に設定したフォントサイズが上書きされることがあります。- トラブルシューティング
スタイルシートを確認し、必要に応じてより具体的なセレクタを使用するか、!important
のようなQtスタイルシートの優先度指定を検討します(ただし、乱用は避けるべきです)。
- トラブルシューティング
-
QFontオブジェクトがウィジェットに適用されていない
QFont
オブジェクトを作成してsetPointSize()
を呼び出しただけでは、UIに反映されません。QWidget::setFont()
などを介して、そのフォントをウィジェットに設定する必要があります。QPushButton *button = new QPushButton("Hello"); QFont font = button->font(); // 現在のフォントを取得 font.setPointSize(16); button->setFont(font); // 新しいフォントを適用
-
システムにフォントがインストールされていない、または利用できない
指定したフォントがシステムにインストールされていない場合、Qtは最も近い代替フォントを選択します。この代替フォントが、指定したポイントサイズをサポートしていない可能性があります。- トラブルシューティング
- 指定したフォントがシステムにインストールされているか確認します。
QFontInfo
を使用して、実際に使用されているフォントの情報を確認します。QFontInfo::pointSize()
は、実際に描画されるフォントのポイントサイズを返します。
QFont font; font.setPointSize(12); // ... フォントをウィジェットなどに適用 ... QFontInfo fontInfo(font); // QFontInfo は QFont オブジェクトが実際に適用された後に作成 qDebug() << "設定されたポイントサイズ:" << font.pointSize(); qDebug() << "実際に使用されているポイントサイズ:" << fontInfo.pointSize();
font.pointSize()
とfontInfo.pointSize()
の値が異なる場合、システムが代替フォントを選択しているか、指定されたサイズを正確に再現できないことを示唆しています。
- トラブルシューティング
-
スケーラブルなフォントを使用していない
ビットマップフォントなど、特定のサイズでしか利用できないフォントを使用している場合、設定したポイントサイズが正確に反映されないことがあります。アウトラインフォント(TrueType, OpenTypeなど)はスケーラブルであり、任意のサイズで描画できます。- トラブルシューティング
別のフォントファミリー(例: Arial, Times New Roman, Yu Gothicなど、一般的なスケーラブルフォント)を試してください。
- トラブルシューティング
DPIスケーリングによる表示サイズの違い
特に高DPIディスプレイ環境では、同じポイントサイズでも見た目の大きさが異なることがあります。これはQtがDPIスケーリングを自動的に行うためですが、意図しない結果になることもあります。
考えられる原因とトラブルシューティング
極端に小さい/大きいフォントサイズが正しく表示されない
非常に小さい(例: 1ポイント以下)または非常に大きいポイントサイズを設定した場合、表示がおかしくなったり、警告が出たりすることがあります。
考えられる原因とトラブルシューティング
-
レンダリングの問題(特にOpenGL使用時)
QPainter
をQOpenGLWidget
などで使用している場合、特定のフォントサイズでテキストが黒い棒になったり、全く表示されなかったりする報告があります。これは、OpenGLの描画コンテキストやフレームバッファの設定(例: 深度ステンシルバッファの不足)が原因である場合があります。- トラブルシューティング
QOpenGLFramebufferObject
を使用している場合、QOpenGLFramebufferObject::CombinedDepthStencil
アタッチメントを持つように設定されているか確認します。QPainter
を直接QImage
に描画することで回避できる場合もあります。
- トラブルシューティング
-
最小・最大サイズの制限
多くのフォントやレンダリングシステムには、サポートされる最小・最大サイズがあります。特に1ポイント以下のサイズは、警告が出たり、全く表示されなかったりすることがあります。- トラブルシューティング
QFont::setPointSize()
に設定する値が1以上であることを確認してください。また、過度に大きなサイズも問題を引き起こす可能性があります。
- トラブルシューティング
フォントメトリクスやレイアウトのずれ
QFont::pointSize()
で設定したサイズに基づいてテキストの幅や高さを計算する際に、QFontMetrics
やQFontMetricsF
を使用しますが、この値が実際の描画とずれることがあります。
考えられる原因とトラブルシューティング
-
フォントの行間(Leading)
フォントには、文字の高さ以外に行間を確保するためのスペースが含まれることがあります。QFontMetrics::height()
などはこの行間を含むため、テキストの描画領域と高さが一致しないことがあります。- トラブルシューティング
QFontMetrics::ascent()
とQFontMetrics::descent()
を組み合わせて、ベースラインからの上方向と下方向の距離を把握し、より正確なテキスト描画領域を計算します。
- トラブルシューティング
-
カーニングや文字間隔(レタースペーシング)
フォントのカーニング設定や、QtのQFont::setLetterSpacing()
などが影響し、テキストの実際の幅や高さが、単純な計算と異なる場合があります。- トラブルシューティング
QFontMetrics
やQFontMetricsF
を使用する際は、boundingRect()
やtightBoundingRect()
などの関数で実際に描画される範囲を考慮します。QFont::setKerning(true)
がデフォルトで有効ですが、フォントによっては期待通りに機能しないこともあります。QFont::setStretch()
などで文字の幅を調整している場合も、予想と異なる結果になることがあります。
- トラブルシューティング
- QtフォーラムやStack Overflowで検索する
同様の問題に遭遇している開発者がいる可能性が高く、解決策が見つかることがあります。 - Qtドキュメントを確認する
QFont
,QFontInfo
,QFontMetrics
,QFontMetricsF
の公式ドキュメントには、詳細な情報や注意点が記載されています。 - シンプルなコードで再現テスト
問題が複雑なUIの一部で発生している場合、最小限のコードで問題が再現するかどうかを試すことで、原因の切り分けがしやすくなります。 - qDebug()を多用する
QFont::pointSize()
、QFontInfo::pointSize()
、QFont::pixelSize()
、QFontInfo::pixelSize()
などの値をqDebug()
で出力し、期待通りの値になっているか確認します。
基本的なフォントサイズの設定と取得
この例では、QFont
オブジェクトを作成し、setPointSize()
でポイントサイズを設定し、pointSize()
でその設定値を取得する方法を示します。
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QLabel label("Hello, Qt!"); // QLabel ウィジェットを作成
QFont font = label.font(); // 現在のラベルのフォントを取得
qDebug() << "初期のフォントファミリー:" << font.family();
qDebug() << "初期のポイントサイズ:" << font.pointSize();
// フォントファミリーとポイントサイズを設定
font.setFamily("Arial");
font.setPointSize(24); // 24ポイントに設定
label.setFont(font); // ラベルにフォントを適用
qDebug() << "設定後のフォントファミリー:" << font.family();
qDebug() << "設定後のポイントサイズ:" << font.pointSize();
label.show();
return a.exec();
}
解説
qDebug()
を使用して、設定前後のポイントサイズを確認できます。label.setFont(font);
で、変更したフォントをラベルに適用します。この行を忘れると、フォントの変更はUIに反映されません。font.setPointSize(24);
で、フォントのポイントサイズを24に設定します。QFont font = label.font();
で、ラベルの現在のフォントを取得します。ウィジェットのフォントは通常、システムのデフォルトフォントから初期化されます。
QFontInfo を使った実際の表示サイズの確認
QFont::pointSize()
は設定した値を返しますが、実際にシステムが描画に使うフォントのポイントサイズは異なる場合があります。QFontInfo
は、システムが実際に選択したフォントの情報を提供します。
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QFontInfo>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QLabel label("Qt Fonts in Action!");
QFont requestedFont("Meiryo UI", 30, QFont::Bold); // 30ポイント、太字のメイリオUIを要求
label.setFont(requestedFont);
// QFontInfo を使って、実際に使用されているフォントの情報を取得
QFontInfo actualFontInfo(label.font());
qDebug() << "要求したフォントファミリー:" << requestedFont.family();
qDebug() << "要求したポイントサイズ:" << requestedFont.pointSize();
qDebug() << "要求した太さ:" << requestedFont.weight();
qDebug() << "-----------------------------------";
qDebug() << "実際に使用されているフォントファミリー:" << actualFontInfo.family();
qDebug() << "実際に使用されているポイントサイズ:" << actualFontInfo.pointSize();
qDebug() << "実際に使用されているピクセルサイズ:" << actualFontInfo.pixelSize(); // ピクセルサイズも確認
qDebug() << "実際に使用されている太さ:" << actualFontInfo.weight();
qDebug() << "フォントがスケーラブルか?:" << actualFontInfo.isScalable();
label.show();
return a.exec();
}
解説
actualFontInfo.pixelSize()
は、実際の描画に使われるピクセル単位のサイズを返します。これはディスプレイのDPI設定に影響されます。actualFontInfo.pointSize()
は、システムが選択したフォントのポイントサイズを返します。これがrequestedFont.pointSize()
と同じとは限りません。QFont requestedFont(...)
で、特定のフォントファミリー(例: "Meiryo UI")とポイントサイズ、太さを要求しています。
スライダーやボタンを使って、フォントサイズを動的に変更する例です。
#include <QApplication>
#include <QWidget>
#include <QLabel>
#include <QSlider>
#include <QVBoxLayout>
#include <QDebug>
class FontResizerWidget : public QWidget {
Q_OBJECT // シグナルとスロットを使用するために必要
public:
FontResizerWidget(QWidget *parent = nullptr) : QWidget(parent) {
setWindowTitle("Font Resizer");
// ラベルを作成
label = new QLabel("このテキストのサイズが変わります。");
label->setAlignment(Qt::AlignCenter); // 中央揃え
// スライダーを作成 (最小10ポイント、最大40ポイント)
slider = new QSlider(Qt::Horizontal);
slider->setRange(10, 40);
slider->setValue(label->font().pointSize()); // 初期値を現在のフォントサイズに設定
// レイアウトを設定
QVBoxLayout *layout = new QVBoxLayout(this);
layout->addWidget(label);
layout->addWidget(slider);
// スライダーの値が変更されたときにフォントサイズを更新
connect(slider, &QSlider::valueChanged, this, &FontResizerWidget::updateFontSize);
// 初期のフォントサイズを適用
updateFontSize(slider->value());
}
private slots:
void updateFontSize(int newPointSize) {
QFont font = label->font(); // 現在のラベルのフォントを取得
font.setPointSize(newPointSize); // 新しいポイントサイズを設定
label->setFont(font); // ラベルに適用
qDebug() << "現在のポイントサイズ:" << font.pointSize();
}
private:
QLabel *label;
QSlider *slider;
};
#include "main.moc" // MOCファイル(Qtのメタオブジェクトコンパイラが必要)
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
FontResizerWidget window;
window.resize(400, 200);
window.show();
return a.exec();
}
Q_OBJECT
マクロとmain.moc
のインクルードは、シグナルとスロットを使用するために必須です。プロジェクトのビルド設定にQtのMOC処理が含まれていることを確認してください(通常はqmake
やCMake
が自動で行います)。updateFontSize
スロット内で、スライダーから受け取った新しいポイントサイズをlabel->font()
で取得したQFont
オブジェクトに設定し、label->setFont()
でラベルに適用しています。QSlider::valueChanged
シグナルをupdateFontSize
スロットに接続しています。FontResizerWidget
クラスは、QLabel
とQSlider
を持っています。
QFont::setPixelSize() と QFont::pixelSize()
QFont::pointSize()との違い
pixelSize()
は、指定したピクセル数でフォントを描画しようとします。DPIスケーリングの影響を直接受けないため、異なるDPIのディスプレイでは同じピクセルサイズでも見た目の大きさが異なる可能性があります。pointSize()
はデバイスに依存しない単位(ポイント)で指定するため、異なるDPI(Dots Per Inch)のディスプレイでも相対的に同じ視覚的なサイズになります。Qtが内部でDPIを考慮して適切なピクセルサイズに変換します。
利点
- DPIスケーリングによる自動調整を避けたい場合に有用です。
- 特定のピクセル精度が必要なUIデザインや、低解像度ディスプレイでの正確なレイアウト調整に適しています。
欠点
- デバイス独立性が低い。異なるDPIの環境で見た目が一致しない可能性があります。
使用例
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QDebug>
#include <QFontInfo> // 実際に使用されるピクセルサイズを確認するため
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QLabel label("ピクセルサイズで指定されたテキスト");
QFont font = label.font();
font.setPixelSize(20); // 20ピクセルに設定
label.setFont(font);
// QFontInfo で実際に使用されているピクセルサイズを確認
QFontInfo fontInfo(label.font());
qDebug() << "設定されたピクセルサイズ:" << font.pixelSize();
qDebug() << "実際に使用されているピクセルサイズ:" << fontInfo.pixelSize();
label.show();
return a.exec();
}
QFontMetrics と QFontMetricsF を使用したテキストの高さ・幅の計算
QFont::pointSize()との関連
QFont::pointSize()
(またはpixelSize()
)で指定されたフォントに基づいて、QFontMetrics
オブジェクトを作成し、そのフォントで描画されるテキストのサイズを測定します。
利点
- 動的なテキストの描画(例えばカスタムペイント)で、テキストの配置を正確に行うために使用します。
- UIレイアウトの正確な計算。テキストがウィジェット内で収まるか、あるいは特定の領域に表示されるように調整する際に不可欠です。
主なメソッド
descent()
: ベースラインからフォントの最も低い部分までの距離。ascent()
: ベースラインからフォントの最も高い部分までの距離。boundingRect(const QString &text)
: テキストの描画領域をQRect
(またはQRectF
)で返す。height()
: フォントの行の高さ(アセンダ、ディセンダ、行間を含む)をピクセル単位で返す。width(const QString &text)
: テキストの幅をピクセル単位で返す。
使用例
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QFontMetrics>
#include <QDebug>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QLabel label("Hello, Qt with Metrics!");
QFont font = label.font();
font.setPointSize(18); // 18ポイントに設定
label.setFont(font);
// QFontMetrics を作成(QLabel のフォントから)
QFontMetrics metrics(label.font());
QString textToMeasure = "Sample Text";
int textWidth = metrics.horizontalAdvance(textToMeasure); // Qt 5.11以降の推奨
int textHeight = metrics.height();
QRect boundingBox = metrics.boundingRect(textToMeasure);
qDebug() << "フォントのポイントサイズ:" << font.pointSize();
qDebug() << "テキストの幅 ('" << textToMeasure << "'):" << textWidth << "px";
qDebug() << "フォントの高さ:" << textHeight << "px";
qDebug() << "バウンディングボックス:" << boundingBox;
// 例として、ラベルのサイズをテキストに合わせる
label.adjustSize(); // この場合はQLabel::adjustSize()が自動でメトリクスを使用します
label.show();
return a.exec();
}
スタイルシート (Qt Style Sheets) によるフォントサイズの制御
QFont::pointSize()との関連
スタイルシートでフォントサイズを指定すると、内部的にはQtがQFont
オブジェクトを作成し、そこでpointSize()
または対応するピクセルサイズが設定されます。
利点
- テーマの切り替えが容易になる。
- コードとデザインを分離できる。
- UIのルック&フィールを一元的に管理できる。
欠点
- 複雑なスタイルシートはデバッグが難しい場合がある。
- C++コード内で動的にフォントサイズを変更する柔軟性は低い(スタイルシート文字列を動的に生成・適用する必要がある)。
使用例
#include <QApplication>
#include <QLabel>
#include <QPushButton>
#include <QVBoxLayout>
#include <QWidget>
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
QWidget window;
QVBoxLayout *layout = new QVBoxLayout(&window);
QLabel *label1 = new QLabel("スタイルシートで20pt");
// QLabel に直接スタイルシートを適用
label1->setStyleSheet("QLabel { font-size: 20pt; color: blue; }");
layout->addWidget(label1);
QLabel *label2 = new QLabel("ボタンにスタイルシートで16pt");
QPushButton *button = new QPushButton("クリック!");
// QPushButton に直接スタイルシートを適用
button->setStyleSheet("QPushButton { font-size: 16pt; background-color: lightgray; }");
layout->addWidget(label2);
layout->addWidget(button);
// アプリケーション全体にスタイルシートを適用することも可能
// a.setStyleSheet("QLabel { font-size: 14pt; }");
// この場合、個別のウィジェットのスタイルシートが優先される(詳細度による)
window.show();
return a.exec();
}
QFont::pointSize()との関連
pointSize()
でフォントサイズを指定した場合、QtはDPIスケーリングを考慮して、そのポイントサイズが実際に適切なピクセルサイズで描画されるように調整します。これらの設定は、その自動調整の動作を制御します。
利点
- 異なるディスプレイ環境での一貫したユーザーエクスペリエンスを提供。
- 高DPIディスプレイでの見た目を改善し、アプリケーションの可読性を保つ。
方法
- 環境変数:
QT_SCALE_FACTOR=1.5
: アプリケーション全体のスケールファクターを強制的に設定する。QT_AUTO_SCREEN_SCALE_FACTOR=1
: 画面のDPIに基づいて自動的にスケールファクターを決定する(通常はこれが推奨)。QT_FONT_DPI=96
: フォントレンダリングに使用する論理DPIを強制的に設定する。
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
: 高DPI環境でアイコンや画像が鮮明に表示されるようにする。QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
: Qt 5.6以降で高DPIスケーリングを有効にする(デフォルトで有効な場合が多い)。
#include <QApplication>
#include <QLabel>
#include <QFont>
#include <QDebug>
int main(int argc, char *argv[]) {
// 高DPIスケーリングを有効にする (Qt 5.6以降)
// この行はQApplicationオブジェクトを作成する前に記述する必要がある
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QCoreApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QApplication a(argc, argv);
QLabel label("DPIスケーリングが適用されたテキスト");
QFont font = label.font();
font.setPointSize(16); // 16ポイントに設定
label.setFont(font);
qDebug() << "フォントのポイントサイズ:" << font.pointSize();
qDebug() << "実際に使用されるピクセルサイズ:" << QFontInfo(label.font()).pixelSize(); // 環境によって変化する
label.show();
return a.exec();
}