Exemple de formulaire 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 la boîte de dialogue DetailsDialog
La classe ` DetailsDialog ` est une sous-classe de ` QDialog`, implémentant un slot ` verify() ` afin de permettre la vérification ultérieure du contenu du ` DetailsDialog `. Ceci est expliqué plus en détail dans la section « Implémentation de ` 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;
};Le constructeur de DetailsDialog accepte les paramètres title et parent. La classe définit quatre fonctions getter: orderItems(), senderName(), senderAddress() et sendOffers() afin de permettre l'accès aux données depuis l'extérieur.
La définition de la classe inclut des widgets de saisie pour les champs obligatoires : nameEdit et addressEdit. De plus, un QCheckBox et un QDialogButtonBox sont définis ; le premier pour offrir à l’utilisateur la possibilité de recevoir des informations sur les produits et les offres, et le second pour garantir que les boutons utilisés soient disposés conformément à la plateforme native de l’utilisateur. Par ailleurs, un QTableWidget, itemsTable, est utilisé pour contenir les détails de la commande.
La capture d’écran ci-dessous présente la boîte de dialogue « DetailsDialog » que nous avons l’intention de créer.

Implémentation de 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 appelée pour configurer et remplir itemsTable. L’objet QDialogButtonBox, buttonBox, est instancié avec les boutons OK et Cancel. Les signaux accepted() et rejected() de ce buttonBox sont connectés aux slots verify() et reject() de 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 mise en page avec les colonnes « nom » et « quantité ». Une boucle « for » est utilisée pour remplir le tableau « itemsTable » et l’indicateur de l’élément « name » est défini sur « Qt::ItemIsEnabled » ou « Qt::ItemIsSelectable ». À des fins de démonstration, l’élément « quantity » est défini sur 1 et tous les éléments de la liste « itemsTable » ont cette valeur pour la quantité ; mais cela peut être modifié en éditant le contenu des cellules lors 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 la table itemsTable et les renvoie sous la forme d’un tableau 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() permet de renvoyer la valeur de la variable QLineEdit, qui stocke le champ « nom » du bon de commande.
QString DetailsDialog::senderName() const
{
return nameEdit->text();
}La fonction senderAddress() est utilisée pour renvoyer la valeur de l’ QTextEdit contenant l’adresse du bon de commande.
QString DetailsDialog::senderAddress() const
{
return addressEdit->toPlainText();
}La fonction sendOffers() permet de renvoyer une valeur de type « true » ou « false » qui sert à déterminer si le client figurant dans le formulaire de commande souhaite recevoir davantage d’informations sur les offres et promotions de l’entreprise.
bool DetailsDialog::sendOffers()
{
return offersCheckBox->isChecked();
}La fonction verify() est un slot supplémentaire implémenté qui sert à vérifier les informations saisies par l’utilisateur dans le champ DetailsDialog. Si les informations saisies sont incomplètes, un message d’erreur QMessageBox s’affiche, offrant à l’utilisateur la possibilité d’annuler la commande DetailsDialog. Dans le cas contraire, les informations sont acceptées et la fonction accept() est appelé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 MainWindow
La classe ` MainWindow ` est une sous-classe de ` QMainWindow`, implémentant 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;
};Implémentation de MainWindow
Le constructeur MainWindow configure l’ 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. L’ QTabWidget, letters, est instancié et défini comme 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 correspondant à ceux obtenus via 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 l’ editor e à l’aide de QTextEdit::textCursor(). L’ cursor e 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 Rich Text, dans lequel 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 de bon de commande, la structure du document pour cette partie est décrite par le tableau ci-dessous :
| cadre avec referenceFrameFormat | |
| bloc | A company |
| bloc | |
| bloc | 321 City Street |
| bloc | |
| bloc | Industry Park |
| bloc | |
| bloc | Another country |
Pour ce faire, utilisez 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 n'apparaît pas dans la structure du document.
Nous remettons 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 une plage pour parcourir QString et 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);
}L'cursor est désormais de retour dans ` topFrame ` et la structure du document pour la partie de code ci-dessus est la suivante :
| block | Donald |
| bloc | 47338 Park Avenue |
| bloc | Big City |
Pour des raisons d’espacement, nous appelons insertBlock() deux fois. La valeur de currentDate() est obtenue et affichée. Nous utilisons setWidth() pour augmenter la largeur de bodyFrameFormat et nous insérons un nouveau cadre avec 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 du 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 désormais la date, un cadre avec bodyFrameFormat, ainsi que le texte standard.
| bloc | |
| bloc | |
| bloc | Date: 25 May 2007 |
| bloc | |
| encadré 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 parcourons la collection QList d'objets 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 obtenue pour cette section est la suivante :
orderTable avec orderTableFormat | |
| block | Product |
| block | Quantity |
| bloc | T-shirt |
| bloc | 4 |
| bloc | Badge |
| bloc | 3 |
| bloc | Reference book |
| bloc | 2 |
| bloc | Coffee cup |
| bloc | 5 |
L'cursor est ensuite renvoyée vers la méthode lastPosition() de topFrame et du texte plus standard 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é, afin d’afficher les préférences du client concernant les 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 |
L'cursor ion est déplacée pour insérer « Cordialement » ainsi que le nom du client. D'autres blocs sont insérés à des fins d'espacement. L'printAction ion est activée pour indiquer qu'un bon de commande peut désormais ê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 se présente comme suit :
| bloc | |
| bloc | Sincerely, |
| bloc | |
| bloc | |
| bloc | |
| bloc | Donald |
La fonction createSample() est utilisée à titre 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 appelé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());
}
}Afin d’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’intégralité du document.
main() Fonction
La fonction ` main() ` instancie ` MainWindow ` et définit sa taille à 640 × 480 pixels avant d’appeler 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.