目录名字
Qt Dock Widgets 官方示例的翻译
Dock Widgets Example 介绍:
Dock Widgets 示例程序描述的有两个技术要点:
- 1、如何添加Dock 窗体到应用程序中。
- 2、如何使用Qt的富文本引擎。
该示例应用程序描述的是一个简单的处理商业邮件的模板程序。在两个Dock 窗体中分别显示了客户的信息 和 常用语。通过单击Dock中的列表,将自定添加选中的信息添加到邮件模板中。当然,撤销按钮可以撤去邮件模板中错误的或者不需要的信息。一旦邮件完成,可以直接答应或者保存为HTML格式。
MainWindow Class 定义:
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow();
private slots:
void newLetter();
void save();
void print();
void undo();
void about();
void insertCustomer(const QString &customer);
void addParagraph(const QString ¶graph);
private:
void createActions();
void createStatusBar();
void createDockWindows();
QTextEdit *textEdit;
QListWidget *customerList;
QListWidget *paragraphsList;
QMenu *viewMenu;
};
接着,我们来一个个来了解每个函数的功能。
MainWindow Class 关联的相关头文件
#include
#if defined(QT_PRINTSUPPORT_LIB)
#include <QtPrintSupport/qtprintsupportglobal.h>
#if QT_CONFIG(printdialog)
#include
#endif
#endif
#include “mainwindow.h”
相关函数功能的介绍:
一开始我们包含了 ,QWidget类是所有用户界面对象的基类。我们同样需要包含mainwindow.h
MainWindow::MainWindow()
: textEdit(new QTextEdit)
{
setCentralWidget(textEdit);
createActions();
createStatusBar();
createDockWindows();
setWindowTitle(tr("Dock Widgets"));
newLetter();
setUnifiedTitleAndToolBarOnMac(true);
}
在该构造函数中,我们一开始就创建了QTextEdit Widget。 然后我们调用QMainWindow::setCentralWidget()。 该函数会将 QTextEdit 的所有权传递给 MainWindow ,同时QTextEdit 会占据MainWindow 的中央区域。
然后我们调用 createActions(), createMenus(), createToolBars(), createStatusBar(), and createDockWindows() 来初始化窗体.。
最后,我们调用 setWindowTitle() 来给用用程序设定一个名称, newLetter() 来创建一个邮件模板。
我们 调用 createActions(), createMenus(), createToolBars(), and createStatusBar() 函数,是为了保持和其他的Qt示例程序的风格保持一致。
void MainWindow::createDockWindows()
{
QDockWidget *dock = new QDockWidget(tr("Customers"), this);
dock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
customerList = new QListWidget(dock);
customerList->addItems(QStringList()
<< "John Doe, Harmony Enterprises, 12 Lakeside, Ambleton"
<< "Jane Doe, Memorabilia, 23 Watersedge, Beaton"
<< "Tammy Shea, Tiblanka, 38 Sea Views, Carlton"
<< "Tim Sheen, Caraba Gifts, 48 Ocean Way, Deal"
<< "Sol Harvey, Chicos Coffee, 53 New Springs, Eccleston"
<< "Sally Hobart, Tiroli Tea, 67 Long River, Fedula");
dock->setWidget(customerList);
addDockWidget(Qt::RightDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
dock = new QDockWidget(tr("Paragraphs"), this);
paragraphsList = new QListWidget(dock);
paragraphsList->addItems(QStringList()
<< "Thank you for your payment which we have received today."
<< "Your order has been dispatched and should be with you "
"within 28 days."
<< "We have dispatched those items that were in stock. The "
"rest of your order will be dispatched once all the "
"remaining items have arrived at our warehouse. No "
"additional shipping charges will be made."
<< "You made a small overpayment (less than $5) which we "
"will keep on account for you, or return at your request."
<< "You made a small underpayment (less than $1), but we have "
"sent your order anyway. We'll add this underpayment to "
"your next bill."
<< "Unfortunately you did not send enough money. Please remit "
"an additional $. Your order will be dispatched as soon as "
"the complete amount has been received."
<< "You made an overpayment (more than $5). Do you wish to "
"buy more items, or should we return the excess to you?");
dock->setWidget(paragraphsList);
addDockWidget(Qt::RightDockWidgetArea, dock);
viewMenu->addAction(dock->toggleViewAction());
connect(customerList, &QListWidget::currentTextChanged,
this, &MainWindow::insertCustomer);
connect(paragraphsList, &QListWidget::currentTextChanged,
this, &MainWindow::addParagraph);
}
我们创建一个关于客户信息的Dock 窗体,设定了该窗体的标题,我们同时传递“this”指针,这样就指定了MainWindows为父窗体。一般情况下,我们不需要传递,因为当Widgets 陈列出时, 是自动继承父窗体的,但是Dock 窗体是个例外,因为它不是通过layouts 的方式来陈列的。
我们选择限制这个客户信息的Dock 窗体只能显示在左边和右边的Dock区域。关于Dock区域的图示,请看下图:
用户可以通过鼠标的拓展将Dock 移出,而变成一个自由窗体。通过QDockWidget::setFeatures()来设置Dock窗体是可移动的还是不可移动。
一旦我们创建好了Dock 窗体,创建好了list窗体,并指定list窗体的父窗体为Dock窗体,那么最后我们就可以调用addDockWidget()添加Dock 窗体到MainWindows 窗体中了。
我们依照同样的过程可以创建另一个Dock 窗体,这次我们不限定该窗体的区域位置。
最后,我们通过信号槽事件。关联信号currentTextChanged() ,到两个槽 insertCustomer() ,addParagraph() 。
接着,我们来讨论剩余的其他一些函数的实现。
void MainWindow::newLetter()
{
textEdit->clear();
QTextCursor cursor(textEdit->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);
QTextCharFormat italicFormat;
italicFormat.setFontItalic(true);
QTextTableFormat tableFormat;
tableFormat.setBorder(1);
tableFormat.setCellPadding(16);
tableFormat.setAlignment(Qt::AlignRight);
cursor.insertTable(1, 1, tableFormat);
cursor.insertText("The Firm", boldFormat);
cursor.insertBlock();
cursor.insertText("321 City Street", textFormat);
cursor.insertBlock();
cursor.insertText("Industry Park");
cursor.insertBlock();
cursor.insertText("Some Country");
cursor.setPosition(topFrame->lastPosition());
cursor.insertText(QDate::currentDate().toString("d MMMM yyyy"), textFormat);
cursor.insertBlock();
cursor.insertBlock();
cursor.insertText("Dear ", textFormat);
cursor.insertText("NAME", italicFormat);
cursor.insertText(",", textFormat);
for (int i = 0; i < 3; ++i)
cursor.insertBlock();
cursor.insertText(tr("Yours sincerely,"), textFormat);
for (int i = 0; i < 3; ++i)
cursor.insertBlock();
cursor.insertText("The Boss", textFormat);
cursor.insertBlock();
cursor.insertText("ADDRESS", italicFormat);
}
在该函数中,我们清空了QTextEdit。接着我们创建了一个QTextCursor ,我们移动光标到文档的开始处,创建并格式化一个frame。 我们创建一些字符格式和一个表格格式。我们插入一个表格到文档中,并参照上满的格式插入公司名和地址到表格中。接着我们插入包含标记NAME和ADDRESS的邮件“骨架”,我们用“Yours sincerely”,也作为一个标记。
void MainWindow::insertCustomer(const QString &customer)
{
if (customer.isEmpty())
return;
QStringList customerList = customer.split(", ");
QTextDocument *document = textEdit->document();
QTextCursor cursor = document->find("NAME");
if (!cursor.isNull()) {
cursor.beginEditBlock();
cursor.insertText(customerList.at(0));
QTextCursor oldcursor = cursor;
cursor = document->find("ADDRESS");
if (!cursor.isNull()) {
for (int i = 1; i < customerList.size(); ++i) {
cursor.insertBlock();
cursor.insertText(customerList.at(i));
}
cursor.endEditBlock();
}
else
oldcursor.endEditBlock();
}
}
如果用户单击了客户信息的Dock, 会分割关于客户的信息。然后我们查找标记“NAME”,在该标记中插入客户的命名,同样的,我们查找标记“ADDRESS”,并将此标记替代为客户的地址。
值得注意的是:我们将所有的插入放置在beginEditBlock() 和endEditBlock() 这两个函数之间。
void MainWindow::addParagraph(const QString ¶graph)
{
if (paragraph.isEmpty())
return;
QTextDocument *document = textEdit->document();
QTextCursor cursor = document->find(tr("Yours sincerely,"));
if (cursor.isNull())
return;
cursor.beginEditBlock();
cursor.movePosition(QTextCursor::PreviousBlock, QTextCursor::MoveAnchor, 2);
cursor.insertBlock();
cursor.insertText(paragraph);
cursor.insertBlock();
cursor.endEditBlock();
}
该函数的功能类似于insertCustomer(). 首先我们寻找标记,这里的标记是“Yours sincerely”,然后在在标记前,插入单击选中的段落文本。同样的这里我们调用beginEditBlock() … endEditBlock()函数对,以便于我们撤销时,把整段添加的都一并撤销。
void MainWindow::print()
{
#if QT_CONFIG(printdialog)
QTextDocument *document = textEdit->document();
QPrinter printer;
QPrintDialog dlg(&printer, this);
if (dlg.exec() != QDialog::Accepted) {
return;
}
document->print(&printer);
statusBar()->showMessage(tr("Ready"), 2000);
#endif
}
可以看到,Qt 的QTextDocument 类调用打印文档也非常简单。
void MainWindow::save()
{
QMimeDatabase mimeDatabase;
QString fileName = QFileDialog::getSaveFileName(this,
tr("Choose a file name"), ".",
mimeDatabase.mimeTypeForName("text/html").filterString());
if (fileName.isEmpty())
return;
QFile file(fileName);
if (!file.open(QFile::WriteOnly | QFile::Text)) {
QMessageBox::warning(this, tr("Dock Widgets"),
tr("Cannot write file %1:\n%2.")
.arg(QDir::toNativeSeparators(fileName), file.errorString()));
return;
}
QTextStream out(&file);
QGuiApplication::setOverrideCursor(Qt::WaitCursor);
out << textEdit->toHtml();
QGuiApplication::restoreOverrideCursor();
statusBar()->showMessage(tr("Saved '%1'").arg(fileName), 2000);
}
QTextEdit 提供输出HTML格式的文档。
void MainWindow::undo()
{
QTextDocument *document = textEdit->document();
document->undo();
}
如果窗体的焦点放置在QTextEdit,可以通过撤销功能来撤销删除之前添加的文本。
总结:
1、官方给定的示例对DockWidget 的使用做了简单介绍。
2、富文本的应用这里也有涉及到。
3、按照该示例程序的介绍可以很好的训练程序思维。
总之,按部就班的学习示例程序是学好Qt的一项基本策略。
ps:翻译有不当之处,请读者们多多指点,本人纯粹是为了项目和学习的需要,才斗胆拙笔成文。