Qtプログラミング:QFileDialog::setLabelText() のエラーと解決策【日本語】
ファイルダイアログは、ファイルを開いたり保存したりする際にユーザーに表示される標準的なダイアログです。このダイアログには、「ファイル名」「場所」「開く」「キャンセル」などの様々なラベルやボタンがあります。setLabelText()
は、これらの標準的なテキストをアプリケーションの要件に合わせてカスタマイズしたい場合に役立ちます。
QFileDialog::setLabelText()
の使い方
この関数は2つの引数を取ります。
-
QFileDialog::DialogLabel label
: どの要素のテキストを変更するかを指定します。QFileDialog
クラス内に定義されているDialogLabel
列挙型の値を使用します。主なものには以下のようなものがあります。QFileDialog::FileName
: ファイル名の入力欄のラベル。QFileDialog::Accept
: 「開く」や「保存」などの、ダイアログを確定するボタンのテキスト。QFileDialog::Reject
: 「キャンセル」ボタンのテキスト。QFileDialog::LookIn
: 「場所」または「フォルダ」を示すラベル。QFileDialog::FileType
: ファイルの種類(フィルター)を示すラベル。
-
const QString &text
: 設定したい新しいテキストです。
例
#include <QApplication>
#include <QFileDialog>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog dialog;
// 「開く」ボタンのテキストを「選択」に変更
dialog.setLabelText(QFileDialog::Accept, QApplication::tr("選択"));
// 「ファイル名」のラベルを「対象ファイル」に変更
dialog.setLabelText(QFileDialog::FileName, QApplication::tr("対象ファイル"));
// 「キャンセル」ボタンのテキストを「中止」に変更 (ネイティブダイアログでは動作しない場合がある点に注意)
dialog.setLabelText(QFileDialog::Reject, QApplication::tr("中止"));
// ファイルモードを設定 (例: 既存のファイルを選択)
dialog.setFileMode(QFileDialog::ExistingFile);
if (dialog.exec()) {
qDebug() << "選択されたファイル:" << dialog.selectedFiles();
}
return a.exec();
}
QFileDialog::DontUseNativeDialog
オプション: もし、setLabelText()
で設定した全てのテキストが確実に反映されるようにしたい場合は、QFileDialog::DontUseNativeDialog
オプションを設定して、Qt独自のファイルダイアログを使用するように強制することができます。
ただし、このオプションを使用すると、OSのルック&フィールに合わないダイアログが表示される可能性があります。dialog.setOption(QFileDialog::DontUseNativeDialog);
- ネイティブダイアログとの互換性: Qtの
QFileDialog
は、可能であればOSのネイティブなファイルダイアログを使用しようとします。しかし、ネイティブダイアログでは、setLabelText()
で設定した全てのテキストが反映されるわけではありません。特に、「キャンセル」ボタンのテキストなどは、OSの仕様により変更できない場合があります。
setLabelText() が適用されない(最も一般的なエラー)
問題
setLabelText()
を呼び出したにもかかわらず、ファイルダイアログに表示されるテキストが変更されない。
原因
これが最も一般的な問題であり、ほとんどの場合、Qt がOSのネイティブなファイルダイアログを使用していることが原因です。ネイティブダイアログは、OSの標準的なルック&フィールを提供するために設計されており、そのラベルやボタンのテキストはOSによって管理されています。Qtはこれらのネイティブダイアログの内部テキストを直接変更するAPIを提供していません。
トラブルシューティング/解決策
-
どのラベルが影響を受けるか理解する
すべてのDialogLabel
がネイティブダイアログで無視されるわけではありません。例えば、QFileDialog::FileName
は比較的多くのプラットフォームで変更が反映されやすいですが、QFileDialog::Reject
(キャンセルボタン)などはほとんどのネイティブダイアログで変更できません。どのラベルをカスタマイズしたいかによって、解決策を検討する必要があります。 -
QFileDialog::DontUseNativeDialog オプションを使用する
これが最も直接的な解決策です。QFileDialog::DontUseNativeDialog
オプションを設定することで、QtはOSのネイティブダイアログを使用せず、Qt自身で描画する標準的なファイルダイアログを表示します。このQt標準ダイアログは、setLabelText()
で設定したテキストを完全に尊重します。QFileDialog dialog; dialog.setOption(QFileDialog::DontUseNativeDialog); // ここが重要 dialog.setLabelText(QFileDialog::Accept, QApplication::tr("選択")); dialog.setLabelText(QFileDialog::FileName, QApplication::tr("対象ファイル")); // ...
- 見た目の一貫性
OSのネイティブダイアログと比較して、Qt標準ダイアログは見た目がわずかに異なる場合があります。OSの他のアプリケーションと完全に一致させたい場合は、このオプションの使用は避けるべきかもしれません。 - 機能の差異
ネイティブダイアログが提供する一部の高度な機能(例えば、macOSのタグ付け機能など)が、Qt標準ダイアログでは利用できない場合があります。
- 見た目の一貫性
トラブルシューティング/解決策
-
ダイアログ生成後の言語変更
アプリケーションの実行中に言語を変更した場合、既に表示されているダイアログのテキストは自動的には更新されません。ダイアログを再表示するか、言語変更イベントを捕捉してダイアログのテキストを再設定する必要があります。
問題
setLabelText()
の最初の引数に、存在しないか、間違った QFileDialog::DialogLabel
の値を渡してしまい、予期しない動作になるか、何も変更されない。
原因
タイプミスや、存在しない列挙子を使っている可能性があります。
トラブルシューティング/解決策
-
コンパイルエラー/警告の確認
多くの場合、存在しない列挙子を使った場合、コンパイルエラーまたは警告が発生します。それらを見逃さないようにしましょう。 -
Qtドキュメントを確認する
QFileDialog::DialogLabel
の有効な値をQtの公式ドキュメントで確認し、正しい列挙子を使用していることを確認してください。
重要な注意点
QFileDialog::setLabelText()
で設定したテキストは、Qt がネイティブなファイルダイアログを使用しない場合にのみ、すべてのラベルで完全に反映されます。 ネイティブダイアログ(デフォルトの動作)を使用する場合、OSの仕様により一部のラベル(特に「キャンセル」ボタンなど)は変更できません。確実にすべてのラベルが変更されるようにするには、dialog.setOption(QFileDialog::DontUseNativeDialog);
を設定する必要があります。
例1: 基本的な使用法と「開く」ボタンの変更
この例では、ファイルを開くダイアログを表示し、「開く」ボタンとファイル名入力欄のラベルを変更します。
#include <QApplication>
#include <QFileDialog>
#include <QDebug> // デバッグ出力用
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QFileDialog オブジェクトを作成
QFileDialog dialog;
// ----- ここからが setLabelText() の使用例 -----
// QFileDialog::Accept は、ダイアログを確定するボタン(「開く」または「保存」)
// のラベルです。ここでは「選択」に変更します。
dialog.setLabelText(QFileDialog::Accept, QApplication::tr("選択"));
// QFileDialog::FileName は、ファイル名入力欄のラベルです。
// ここでは「対象ファイル名」に変更します。
dialog.setLabelText(QFileDialog::FileName, QApplication::tr("対象ファイル名"));
// ----- setLabelText() の使用例はここまで -----
// ダイアログのタイトルを設定
dialog.setWindowTitle(QApplication::tr("ファイルを選択してください"));
// ファイルモードを設定 (例: 既存のファイルを選択)
dialog.setFileMode(QFileDialog::ExistingFile);
// ダイアログを表示し、ユーザーがOKボタンを押したかチェック
if (dialog.exec() == QFileDialog::Accepted) {
// ユーザーがファイルを選択した場合
QStringList selectedFiles = dialog.selectedFiles();
if (!selectedFiles.isEmpty()) {
qDebug() << "選択されたファイル:" << selectedFiles.first();
}
} else {
// ユーザーがキャンセルした場合
qDebug() << "ファイル選択がキャンセルされました。";
}
return a.exec();
}
実行結果(Qt標準ダイアログの場合)
「開く」ボタンが「選択」に、「ファイル名」のラベルが「対象ファイル名」に変更されて表示されます。
例2: すべての主要なラベルを変更し、Qt標準ダイアログを強制する
この例では、より多くのラベルを変更し、QFileDialog::DontUseNativeDialog
オプションを使用して、変更が確実に反映されるようにします。
#include <QApplication>
#include <QFileDialog>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog dialog;
// ----- Qt標準ダイアログを強制する設定 -----
// これにより、setLabelText() で設定した全てのラベル変更が確実に反映されます。
dialog.setOption(QFileDialog::DontUseNativeDialog);
// ----- setLabelText() の使用例 -----
// ダイアログ確定ボタン(「開く」/「保存」)
dialog.setLabelText(QFileDialog::Accept, QApplication::tr("インポート実行"));
// ダイアログキャンセルボタン
dialog.setLabelText(QFileDialog::Reject, QApplication::tr("処理中止"));
// ファイル名入力欄のラベル
dialog.setLabelText(QFileDialog::FileName, QApplication::tr("対象データファイル"));
// ファイルの種類(フィルター)のラベル
dialog.setLabelText(QFileDialog::FileType, QApplication::tr("データ形式"));
// 「場所」または「フォルダ」を示すラベル
dialog.setLabelText(QFileDialog::LookIn, QApplication::tr("参照場所"));
// ----- setLabelText() の使用例はここまで -----
dialog.setWindowTitle(QApplication::tr("インポートするデータファイルを選択"));
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(QApplication::tr("データファイル (*.dat *.csv);;すべてのファイル (*)"));
if (dialog.exec() == QFileDialog::Accepted) {
QStringList selectedFiles = dialog.selectedFiles();
if (!selectedFiles.isEmpty()) {
qDebug() << "インポート対象ファイル:" << selectedFiles.first();
}
} else {
qDebug() << "インポートがキャンセルされました。";
}
return a.exec();
}
実行結果(Qt標準ダイアログの場合)
「開く」ボタンが「インポート実行」に、「キャンセル」ボタンが「処理中止」に、「ファイル名」が「対象データファイル」に、「ファイルの種類」が「データ形式」に、「場所」が「参照場所」に変更されて表示されます。
この例では、ファイル保存ダイアログで setLabelText()
を使用します。
#include <QApplication>
#include <QFileDialog>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog dialog;
// ファイル保存ダイアログにするため、SaveFileモードを設定
dialog.setAcceptMode(QFileDialog::AcceptSave);
// ----- setLabelText() の使用例 -----
// 「保存」ボタンのラベルを「出力」に変更
dialog.setLabelText(QFileDialog::Accept, QApplication::tr("出力"));
// ファイル名入力欄のラベルを「出力ファイル名」に変更
dialog.setLabelText(QFileDialog::FileName, QApplication::tr("出力ファイル名"));
// ----- setLabelText() の使用例はここまで -----
dialog.setWindowTitle(QApplication::tr("データを保存"));
dialog.setDefaultSuffix("txt"); // デフォルトの拡張子を設定
dialog.setNameFilter(QApplication::tr("テキストファイル (*.txt);;すべてのファイル (*)"));
// 初期ファイル名を設定することもできます
dialog.selectFile("新しいデータ.txt");
if (dialog.exec() == QFileDialog::Accepted) {
QString selectedFile = dialog.selectedFiles().first();
qDebug() << "保存パス:" << selectedFile;
// ここで実際にファイルにデータを書き込む処理を行う
} else {
qDebug() << "保存がキャンセルされました。";
}
return a.exec();
}
実行結果(Qt標準ダイアログの場合)
「保存」ボタンが「出力」に、「ファイル名」のラベルが「出力ファイル名」に変更されて表示されます。
QFileDialog::DontUseNativeDialog オプションを常に使用する (最も直接的な代替策)
これは setLabelText()
の一般的なトラブルシューティングのセクションでも触れましたが、最も直接的で効果的な代替策です。
説明
QFileDialog
は、デフォルトでプラットフォームのネイティブなファイルダイアログを使用しようとします。しかし、QFileDialog::DontUseNativeDialog
オプションを設定することで、Qt が提供するウィジェットベースのファイルダイアログを強制的に使用させることができます。このQt標準ダイアログは setLabelText()
の呼び出しに完全に準拠するため、すべてのラベルが意図通りに変更されます。
利点
- 実装が非常に簡単。
- Qt の通常のウィジェットとして扱われるため、Qtの他の機能(スタイルシートなど)で外観をある程度カスタマイズできる可能性がある。
setLabelText()
が意図通りに動作するようになる。
欠点
- ネイティブダイアログが提供する一部の高度な機能(例: Windowsのエクスプローラー連携機能、macOSのタグ付けなど)が利用できない場合がある。
- OSのネイティブなルック&フィールから外れる。ユーザーにとっては、他のアプリケーションと一貫性のない見た目になる可能性がある。
コード例
#include <QApplication>
#include <QFileDialog>
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QFileDialog dialog;
// ネイティブダイアログの使用を無効にする
dialog.setOption(QFileDialog::DontUseNativeDialog);
// これで setLabelText() が確実に反映される
dialog.setLabelText(QFileDialog::Accept, QApplication::tr("データの取り込み"));
dialog.setLabelText(QFileDialog::FileName, QApplication::tr("対象ファイルを選択"));
dialog.setLabelText(QFileDialog::Reject, QApplication::tr("中止する"));
dialog.setLabelText(QFileDialog::LookIn, QApplication::tr("ファイル検索場所"));
dialog.setWindowTitle(QApplication::tr("カスタムファイルインポート"));
dialog.setFileMode(QFileDialog::ExistingFile);
dialog.setNameFilter(QApplication::tr("テキストファイル (*.txt);;すべてのファイル (*)"));
if (dialog.exec() == QFileDialog::Accepted) {
qDebug() << "選択されたファイル:" << dialog.selectedFiles().first();
} else {
qDebug() << "ダイアログがキャンセルされました。";
}
return a.exec();
}
QFileDialog をサブクラス化し、独自のウィジェットを追加する (より高度なカスタマイズ)
これは setLabelText()
の範囲を超える、より抜本的な変更を行いたい場合に検討する方法です。QFileDialog
は QDialog
を継承しているため、通常のダイアログと同様に独自のウィジェットを追加することができます。
説明
QFileDialog
の内部レイアウトにアクセスし、そこにカスタムウィジェット(例: 追加のチェックボックス、ドロップダウンリスト、テキスト入力欄など)を組み込むことができます。この方法では、ラベルのテキスト変更だけでなく、ファイル選択ダイアログの機能そのものを拡張することが可能です。
利点
- 特定のアプリケーション要件に合わせて、ファイル選択プロセスに追加のオプションを提供できる。
setLabelText()
では不可能な、ダイアログのレイアウトや機能の大幅なカスタマイズが可能。
欠点
- 保守が難しい
内部構造に依存するため、Qtのマイナーバージョンアップでも予期せぬレイアウトの崩れが発生する可能性がある。 - 実装が複雑
QFileDialog
の内部レイアウトを理解し、既存のウィジェットと競合しないように慎重にウィジェットを追加する必要があります。Qtのバージョンアップによって内部レイアウトが変更されるリスクもあります。 - QFileDialog::DontUseNativeDialog が必須
この方法も、Qt標準ダイアログを強制する必要があります。ネイティブダイアログの内部構造はOS依存であり、直接アクセスしてウィジェットを追加することは非常に困難か、不可能です。
コード例 (概念的なもの)
#include <QApplication>
#include <QFileDialog>
#include <QVBoxLayout>
#include <QLabel>
#include <QLineEdit>
#include <QDebug>
class CustomFileDialog : public QFileDialog
{
Q_OBJECT // サブクラス化する場合は Q_OBJECT マクロが必要
public:
CustomFileDialog(QWidget *parent = nullptr)
: QFileDialog(parent)
{
// ネイティブダイアログの使用を無効にする
setOption(QFileDialog::DontUseNativeDialog);
// QFileDialog::setLabelText() を通常通り使用可能
setLabelText(QFileDialog::Accept, QApplication::tr("カスタム開く"));
setLabelText(QFileDialog::Reject, QApplication::tr("やっぱりやめる"));
// 既存のレイアウトを取得(QFileDialogのレイアウトは通常 QGridLayout)
// dynamic_cast は安全性を高めるため。失敗する可能性も考慮
QGridLayout* mainLayout = qobject_cast<QGridLayout*>(layout());
if (mainLayout) {
// 例: 追加のオプションを表示する QLabel と QLineEdit を追加
QLabel* customLabel = new QLabel(QApplication::tr("追加情報:"), this);
QLineEdit* customLineEdit = new QLineEdit(this);
customLineEdit->setPlaceholderText(QApplication::tr("ここに何か入力してください"));
// レイアウトの既存の行数に応じて新しいウィジェットを追加
// 通常、QFileDialogのデフォルトレイアウトは固定されており、
// 新しい行(既存のコンテンツの下)に追加するのが最も安全です。
int rowCount = mainLayout->rowCount();
mainLayout->addWidget(customLabel, rowCount, 0, 1, 1); // Row, Col, RowSpan, ColSpan
mainLayout->addWidget(customLineEdit, rowCount, 1, 1, mainLayout->columnCount() - 1); // 右端まで広げる
// 独自の情報を取得するためのプロパティやシグナル/スロットを追加
// ...
}
}
// 必要に応じてカスタムウィジェットのデータにアクセスする public メソッドを追加
QString getCustomText() const {
// 例のカスタムLineEditにアクセスしてテキストを返す
QGridLayout* mainLayout = qobject_cast<QGridLayout*>(layout());
if (mainLayout && mainLayout->rowCount() > 0) {
// customLineEdit が追加された行のオブジェクトを取得
// これは非常に脆い方法であり、通常はカスタムLineEditをメンバ変数として保持するべきです。
// 簡単な例示として。
QLayoutItem* item = mainLayout->itemAtPosition(mainLayout->rowCount() - 1, 1);
if (item && item->widget()) {
QLineEdit* lineEdit = qobject_cast<QLineEdit*>(item->widget());
if (lineEdit) {
return lineEdit->text();
}
}
}
return QString();
}
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
CustomFileDialog dialog;
dialog.setWindowTitle(QApplication::tr("カスタムファイルダイアログ"));
dialog.setFileMode(QFileDialog::ExistingFile);
if (dialog.exec() == QFileDialog::Accepted) {
qDebug() << "選択されたファイル:" << dialog.selectedFiles().first();
qDebug() << "カスタム入力情報:" << dialog.getCustomText();
} else {
qDebug() << "キャンセルされました。";
}
return a.exec();
}
#include "main.moc" // Q_OBJECT を使用しているため、moc ファイルを含める必要がある
説明
QFileDialog
を使用せず、QDialog
をベースにして、ファイル選択のためのUIをゼロから構築する方法です。これには、ファイルシステムを表示するための QTreeView
や QListView
、ファイルシステムを扱うための QFileSystemModel
、ディレクトリパスを表示・入力するための QLineEdit
、フィルター用の QComboBox
、OK/Cancel ボタンのための QDialogButtonBox
などのウィジェットを組み合わせて作成します。
利点
- アプリケーションの既存のUI/UXと完全に統合できる。
- ネイティブダイアログの制約を受けない
OSのネイティブダイアログが提供しないような、非常に特殊な機能を実装できる。 - 完全なカスタマイズ性
レイアウト、外観、機能など、ダイアログのあらゆる側面を完全に制御できます。
欠点
- OS固有の機能の欠如
ネイティブダイアログが自動的に提供する一部のOS固有のショートカットや動作(例: クイックアクセス、クラウドストレージの連携など)が失われる可能性がある。 - 多くのコード量
複雑なロジックとUI要素の配置が必要となるため、コード量が増える。 - 実装コストが高い
ファイルシステムを閲覧し、選択する基本的な機能だけでも、QFileDialog
が提供する多くの機能を自分で実装する必要があります。
コード例 (骨格のみ)
#include <QApplication>
#include <QDialog>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QTreeView>
#include <QFileSystemModel>
#include <QLineEdit>
#include <QComboBox>
#include <QDialogButtonBox>
#include <QPushButton>
#include <QDebug>
class MyCustomFileDialog : public QDialog
{
Q_OBJECT
public:
MyCustomFileDialog(QWidget *parent = nullptr)
: QDialog(parent)
{
setWindowTitle(tr("カスタムファイル選択"));
// メインレイアウト
QVBoxLayout* mainLayout = new QVBoxLayout(this);
// パス表示・入力欄
QHBoxLayout* pathLayout = new QHBoxLayout();
QLabel* pathLabel = new QLabel(tr("パス:"));
QLineEdit* pathLineEdit = new QLineEdit();
pathLayout->addWidget(pathLabel);
pathLayout->addWidget(pathLineEdit);
mainLayout->addLayout(pathLayout);
// ファイルシステムツリービュー
QTreeView* treeView = new QTreeView(this);
QFileSystemModel* model = new QFileSystemModel(this);
model->setRootPath(QDir::homePath()); // 初期ディレクトリを設定
treeView->setModel(model);
treeView->setRootIndex(model->index(QDir::homePath()));
treeView->setColumnHidden(1, true); // サイズ列を非表示
treeView->setColumnHidden(2, true); // 種類列を非表示
treeView->setColumnHidden(3, true); // 更新日列を非表示
mainLayout->addWidget(treeView);
// ファイルフィルター
QHBoxLayout* filterLayout = new QHBoxLayout();
QLabel* filterLabel = new QLabel(tr("ファイルの種類:"));
QComboBox* filterComboBox = new QComboBox();
filterComboBox->addItem(tr("テキストファイル (*.txt)"));
filterComboBox->addItem(tr("すべてのファイル (*)"));
filterLayout->addWidget(filterLabel);
filterLayout->addWidget(filterComboBox);
mainLayout->addLayout(filterLayout);
// OK/Cancel ボタン
QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
// ここで「OK」や「Cancel」のテキストを直接変更できる
buttonBox->button(QDialogButtonBox::Ok)->setText(tr("選択完了"));
buttonBox->button(QDialogButtonBox::Cancel)->setText(tr("閉じる"));
connect(buttonBox, &QDialogButtonBox::accepted, this, &MyCustomFileDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &MyCustomFileDialog::reject);
mainLayout->addWidget(buttonBox);
// シグナルとスロットの接続(ファイル選択時の処理、パスの更新など)
connect(treeView, &QTreeView::doubleClicked, this, [=](const QModelIndex& index) {
// ファイルが選択された場合のロジック
if (model->fileInfo(index).isFile()) {
selectedFilePath = model->filePath(index);
accept();
} else if (model->fileInfo(index).isDir()) {
treeView->setRootIndex(index);
pathLineEdit->setText(model->filePath(index));
}
});
connect(treeView->selectionModel(), &QItemSelectionModel::currentChanged, this, [=](const QModelIndex& current, const QModelIndex& previous) {
if (model->fileInfo(current).isFile()) {
pathLineEdit->setText(model->filePath(current));
}
});
// 選択されたファイルパスを保持するメンバ変数
selectedFilePath = "";
}
QString getSelectedFile() const {
return selectedFilePath;
}
private:
QString selectedFilePath;
};
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MyCustomFileDialog dialog;
if (dialog.exec() == QDialog::Accepted) {
qDebug() << "選択されたファイル:" << dialog.getSelectedFile();
} else {
qDebug() << "ダイアログが閉じられました。";
}
return a.exec();
}
#include "main.moc" // Q_OBJECT を使用しているため、moc ファイルを含める必要がある
QFileDialog::setLabelText()
の代替策は、カスタマイズの必要性のレベルによって変わります。
- ファイル選択ダイアログの見た目も機能も完全に制御したい場合
ゼロから独自のQDialog
を構築するのが最も柔軟ですが、最も多くの労力が必要です。 - ファイルダイアログに少し機能を追加したい場合
QFileDialog
をサブクラス化し、その内部レイアウトにウィジェットを追加することを検討できますが、これはQtのバージョンアップに対する脆弱性があります。 - 簡単なラベル変更のみで、ネイティブな見た目を気にしない場合
QFileDialog::DontUseNativeDialog
オプションを使用するのが最も簡単で推奨される方法です。