Beispiel für ein Bestellformular

Das Beispiel des Bestellformulars zeigt, wie man Rich-Text-Dokumente durch die Kombination einer einfachen Vorlage mit den vom Benutzer in einem Dialog eingegebenen Daten erzeugt.

DetailsDialog Definition

Die Klasse DetailsDialog ist eine Unterklasse von QDialog und implementiert einen Slot verify(), um den Inhalt von DetailsDialog später zu überprüfen. Dies wird in DetailsDialog Implementierung 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 nimmt die Parameter title und parent entgegen. Die Klasse definiert vier Getter-Funktionen: orderItems(), senderName(), senderAddress() und sendOffers(), um den Zugriff auf Daten von außen zu ermöglichen.

Die Klassendefinition umfasst Eingabe-Widgets für die erforderlichen Felder, nameEdit und addressEdit. Außerdem sind ein QCheckBox und ein QDialogButtonBox definiert; ersteres, um dem Benutzer die Möglichkeit zu geben, Informationen über Produkte und Angebote zu erhalten, und letzteres, um sicherzustellen, dass die verwendeten Schaltflächen entsprechend der nativen Plattform des Benutzers angeordnet sind. Darüber hinaus wird ein QTableWidget, itemsTable, verwendet, um Bestelldaten zu speichern.

Der folgende Screenshot zeigt die DetailsDialog, die wir zu erstellen beabsichtigen.

DetailsDialog Implementierung

Der Konstruktor von DetailsDialog instanziiert die zuvor definierten Felder und ihre jeweiligen Bezeichnungen. Das Label für offersCheckBox wird gesetzt und die Funktion setupItemsTable() wird aufgerufen, um itemsTable einzurichten und zu füllen. Das Objekt QDialogButtonBox, buttonBox, wird mit den Schaltflächen OK und Cancel instanziiert. Die Signale accepted() und rejected() dieses buttonBox sind mit den Steckplätzen 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 dem 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 auf der Grundlage des Objekts QStringList, items, fest, das die Art der bestellten Objekte enthält. Die Anzahl der Spalten wird auf 2 festgelegt, so dass ein Layout mit "Name" und "Menge" entsteht. Eine for -Schleife wird verwendet, um die itemsTable zu füllen, und das Flag des name -Objekts wird auf Qt::ItemIsEnabled oder Qt::ItemIsSelectable gesetzt. Zu Demonstrationszwecken ist das Element quantity auf 1 gesetzt, und alle Elemente in itemsTable haben diesen Wert für die Menge; dies kann jedoch durch Bearbeitung des Inhalts der Zellen 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 itemsTable und gibt sie in Form von 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 QLineEdit zurückzugeben, der zum Speichern des Namensfeldes für das Bestellformular verwendet wird.

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

Mit der Funktion senderAddress() wird der Wert des Feldes QTextEdit zurückgegeben, das die Adresse für das Bestellformular enthält.

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

Mit der Funktion sendOffers() wird ein Wert true oder false zurückgegeben, der verwendet wird, um festzustellen, ob der Kunde im Bestellformular weitere Informationen über die Angebote und Aktionen 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 DetailsDialog eingegebenen Daten zu überprüfen. Wenn die eingegebenen Daten unvollständig sind, wird eine QMessageBox angezeigt, die dem Benutzer die Möglichkeit gibt, die 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();
}

MainWindow Definition

Die Klasse MainWindow ist eine Unterklasse von QMainWindow und implementiert zwei Slots - openDialog() und printFile(). Sie enthält auch eine private Instanz von 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;
};

Implementierung von MainWindow

Der MainWindow -Konstruktor richtet fileMenu und die erforderlichen Aktionen newAction und printAction ein. Die triggered() Signale dieser Aktionen sind mit dem zusätzlich implementierten openDialog() Slot und dem Standard close() Slot 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 Elternteil. Diese Funktion akzeptiert vier Parameter, die denjenigen entsprechen, die wir über DetailsDialog erhalten haben, 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 editor mit QTextEdit::textCursor(). Der cursor wird dann mit QTextCursor::Start an den Anfang des Dokuments gesetzt.

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

Erinnern Sie sich an die Struktur eines Rich-Text-Dokuments, in dem Sequenzen von Rahmen und Tabellen immer durch Textblöcke getrennt sind, von denen einige keine Informationen enthalten können.

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

frame mit referenceFrameFormat
BlockA company
Block
Block321 City Street
block
blockIndustry Park
blockieren
blockAnother country

Dies wird mit folgendem Code bewerkstelligt:

    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 Rahmen von editor ist und nicht in der Dokumentstruktur angezeigt wird.

Dann setzen wir die Position von cursor zurück auf die letzte Position in topFrame und geben den Namen des Kunden (der vom Konstruktor bereitgestellt wird) und die Adresse ein - mit 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 jetzt wieder in topFrame und die Dokumentstruktur für den obigen Teil des Codes ist:

BlockDonald
block47338 Park Avenue
blockBig City

Aus Gründen der Übersichtlichkeit rufen wir insertBlock() zweimal auf. currentDate () wird abgerufen und angezeigt. Wir verwenden setWidth(), um die Breite von bodyFrameFormat zu erhöhen, 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
blockierenI would like to place an order for the following items:
blockieren
block

Ein QTextTableFormat Objekt, orderTableFormat, wird verwendet, um die Art des Artikels 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(), um die Kopfzeilen für orderTable zu setzen.

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

Anschließend werden die Objekte QList von QPair durchlaufen, 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 ist:

orderTable mit orderTableFormat
BlockProduct
BlockQuantity
blockT-shirt
block4
blockierenBadge
blockieren3
blockierenReference book
blockieren2
blockierenCoffee cup
Block5

cursor wird dann zurück zu topFrame's lastPosition() verschoben und mehr Standardtext wird 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 Teil ist:

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. Es werden weitere Blöcke eingefügt, um den Abstand zu vergrößern. 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 ist:

Block
BlockSincerely,
Block
Block
block
BlockDonald

Die Funktion createSample() wird zur Veranschaulichung verwendet, um ein Beispiel-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 Objekt DetailsDialog. Wenn die Angaben in 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 eine Funktion printFile() eingefügt, wie unten gezeigt:

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 auch, einen ausgewählten Bereich mit QTextCursor::hasSelection() zu drucken, anstatt das gesamte Dokument zu drucken.

main() Funktion

Die Funktion main() instanziiert MainWindow und setzt dessen Größe auf 640x480 Pixel, 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

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