示例演示如何通过在对话框中输入的数据生成富文本文档的订单报表。
DetailsDialog类是QDialog的子类,它实现了一个slot verify()来允许稍后验证DetailsDialog的内容。这将在DetailsDialog实现中进一步解释。
DetailsDialog的构造函数接受参数title和parent。该类定义了四个getter函数:orderItems()、senderName()、senderAddress()和sendOffers(),以允许外部访问数据。
类定义包括所需字段的input widgets : nameEdit和addressEdit。定义了QCheckBox和QDialogButtonBox;前者为用户提供接收产品和报价信息的选项,后者确保所使用的按钮是根据用户的本地平台安排的。此外,QTableWidget *itemsTable用于保存订单详细信息。
QT_BEGIN_NAMESPACE
class QCheckBox;
class QDialogButtonBox;
class QLabel;
class QLineEdit;
class QTableWidget;
class QTextEdit;
class QWidget;
QT_END_NAMESPACE
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;
};
DetailsDialog的构造函数实例化前面定义的字段及其各自的标签。设置offersCheckBox的标签,并调用setupItemsTable()函数来设置和填充itemsTable。用OK和Cancel按钮实例化QDialogButtonBox对象buttonBox。此按钮框的accept()和reject()信号连接到DetailsDialog中的verify()和reject()插槽。
#include
#include "detailsdialog.h"
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, SIGNAL(accepted()), this, SLOT(verify()));
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
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);
}
//函数的作用是:实例化QTableWidget对象itemsTable,并根据QStringList对象items设置行数。
//for循环用于填充itemsTable,名称项的标志设置为Qt::ItemIsEnabled或Qt::ItemIsSelectable。
//为便于演示,将quantity项设置为1,itemsTable中的所有项都具有该值作为quantity;但是这可以通过在运行时编辑单元格的内容来修改。
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);
}
}
//orderItems()函数从itemsTable中提取数据,并以QList>的形式返回数据
//其中每个QPair对应一个项目和所订购的数量。
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;
}
//函数用于返回用于存储订单名称字段的QLineEdit的值。
QString DetailsDialog::senderName() const
{
return nameEdit->text();
}
//函数用于返回包含订单地址的QTextEdit的值。
QString DetailsDialog::senderAddress() const
{
return addressEdit->toPlainText();
}
//用于确定订购表单中的客户是否希望接收关于公司优惠和促销的更多信息。
bool DetailsDialog::sendOffers()
{
return offersCheckBox->isChecked();
}
//用于验证用户输入到DetailsDialog中的详细信息。
//如果输入的详细信息不完整,将显示一个QMessageBox
//QMessageBox为用户提供放弃DetailsDialog的选项,否则,将接受详细信息并调用accept()函数。
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();
}
#include
#include
#include
QT_BEGIN_NAMESPACE
class QAction;
class QTabWidget;
QT_END_NAMESPACE
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;
};
MainWindow构造函数设置fileMenu和所需的操作、newAction和printAction。这些操作的触发()信号连接到另外实现的openDialog()槽和默认的close()槽。QTabWidget letters被实例化并设置为窗口的central widget。
#include
#ifndef QT_NO_PRINTER
#include
#include
#endif
#include "detailsdialog.h"
#include "mainwindow.h"
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, SLOT(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, SIGNAL(triggered()), this, SLOT(openDialog()));
connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
setCentralWidget(letters);
setWindowTitle(tr("Order Form"));
}
//函数的作用是:创建一个新的QTabWidget,它的父类是QTextEdit*editor。
//该函数接受四个参数,这些参数与我们通过DetailsDialog获得的参数相对应,以便“填充”编辑器。
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);
//然后使用QTextEdit::textCursor()获取编辑器的光标。
//然后使用QTextCursor:: start将光标移动到文档的开头。
QTextCursor cursor(editor->textCursor());
cursor.movePosition(QTextCursor::Start);
//富文本结构通过以下代码实现的:
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");
//注意topFrame是编辑器的顶级框架,在文档结构中没有显示。
//我们将光标的位置设置为topFrame中的最后一个位置
//使用foreach循环遍历QString address,并填写客户的姓名(由构造函数提供)和地址
cursor.setPosition(topFrame->lastPosition());
cursor.insertText(name, textFormat);
QString line;
foreach (line, address.split("\n")) {
cursor.insertBlock();
cursor.insertText(line);
}
//出于间隔目的,我们调用insertBlock()两次。获取并显示currentDate()。
//我们使用setWidth()来增加bodyFrameFormat的宽度,并插入一个具有该宽度的新框架
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);
//以下代码将标准文本插入订单表单。
cursor.insertText(tr("I would like to place an order for the following "
"items:"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
//QTextTableFormat对象orderTableFormat用于保存项目的类型和订购的数量。
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);
//使用cellAt()来设置orderTable的标题。
cursor = orderTable->cellAt(0, 0).firstCursorPosition();
cursor.insertText(tr("Product"), boldFormat);
cursor = orderTable->cellAt(0, 1).firstCursorPosition();
cursor.insertText(tr("Quantity"), boldFormat);
//然后迭代QPair对象的QList来填充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);
}
cursor.setPosition(topFrame->lastPosition());
cursor.insertBlock();
cursor.insertText(tr("Please update my records to take account of the "
"following privacy information:"));
cursor.insertBlock();
//插入另一个QTextTable,以显示客户对报价的偏好。
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);
cursor.setPosition(topFrame->lastPosition());
cursor.insertBlock();
cursor.insertText(tr("Sincerely,"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
cursor.insertBlock();
cursor.insertText(name);
printAction->setEnabled(true);
}
//函数的作用是:创建一个示例订单表单
void MainWindow::createSample()
{
DetailsDialog dialog("Dialog with default values", this);
createLetter("Mr. Smith", "12 High Street\nSmall Town\nThis country",
dialog.orderItems(), true);
}
//函数的作用是:打开一个DetailsDialog对象。
//如果对话框中的细节被接受,则使用从对话框中提取的参数调用createLetter()函数。
void MainWindow::openDialog()
{
DetailsDialog dialog(tr("Enter Customer Details"), this);
if (dialog.exec() == QDialog::Accepted) {
createLetter(dialog.senderName(), dialog.senderAddress(),
dialog.orderItems(), dialog.sendOffers());
}
}
//为了打印出订单,包含了printFile()函数
//该函数还允许用户使用QTextCursor::hasSelection()打印选定区域,而不是打印整个文档。
void MainWindow::printFile()
{
#if !defined(QT_NO_PRINTER) && !defined(QT_NO_PRINTDIALOG)
QTextEdit *editor = static_cast<QTextEdit*>(letters->currentWidget());
QPrinter printer;
QPrintDialog dialog(&printer, this);
dialog.setWindowTitle(tr("Print Document"));
if (editor->textCursor().hasSelection())
dialog.addEnabledOption(QAbstractPrintDialog::PrintSelection);
if (dialog.exec() != QDialog::Accepted) {
return;
}
editor->print(&printer);
#endif
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
MainWindow window;
window.resize(640, 480);
window.show();
window.createSample();
return app.exec();
}