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 | |
Block | A company |
Block | |
Block | 321 City Street |
block | |
block | Industry Park |
blockieren | |
block | Another 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:
Block | Donald |
block | 47338 Park Avenue |
block | Big 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 | |
block | Date: 25 May 2007 |
block | |
Rahmen mit bodyFrameFormat | |
blockieren | I 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 | |
Block | Product |
Block | Quantity |
block | T-shirt |
block | 4 |
blockieren | Badge |
blockieren | 3 |
blockieren | Reference book |
blockieren | 2 |
blockieren | Coffee cup |
Block | 5 |
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 | |
Block | Please update my... |
Block | |
offersTable | |
Block | I want to receive... |
block | I do not want to receive... |
Block | X |
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 | |
Block | Sincerely, |
Block | |
Block | |
block | |
Block | Donald |
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(); }
© 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.