Exemple de bon de commande
L'exemple de formulaire de commande montre comment générer des documents en texte enrichi en combinant un modèle simple avec des données saisies par l'utilisateur dans une boîte de dialogue.

Définition de DetailsDialog
La classe DetailsDialog est une sous-classe de QDialog, qui implémente un slot verify() permettant de vérifier ultérieurement le contenu de DetailsDialog. Ceci est expliqué plus en détail dans DetailsDialog Implementation.
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; };
Le constructeur de DetailsDialog accepte les paramètres title et parent. La classe définit quatre fonctions getter: orderItems() senderName() , senderAddress() et sendOffers() pour permettre l'accès externe aux données.
La définition de la classe inclut des widgets de saisie pour les champs obligatoires, nameEdit et addressEdit. En outre, un QCheckBox et un QDialogButtonBox sont définis ; le premier pour permettre à l'utilisateur de recevoir des informations sur les produits et les offres, et le second pour s'assurer que les boutons utilisés sont disposés en fonction de la plateforme native de l'utilisateur. En outre, un QTableWidget, itemsTable, est utilisé pour contenir les détails de la commande.
La capture d'écran ci-dessous montre le site DetailsDialog que nous avons l'intention de créer.

Mise en œuvre du DetailsDialog
Le constructeur de DetailsDialog instancie les champs définis précédemment et leurs étiquettes respectives. L'étiquette de offersCheckBox est définie et la fonction setupItemsTable() est invoquée pour configurer et remplir itemsTable. L'objet QDialogButtonBox, buttonBox, est instancié avec les boutons OK et Cancel. Les signaux accepted() et rejected() de cet objet buttonBox sont connectés aux emplacements verify() et reject() de l'objet DetailsDialog.
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);
Un QGridLayout est utilisé pour placer tous les objets sur le 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); }
La fonction setupItemsTable() instancie l'objet QTableWidget, itemsTable, et définit le nombre de lignes en fonction de l'objet QStringList, items, qui contient le type d'articles commandés. Le nombre de colonnes est fixé à 2, ce qui permet d'obtenir une présentation "nom" et "quantité". Une boucle for est utilisée pour remplir l'objet itemsTable et l'indicateur de l'objet name est défini sur Qt::ItemIsEnabled ou Qt::ItemIsSelectable. À des fins de démonstration, la valeur 1 est attribuée à l'article quantity et tous les articles de itemsTable ont cette valeur pour la quantité ; mais cette valeur peut être modifiée en éditant le contenu des cellules au moment de l'exécution.
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); } }
La fonction orderItems() extrait les données de itemsTable et les renvoie sous la forme d'un QList<QPair<QString,int>> où chaque QPair correspond à un article et à la quantité commandée.
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; }
La fonction senderName() est utilisée pour renvoyer la valeur de QLineEdit utilisée pour stocker le champ du nom pour le formulaire de commande.
QString DetailsDialog::senderName() const { return nameEdit->text(); }
La fonction senderAddress() est utilisée pour renvoyer la valeur de QTextEdit contenant l'adresse du bon de commande.
QString DetailsDialog::senderAddress() const { return addressEdit->toPlainText(); }
La fonction sendOffers() est utilisée pour renvoyer une valeur true ou false qui est utilisée pour déterminer si le client dans le formulaire de commande souhaite recevoir plus d'informations sur les offres et les promotions de l'entreprise.
bool DetailsDialog::sendOffers() { return offersCheckBox->isChecked(); }
La fonction verify() est un slot supplémentaire utilisé pour vérifier les informations saisies par l'utilisateur dans le formulaire DetailsDialog. Si les informations saisies sont incomplètes, un message QMessageBox s'affiche, offrant à l'utilisateur la possibilité de rejeter le formulaire DetailsDialog. Dans le cas contraire, les informations sont acceptées et la fonction accept() est invoquée.
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(); }
Définition de la fenêtre principale
La classe MainWindow est une sous-classe de QMainWindow, qui implémente deux slots - openDialog() et printFile(). Elle contient également une instance privée de 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; };
Mise en œuvre de la fenêtre principale
Le constructeur de MainWindow met en place fileMenu et les actions requises, newAction et printAction. Les signaux triggered() de ces actions sont connectés au slot openDialog() implémenté en plus et au slot close() par défaut. Le QTabWidget, letters, est instancié et défini comme le widget central de la fenêtre.
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")); }
La fonction createLetter() crée un nouveau QTabWidget avec un QTextEdit, editor, comme parent. Cette fonction accepte quatre paramètres qui correspondent à ceux que nous avons obtenus par le biais de DetailsDialog, afin de "remplir" le editor.
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);
Nous obtenons ensuite le curseur de editor à l'aide de QTextEdit::textCursor(). Le cursor est ensuite déplacé au début du document à l'aide de QTextCursor::Start.
QTextCursor cursor(editor->textCursor()); cursor.movePosition(QTextCursor::Start);
Rappelons la structure d'un document en texte enrichi, où les séquences de cadres et de tableaux sont toujours séparées par des blocs de texte, dont certains peuvent ne contenir aucune information.
Dans le cas de l'exemple du formulaire de commande, la structure du document pour cette partie est décrite dans le tableau ci-dessous :
| cadre avec référenceFrameFormat | |
| bloc | A company |
| bloc | |
| bloc | 321 City Street |
| bloc | |
| bloc | Industry Park |
| bloc | |
| bloc | Another country |
Ceci est réalisé avec le code suivant :
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");
Notez que topFrame est le cadre de niveau supérieur de editor et qu'il n'apparaît pas dans la structure du document.
Nous ramenons ensuite la position de cursor à sa dernière position dans topFrame et remplissons le nom du client (fourni par le constructeur) et son adresse - en utilisant une boucle for basée sur l'intervalle pour parcourir les cadres 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); }
Le site cursor est maintenant de retour dans le site topFrame et la structure du document pour la portion de code ci-dessus est la suivante :
| bloc | Donald |
| bloc | 47338 Park Avenue |
| bloc | Big City |
Pour des raisons d'espacement, nous invoquons insertBlock() deux fois. La page currentDate() est obtenue et affichée. Nous utilisons setWidth() pour augmenter la largeur de bodyFrameFormat et nous insérons un nouveau cadre de cette largeur.
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);
Le code suivant insère un texte standard dans le formulaire de commande.
cursor.insertText(tr("I would like to place an order for the following " "items:"), textFormat); cursor.insertBlock(); cursor.insertBlock();
Cette partie de la structure du document contient maintenant la date, un cadre avec bodyFrameFormat, ainsi que le texte standard.
| bloc | |
| bloc | |
| bloc | Date: 25 May 2007 |
| bloc | |
| cadre avec bodyFrameFormat | |
| bloc | I would like to place an order for the following items: |
| bloc | |
| bloc |
Un objet QTextTableFormat, orderTableFormat, est utilisé pour contenir le type d'article et la quantité commandée.
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);
Nous utilisons cellAt() pour définir les en-têtes de l'objet orderTable.
cursor = orderTable->cellAt(0, 0).firstCursorPosition(); cursor.insertText(tr("Product"), boldFormat); cursor = orderTable->cellAt(0, 1).firstCursorPosition(); cursor.insertText(tr("Quantity"), boldFormat);
Ensuite, nous itérons à travers les objets QList de QPair pour remplir 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); }
La structure du document résultant de cette section est la suivante
orderTable avec orderTableFormat | |
| bloc | Product |
| bloc | Quantity |
| bloc | T-shirt |
| bloc | 4 |
| bloc | Badge |
| bloc | 3 |
| bloc | Reference book |
| bloc | 2 |
| bloc | Coffee cup |
| bloc | 5 |
Le site cursor est ensuite déplacé vers le site lastPosition() de topFrame et un texte standard supplémentaire est inséré.
cursor.setPosition(topFrame->lastPosition()); cursor.insertBlock(); cursor.insertText(tr("Please update my records to take account of the " "following privacy information:")); cursor.insertBlock();
Un autre QTextTable est inséré pour indiquer les préférences du client en matière d'offres.
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);
La structure du document pour cette partie est la suivante
| bloc | |
| bloc | Please update my... |
| bloc | |
offersTable | |
| bloc | I want to receive... |
| bloc | I do not want to receive... |
| bloc | X |
Le site cursor est déplacé pour insérer la mention "Cordialement" ainsi que le nom du client. Des blocs supplémentaires sont insérés à des fins d'espacement. L'adresse printAction est activée pour indiquer qu'un bon de commande peut maintenant être imprimé.
cursor.setPosition(topFrame->lastPosition()); cursor.insertBlock(); cursor.insertText(tr("Sincerely,"), textFormat); cursor.insertBlock(); cursor.insertBlock(); cursor.insertBlock(); cursor.insertText(name); printAction->setEnabled(true); }
La partie inférieure de la structure du document est la suivante
| bloc | |
| bloc | Sincerely, |
| bloc | |
| bloc | |
| bloc | |
| bloc | Donald |
La fonction createSample() est utilisée à des fins d'illustration, pour créer un exemple de bon de commande.
void MainWindow::createSample() { DetailsDialog dialog("Dialog with default values", this); createLetter("Mr. Smith", "12 High Street\nSmall Town\nThis country", dialog.orderItems(), true); }
La fonction openDialog() ouvre un objet DetailsDialog. Si les informations contenues dans dialog sont acceptées, la fonction createLetter() est invoquée à l'aide des paramètres extraits de dialog.
void MainWindow::openDialog() { DetailsDialog dialog(tr("Enter Customer Details"), this); if (dialog.exec() == QDialog::Accepted) { createLetter(dialog.senderName(), dialog.senderAddress(), dialog.orderItems(), dialog.sendOffers()); } }
Pour imprimer le bon de commande, une fonction printFile() est incluse, comme indiqué ci-dessous :
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 }
Cette fonction permet également à l'utilisateur d'imprimer une zone sélectionnée à l'aide de QTextCursor::hasSelection(), au lieu d'imprimer l'ensemble du document.
main() Fonction
La fonction main() instancie MainWindow et définit sa taille à 640x480 pixels avant d'invoquer les fonctions show() et 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.