注文フォームの例
「注文フォーム」の例では、シンプルなテンプレートと、ダイアログでユーザーが入力したデータを組み合わせて、リッチテキスト文書を生成する方法を示しています。

DetailsDialog の定義
DetailsDialog クラスはQDialog のサブクラスであり、スロットverify() を実装することで、DetailsDialog の内容を後で検証できるようにしています。これについては、「DetailsDialog の実装」でさらに詳しく説明しています。
class DetailsDialog : public QDialog
{
Q_OBJECT
public:
DetailsDialog(const QString &title, QWidget *parent);
public slots:
void verify();
public:
QList<QPair<QString, int> > orderItems();
QString senderName() const;
QString senderAddress() const;
bool sendOffers();
private:
void setupItemsTable();
QLabel *nameLabel;
QLabel *addressLabel;
QCheckBox *offersCheckBox;
QLineEdit *nameEdit;
QStringList items;
QTableWidget *itemsTable;
QTextEdit *addressEdit;
QDialogButtonBox *buttonBox;
};DetailsDialog のコンストラクタは、title およびparent というパラメータを受け付けます。このクラスは、外部からデータにアクセスできるようにするため、orderItems() 、senderName() 、senderAddress() 、sendOffers() の4つのゲッター関数を定義しています。
このクラスの定義には、必須フィールド用の入力ウィジェットであるnameEdit とaddressEdit が含まれています。また、QCheckBox とQDialogButtonBox が定義されています。前者は、ユーザーに製品やオファーに関する情報を受け取るオプションを提供するためのもので、後者は、使用されるボタンがユーザーのネイティブプラットフォームに合わせて配置されるようにするためのものです。さらに、QTableWidget (itemsTable )は、注文の詳細を保持するために使用されます。
以下のスクリーンショットは、作成を予定しているDetailsDialog を示しています。

DetailsDialogの実装
DetailsDialog のコンストラクタでは、先に定義されたフィールドとそのそれぞれのラベルをインスタンス化します。offersCheckBox のラベルを設定し、setupItemsTable() 関数を呼び出してitemsTable を設定・初期化します。QDialogButtonBox オブジェクト(buttonBox )は、OK およびCancel ボタンを含めてインスタンス化されます。このbuttonBox のaccepted() およびrejected() シグナルは、DetailsDialog 内のverify() およびreject() スロットに接続されます。
DetailsDialog::DetailsDialog(const QString &title, QWidget *parent)
: QDialog(parent)
{
nameLabel = new QLabel(tr("Name:"));
addressLabel = new QLabel(tr("Address:"));
addressLabel->setAlignment(Qt::AlignLeft | Qt::AlignTop);
nameEdit = new QLineEdit;
addressEdit = new QTextEdit;
offersCheckBox = new QCheckBox(tr("Send information about products and "
"special offers"));
setupItemsTable();
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
| QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &DetailsDialog::verify);
connect(buttonBox, &QDialogButtonBox::rejected, this, &DetailsDialog::reject);QGridLayout を使用して、すべてのオブジェクトをDetailsDialog 上に配置します。
QGridLayout *mainLayout = new QGridLayout;
mainLayout->addWidget(nameLabel, 0, 0);
mainLayout->addWidget(nameEdit, 0, 1);
mainLayout->addWidget(addressLabel, 1, 0);
mainLayout->addWidget(addressEdit, 1, 1);
mainLayout->addWidget(itemsTable, 0, 2, 2, 1);
mainLayout->addWidget(offersCheckBox, 2, 1, 1, 2);
mainLayout->addWidget(buttonBox, 3, 0, 1, 3);
setLayout(mainLayout);
setWindowTitle(title);
}setupItemsTable() 関数は、QTableWidget オブジェクト(itemsTable )をインスタンス化し、注文されたアイテムのタイプを保持するQStringList オブジェクト(items )に基づいて行数を設定します。列数は2に設定され、「名前」と「数量」のレイアウトが提供されます。for ループを使用してitemsTable にデータを入力し、name のフラグをQt::ItemIsEnabled またはQt::ItemIsSelectable に設定します。デモの目的上、quantity の値は1に設定されており、itemsTable 内のすべてのアイテムの数量はこの値となっていますが、実行時にセルの内容を編集することで変更可能です。
void DetailsDialog::setupItemsTable()
{
items << tr("T-shirt") << tr("Badge") << tr("Reference book")
<< tr("Coffee cup");
itemsTable = new QTableWidget(items.count(), 2);
for (int row = 0; row < items.count(); ++row) {
QTableWidgetItem *name = new QTableWidgetItem(items[row]);
name->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable);
itemsTable->setItem(row, 0, name);
QTableWidgetItem *quantity = new QTableWidgetItem("1");
itemsTable->setItem(row, 1, quantity);
}
}orderItems() 関数は、itemsTable からデータを抽出し、QList<QPair<QString,int>> の形式で返します。ここで、各QPair は、1つのアイテムとその注文数量に対応しています。
QList<QPair<QString, int> > DetailsDialog::orderItems()
{
QList<QPair<QString, int> > orderList;
for (int row = 0; row < items.count(); ++row) {
QPair<QString, int> item;
item.first = itemsTable->item(row, 0)->text();
int quantity = itemsTable->item(row, 1)->data(Qt::DisplayRole).toInt();
item.second = qMax(0, quantity);
orderList.append(item);
}
return orderList;
}senderName() 関数は、注文フォームの「名前」フィールドを格納するために使用されるQLineEdit の値を返すために使用されます。
QString DetailsDialog::senderName() const
{
return nameEdit->text();
}senderAddress() 関数は、注文フォームの住所を含むQTextEdit の値を返すために使用されます。
QString DetailsDialog::senderAddress() const
{
return addressEdit->toPlainText();
}sendOffers() 関数は、注文フォームの顧客が、会社のオファーやプロモーションに関する詳細情報の受け取りを希望しているかどうかを判断するために使用されるtrue またはfalse の値を返すために使用されます。
bool DetailsDialog::sendOffers()
{
return offersCheckBox->isChecked();
}verify() 関数は、ユーザーがDetailsDialog に入力した詳細情報を検証するために追加で実装されたスロットです。入力された詳細情報が不完全な場合、QMessageBox が表示され、ユーザーにはDetailsDialog を破棄するオプションが提供されます。それ以外の場合は、詳細情報が受け入れられ、accept() 関数が呼び出されます。
void DetailsDialog::verify()
{
if (!nameEdit->text().isEmpty() && !addressEdit->toPlainText().isEmpty()) {
accept();
return;
}
QMessageBox::StandardButton answer;
answer = QMessageBox::warning(this, tr("Incomplete Form"),
tr("The form does not contain all the necessary information.\n"
"Do you want to discard it?"),
QMessageBox::Yes | QMessageBox::No);
if (answer == QMessageBox::Yes)
reject();
}MainWindow の定義
MainWindow クラスはQMainWindow のサブクラスであり、openDialog() とprintFile() の2つのスロットを実装しています。また、QTabWidget のプライベートインスタンスであるletters を含んでいます。
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
void createSample();
public slots:
void openDialog();
void printFile();
private:
void createLetter(const QString &name, const QString &address,
QList<QPair<QString,int> > orderItems,
bool sendOffers);
QAction *printAction;
QTabWidget *letters;
};MainWindow の実装
MainWindow のコンストラクタは、fileMenu と、必要なアクションであるnewAction およびprintAction を設定します。これらのアクションのtriggered() シグナルは、追加で実装されたopenDialog()スロットおよびデフォルトのclose()スロットに接続されています。QTabWidget (letters )がインスタンス化され、ウィンドウの中央ウィジェットとして設定されます。
MainWindow::MainWindow()
{
QMenu *fileMenu = new QMenu(tr("&File"), this);
QAction *newAction = fileMenu->addAction(tr("&New..."));
newAction->setShortcuts(QKeySequence::New);
printAction = fileMenu->addAction(tr("&Print..."), this, &MainWindow::printFile);
printAction->setShortcuts(QKeySequence::Print);
printAction->setEnabled(false);
QAction *quitAction = fileMenu->addAction(tr("E&xit"));
quitAction->setShortcuts(QKeySequence::Quit);
menuBar()->addMenu(fileMenu);
letters = new QTabWidget;
connect(newAction, &QAction::triggered, this, &MainWindow::openDialog);
connect(quitAction, &QAction::triggered, this, &MainWindow::close);
setCentralWidget(letters);
setWindowTitle(tr("Order Form"));
}createLetter() 関数は、QTextEdit (editor )を親とする新しいQTabWidget を作成します。この関数は、editor を「埋める」ために、DetailsDialog を通じて取得した4つのパラメータを受け取ります。
void MainWindow::createLetter(const QString &name, const QString &address,
QList<QPair<QString,int> > orderItems,
bool sendOffers)
{
QTextEdit *editor = new QTextEdit;
int tabIndex = letters->addTab(editor, name);
letters->setCurrentIndex(tabIndex);次に、QTextEdit::textCursor() を使用して、editor のカーソルを取得します。その後、QTextCursor::Start を使用して、cursor をドキュメントの先頭に移動させます。
QTextCursor cursor(editor->textCursor());
cursor.movePosition(QTextCursor::Start);リッチテキスト文書の構造を思い出してください。フレームや表のシーケンスは常にテキストブロックによって区切られており、その中には情報が含まれていないものもあります。
注文フォームの例の場合、この部分のドキュメント構造は以下の表に示されています:
| 参照フレーム形式を持つフレーム | |
| ブロック | A company |
| ブロック | |
| ブロック | 321 City Street |
| ブロック | |
| ブロック | Industry Park |
| ブロック | |
| ブロック | Another country |
これは、以下のコードによって実現されます:
QTextFrame *topFrame = cursor.currentFrame();
QTextFrameFormat topFrameFormat = topFrame->frameFormat();
topFrameFormat.setPadding(16);
topFrame->setFrameFormat(topFrameFormat);
QTextCharFormat textFormat;
QTextCharFormat boldFormat;
boldFormat.setFontWeight(QFont::Bold);
QTextFrameFormat referenceFrameFormat;
referenceFrameFormat.setBorder(1);
referenceFrameFormat.setPadding(8);
referenceFrameFormat.setPosition(QTextFrameFormat::FloatRight);
referenceFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 40));
cursor.insertFrame(referenceFrameFormat);
cursor.insertText("A company", boldFormat);
cursor.insertBlock();
cursor.insertText("321 City Street");
cursor.insertBlock();
cursor.insertText("Industry Park");
cursor.insertBlock();
cursor.insertText("Another country");なお、topFrame はeditor の最上位フレームであり、ドキュメント構造には表示されません。
次に、cursor の位置をtopFrame 内の最後の位置に戻し、コンストラクタから提供された顧客の名前と住所を入力します。これには、範囲ベースの for ループを使用してQString 、address を順に処理します。
cursor.setPosition(topFrame->lastPosition());
cursor.insertText(name, textFormat);
const QStringList lines = address.split('\n');
for (const QString &line : lines) {
cursor.insertBlock();
cursor.insertText(line);
}これで、cursor はtopFrame に戻り、上記のコード部分のドキュメント構造は次のようになります:
| block | Donald |
| block | 47338 Park Avenue |
| ブロック | Big City |
スペース調整のため、insertBlock()を2回呼び出します。currentDate()を取得して表示します。setWidth()を使用してbodyFrameFormat の幅を広げ、その幅で新しいフレームを挿入します。
cursor.insertBlock();
cursor.insertBlock();
QDate date = QDate::currentDate();
cursor.insertText(tr("Date: %1").arg(date.toString("d MMMM yyyy")),
textFormat);
cursor.insertBlock();
QTextFrameFormat bodyFrameFormat;
bodyFrameFormat.setWidth(QTextLength(QTextLength::PercentageLength, 100));
cursor.insertFrame(bodyFrameFormat);次のコードは、注文フォームに標準テキストを挿入します。
cursor.insertText(tr("I would like to place an order for the following "
"items:"), textFormat);
cursor.insertBlock();
cursor.insertBlock();ドキュメント構造のこの部分には、日付、bodyFrameFormat を含むフレーム、および標準テキストが含まれるようになりました。
| ブロック | |
| ブロックブロック | |
| ブロックブロック | Date: 25 May 2007 |
| block | |
| bodyFrameFormatを持つフレーム | |
| ブロック | I would like to place an order for the following items: |
| ブロック | |
| ブロック |
QTextTableFormat オブジェクト(orderTableFormat )は、アイテムの種類と注文数量を保持するために使用されます。
QTextTableFormat orderTableFormat;
orderTableFormat.setAlignment(Qt::AlignHCenter);
QTextTable *orderTable = cursor.insertTable(1, 2, orderTableFormat);
QTextFrameFormat orderFrameFormat = cursor.currentFrame()->frameFormat();
orderFrameFormat.setBorder(1);
cursor.currentFrame()->setFrameFormat(orderFrameFormat);cellAt() を使用して、orderTable のヘッダーを設定します。
cursor = orderTable->cellAt(0, 0).firstCursorPosition();
cursor.insertText(tr("Product"), boldFormat);
cursor = orderTable->cellAt(0, 1).firstCursorPosition();
cursor.insertText(tr("Quantity"), boldFormat);次に、QPair オブジェクトのQList を反復処理して、orderTable にデータを入力します。
for (int i = 0; i < orderItems.count(); ++i) {
QPair<QString,int> item = orderItems[i];
int row = orderTable->rows();
orderTable->insertRows(row, 1);
cursor = orderTable->cellAt(row, 0).firstCursorPosition();
cursor.insertText(item.first, textFormat);
cursor = orderTable->cellAt(row, 1).firstCursorPosition();
cursor.insertText(QString("%1").arg(item.second), textFormat);
}このセクションの最終的なドキュメント構造は次のようになります:
orderTable orderTableFormatを使用した場合 | |
| block | Product |
| block | Quantity |
| block | T-shirt |
| ブロック | 4 |
| ブロック | Badge |
| ブロック | 3 |
| ブロック | Reference book |
| ブロック | 2 |
| ブロック | Coffee cup |
| ブロック | 5 |
その後、cursor はtopFrame のlastPosition()に戻され、さらに標準的なテキストが挿入されます。
cursor.setPosition(topFrame->lastPosition());
cursor.insertBlock();
cursor.insertText(tr("Please update my records to take account of the "
"following privacy information:"));
cursor.insertBlock();オファーに関する顧客の好みを表示するために、もう1つのQTextTable が挿入されます。
QTextTable *offersTable = cursor.insertTable(2, 2);
cursor = offersTable->cellAt(0, 1).firstCursorPosition();
cursor.insertText(tr("I want to receive more information about your "
"company's products and special offers."), textFormat);
cursor = offersTable->cellAt(1, 1).firstCursorPosition();
cursor.insertText(tr("I do not want to receive any promotional information "
"from your company."), textFormat);
if (sendOffers)
cursor = offersTable->cellAt(0, 0).firstCursorPosition();
else
cursor = offersTable->cellAt(1, 0).firstCursorPosition();
cursor.insertText("X", boldFormat);この部分のドキュメント構造は次のとおりです:
| block | |
| block | Please update my... |
| block | |
offersTable | |
| block | I want to receive... |
| ブロック | I do not want to receive... |
| ブロック | X |
「cursor 」を移動し、顧客名とともに「Sincerely」を挿入します。余白調整のために、さらにブロックを挿入します。「printAction 」を有効にし、注文書を印刷できるようになったことを示します。
cursor.setPosition(topFrame->lastPosition());
cursor.insertBlock();
cursor.insertText(tr("Sincerely,"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
cursor.insertBlock();
cursor.insertText(name);
printAction->setEnabled(true);
}文書構造の下部は以下の通りです:
| ブロック | |
| ブロック | Sincerely, |
| ブロック | |
| ブロック | |
| ブロック | |
| ブロック | Donald |
createSample() 関数は、サンプル注文フォームを作成するための説明用として使用されます。
void MainWindow::createSample()
{
DetailsDialog dialog("Dialog with default values", this);
createLetter("Mr. Smith", "12 High Street\nSmall Town\nThis country",
dialog.orderItems(), true);
}openDialog() 関数は、DetailsDialog オブジェクトを開きます。dialog 内の詳細が承認された場合、dialog から抽出されたパラメータを使用して、createLetter() 関数が呼び出されます。
void MainWindow::openDialog()
{
DetailsDialog dialog(tr("Enter Customer Details"), this);
if (dialog.exec() == QDialog::Accepted) {
createLetter(dialog.senderName(), dialog.senderAddress(),
dialog.orderItems(), dialog.sendOffers());
}
}注文フォームを出力するために、以下に示すように、printFile() 関数が用意されています。
void MainWindow::printFile()
{
#if defined(QT_PRINTSUPPORT_LIB) && QT_CONFIG(printdialog)
QTextEdit *editor = static_cast<QTextEdit*>(letters->currentWidget());
QPrinter printer;
QPrintDialog dialog(&printer, this);
dialog.setWindowTitle(tr("Print Document"));
if (editor->textCursor().hasSelection())
dialog.setOption(QAbstractPrintDialog::PrintSelection);
if (dialog.exec() != QDialog::Accepted) {
return;
}
editor->print(&printer);
#endif
}この関数では、ドキュメント全体を印刷する代わりに、QTextCursor::hasSelection() を使用して選択した領域のみを印刷することも可能です。
main() 関数
main() 関数は、MainWindow をインスタンス化し、そのサイズを 640x480 ピクセルに設定してから、show() 関数およびcreateSample() 関数を呼び出します。
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.resize(640, 480);
window.show();
window.createSample();
return app.exec();
}© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.