주문 양식 예시
'주문 양식' 예제는 간단한 템플릿과 대화 상자에서 사용자가 입력한 데이터를 결합하여 서식 있는 텍스트 문서를 생성하는 방법을 보여줍니다.

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() 등 네 가지 게터 함수를 정의합니다.
이 클래스 정의에는 필수 입력 필드인 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 는 하나의 품목과 주문 수량을 나타냅니다.
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() 라는 두 개의 슬롯을 구현합니다. 또한 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 를 통해 얻은 값에 해당하는 네 개의 매개변수를 받아들입니다.
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);리치 텍스트 문서의 구조를 상기해 보십시오. 프레임과 표의 시퀀스는 항상 텍스트 블록으로 구분되며, 일부 텍스트 블록에는 정보가 포함되지 않을 수도 있습니다.
주문서 예제의 경우, 이 부분의 문서 구조는 아래 표와 같습니다:
| referenceFrameFormat을 가진 프레임 | |
| 블록 | 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 |
| 블록 | 47338 Park Avenue |
| 블록 | Big City |
간격 조정을 위해 insertBlock()를 두 번 호출합니다. 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 |
| 블록 | |
| 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을 사용하여 | |
| 블록 | Product |
| block | Quantity |
| 블록 | 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();제안과 관련된 고객의 선호도를 표시하기 위해 또 다른 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 | Please update my... |
| 블록 | |
offersTable | |
| 블록 | 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.