Auf dieser Seite

Beispiel für ein Bestellformular

Das Beispiel „Bestellformular“ zeigt, wie Rich-Text-Dokumente durch die Kombination einer einfachen Vorlage mit den vom Benutzer in einem Dialogfeld eingegebenen Daten erstellt werden können.

Anwendung, die ein ausgefülltes Bestellformular für einen Kunden anzeigt

Definition des DetailsDialog

Die Klasse „ DetailsDialog “ ist eine Unterklasse von „ QDialog “ und implementiert einen Slot „ verify() “, um die spätere Überprüfung des Inhalts des „ DetailsDialog “ zu ermöglichen. Dies wird in der Implementierung von „ DetailsDialog “ näher erläutert.

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;
};

Der Konstruktor von ` DetailsDialog ` akzeptiert die Parameter ` title ` und ` parent`. Die Klasse definiert vier Getter-Funktionen: ` orderItems()`, ` senderName()`, ` senderAddress()` und ` sendOffers() `, um den externen Zugriff auf die Daten zu ermöglichen.

Die Klassendefinition enthält Eingabe-Widgets für die Pflichtfelder: „ nameEdit “ und „ addressEdit “. Außerdem werden ein „ QCheckBox “ und ein „ QDialogButtonBox “ definiert; ersterer, um dem Benutzer die Möglichkeit zu geben, Informationen zu Produkten und Angeboten zu erhalten, und letzterer, um sicherzustellen, dass die verwendeten Schaltflächen entsprechend der nativen Plattform des Benutzers angeordnet werden. Darüber hinaus wird ein „ QTableWidget “, „ itemsTable “, verwendet, um Bestelldetails zu speichern.

Der folgende Screenshot zeigt den „ DetailsDialog “, den wir erstellen möchten.

Dialogfeld zur Eingabe von Kundenauftragsdaten

Implementierung von „DetailsDialog“

Der Konstruktor von ` DetailsDialog ` instanziiert die zuvor definierten Felder und ihre jeweiligen Beschriftungen. Die Beschriftung für ` offersCheckBox ` wird festgelegt, und die Funktion ` setupItemsTable() ` wird aufgerufen, um ` itemsTable` einzurichten und zu füllen. Das ` QDialogButtonBox `-Objekt, ` buttonBox`, wird mit den Schaltflächen ` OK ` und ` Cancel ` instanziiert. Die Signale ` accepted() ` und ` rejected() ` dieses ` buttonBox` werden mit den Slots ` verify() ` und ` reject() ` in ` DetailsDialog` verbunden.

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);

Ein „ QGridLayout “ wird verwendet, um alle Objekte auf der „ DetailsDialog “ zu platzieren.

    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);
}

Die Funktion „ setupItemsTable() “ instanziiert das Objekt „ QTableWidget “ ( itemsTable) und legt die Anzahl der Zeilen anhand des Objekts „ QStringList “ ( items) fest, das den Typ der bestellten Artikel enthält. Die Anzahl der Spalten wird auf 2 festgelegt, wodurch ein Layout mit den Spalten „name“ und „quantity“ entsteht. Eine „ for “-Schleife wird verwendet, um das „ itemsTable “ zu füllen, und das Flag des Elements „ name “ wird auf „ Qt::ItemIsEnabled “ oder „ Qt::ItemIsSelectable “ gesetzt. Zu Demonstrationszwecken wird das Element „ quantity “ auf 1 gesetzt, und alle Elemente im „ itemsTable “ weisen diesen Wert für die Menge auf; dies kann jedoch durch Bearbeiten des Zellinhalts zur Laufzeit geändert werden.

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);
    }
}

Die Funktion „ orderItems() “ extrahiert Daten aus der „ itemsTable “ und gibt sie in der Form „ QList<QPair<QString,int>>“ zurück, wobei jedes „ QPair “ einem Artikel und der bestellten Menge entspricht.

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;
}

Die Funktion „ senderName() “ wird verwendet, um den Wert des Feldes „ QLineEdit “ zurückzugeben, in dem das Namensfeld für das Bestellformular gespeichert ist.

QString DetailsDialog::senderName() const
{
    return nameEdit->text();
}

Die Funktion „ senderAddress() “ wird verwendet, um den Wert des „ QTextEdit “ zurückzugeben, der die Adresse für das Bestellformular enthält.

QString DetailsDialog::senderAddress() const
{
    return addressEdit->toPlainText();
}

Die Funktion „ sendOffers() “ dient dazu, einen Wert des „ true “ oder „ false “ zurückzugeben, anhand dessen ermittelt wird, ob der Kunde im Bestellformular weitere Informationen zu den Angeboten und Werbeaktionen des Unternehmens erhalten möchte.

bool DetailsDialog::sendOffers()
{
    return offersCheckBox->isChecked();
}

Die Funktion „ verify() “ ist ein zusätzlich implementierter Slot, der dazu dient, die vom Benutzer in das „ DetailsDialog “ eingegebenen Daten zu überprüfen. Sind die eingegebenen Daten unvollständig, wird ein „ QMessageBox “ angezeigt, der dem Benutzer die Möglichkeit bietet, das „ DetailsDialog “ zu verwerfen. Andernfalls werden die Daten akzeptiert und die Funktion „ accept() “ aufgerufen.

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();
}

Definition von „MainWindow“

Die Klasse „ MainWindow “ ist eine Unterklasse von „ QMainWindow “ und implementiert zwei Slots: „ openDialog() “ und „ printFile() “. Sie enthält außerdem eine private Instanz von „ QTabWidget “, nämlich „ 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;
};

Implementierung von „MainWindow“

Der Konstruktor „ MainWindow “ richtet das „ fileMenu “ sowie die erforderlichen Aktionen „ newAction “ und „ printAction “ ein. Die „ triggered() “-Signale dieser Aktionen sind mit dem zusätzlich implementierten Slot „openDialog()“ und dem Standard-Slot „close()“ verbunden. Das „ QTabWidget “, „ letters “, wird instanziiert und als zentrales Widget des Fensters festgelegt.

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"));
}

Die Funktion „ createLetter() “ erstellt ein neues „ QTabWidget “ mit einem „ QTextEdit “, „ editor “, als übergeordnetem Element. Diese Funktion akzeptiert vier Parameter, die den über „ DetailsDialog “ erhaltenen Werten entsprechen, um das „ editor “ zu „füllen“.

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);

Anschließend erhalten wir den Cursor für das „ editor “ mithilfe von ` QTextEdit::textCursor()`. Das „ cursor “ wird dann mit ` QTextCursor::Start` an den Anfang des Dokuments verschoben.

    QTextCursor cursor(editor->textCursor());
    cursor.movePosition(QTextCursor::Start);

Erinnern Sie sich an die Struktur eines Rich-Text-Dokuments, in dem Abfolgen von Rahmen und Tabellen stets durch Textblöcke getrennt sind, von denen einige möglicherweise keine Informationen enthalten.

Im Fall des Bestellformular-Beispiels wird die Dokumentstruktur für diesen Abschnitt durch die folgende Tabelle beschrieben:

Rahmen mit referenceFrameFormat
BlockA company
Block
Block321 City Street
Block
BlockIndustry Park
Block
BlockAnother country

Dies wird mit dem folgenden Code erreicht:

    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");

Beachten Sie, dass „ topFrame “ der oberste Frame des „ editor “ ist und in der Dokumentstruktur nicht angezeigt wird.

Anschließend setzen wir die Position von „ cursor “ wieder auf ihre letzte Position in „ topFrame “ zurück und füllen den Namen des Kunden (vom Konstruktor bereitgestellt) sowie die Adresse ein – mithilfe einer bereichsbasierten for-Schleife, um „ QString “ und „ address “ zu durchlaufen.

    cursor.setPosition(topFrame->lastPosition());

    cursor.insertText(name, textFormat);
    const QStringList lines = address.split('\n');
    for (const QString &line : lines) {
        cursor.insertBlock();
        cursor.insertText(line);
    }

Die ` cursor ` befindet sich nun wieder in ` topFrame ` und die Dokumentstruktur für den obigen Codeabschnitt lautet:

blockDonald
block47338 Park Avenue
BlockBig City

Aus Platzgründen rufen wir „ insertBlock()“ zweimal auf. „ currentDate()“ wird abgerufen und angezeigt. Mit „ setWidth()“ vergrößern wir die Breite von „ bodyFrameFormat “ und fügen einen neuen Rahmen mit dieser Breite ein.

    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);

Der folgende Code fügt Standardtext in das Bestellformular ein.

    cursor.insertText(tr("I would like to place an order for the following "
                         "items:"), textFormat);
    cursor.insertBlock();
    cursor.insertBlock();

Dieser Teil der Dokumentstruktur enthält nun das Datum, einen Rahmen mit bodyFrameFormat sowie den Standardtext.

Block
block
blockDate: 25 May 2007
Block
Rahmen mit bodyFrameFormat
BlockI would like to place an order for the following items:
Block
Block

Ein „ QTextTableFormat “-Objekt ( orderTableFormat) wird verwendet, um den Artikeltyp und die bestellte Menge zu speichern.

    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);

Wir verwenden ` cellAt()` zum Festlegen der Header für die ` orderTable`-Objekte.

    cursor = orderTable->cellAt(0, 0).firstCursorPosition();
    cursor.insertText(tr("Product"), boldFormat);
    cursor = orderTable->cellAt(0, 1).firstCursorPosition();
    cursor.insertText(tr("Quantity"), boldFormat);

Anschließend durchlaufen wir die ` QList ` der ` QPair `-Objekte, um ` orderTable` zu füllen.

    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);
    }

Die resultierende Dokumentstruktur für diesen Abschnitt lautet:

orderTable mit „orderTableFormat“
blockProduct
blockQuantity
blockT-shirt
Block4
BlockBadge
Block3
BlockReference book
Block2
BlockCoffee cup
Block5

Das „ cursor “ wird dann zurück in die Funktion „ lastPosition()“ von „ topFrame “ verschoben, und es wird weiterer Standardtext eingefügt.

    cursor.setPosition(topFrame->lastPosition());

    cursor.insertBlock();
    cursor.insertText(tr("Please update my records to take account of the "
                         "following privacy information:"));
    cursor.insertBlock();

Ein weiterer „ QTextTable “ wird eingefügt, um die Präferenzen des Kunden in Bezug auf Angebote anzuzeigen.

    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);

Die Dokumentstruktur für diesen Abschnitt lautet:

block
blockPlease update my...
block
offersTable
BlockI want to receive...
BlockI do not want to receive...
BlockX

Die „ cursor “ wird verschoben, um „Mit freundlichen Grüßen“ zusammen mit dem Namen des Kunden einzufügen. Zur Abstandspassung werden weitere Blöcke eingefügt. Die „ printAction “ wird aktiviert, um anzuzeigen, dass ein Bestellformular nun gedruckt werden kann.

    cursor.setPosition(topFrame->lastPosition());
    cursor.insertBlock();
    cursor.insertText(tr("Sincerely,"), textFormat);
    cursor.insertBlock();
    cursor.insertBlock();
    cursor.insertBlock();
    cursor.insertText(name);

    printAction->setEnabled(true);
}

Der untere Teil der Dokumentstruktur lautet:

Block
BlockSincerely,
Block
Block
Block
BlockDonald

Die Funktion „ createSample() “ dient zu Illustrationszwecken, um ein Beispiel für ein Bestellformular zu erstellen.

void MainWindow::createSample()
{
    DetailsDialog dialog("Dialog with default values", this);
    createLetter("Mr. Smith", "12 High Street\nSmall Town\nThis country",
                 dialog.orderItems(), true);
}

Die Funktion „ openDialog() “ öffnet ein „ DetailsDialog “-Objekt. Wenn die Angaben unter „ dialog “ akzeptiert werden, wird die Funktion „ createLetter() “ mit den aus „ dialog “ extrahierten Parametern aufgerufen.

void MainWindow::openDialog()
{
    DetailsDialog dialog(tr("Enter Customer Details"), this);

    if (dialog.exec() == QDialog::Accepted) {
        createLetter(dialog.senderName(), dialog.senderAddress(),
                     dialog.orderItems(), dialog.sendOffers());
    }
}

Um das Bestellformular auszudrucken, wird die Funktion „ printFile() “ wie unten gezeigt eingebunden:

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
}

Diese Funktion ermöglicht es dem Benutzer außerdem, mit ` QTextCursor::hasSelection()` einen ausgewählten Bereich auszudrucken, anstatt das gesamte Dokument auszudrucken.

main() Funktion

Die Funktion „ main() “ instanziiert „ MainWindow “ und legt dessen Größe auf 640 × 480 Pixel fest, bevor sie die Funktionen „ show() “ und „ createSample() “ aufruft.

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MainWindow window;
    window.resize(640, 480);
    window.show();
    window.createSample();
    return app.exec();
}

Beispielprojekt @ code.qt.io

© 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.