一.QTextEdit的使用
rich text是用html标签表示的形式。text edit可以显示plain text(纯文本)和html文件。
setHtml(), toHtml()返回HTML格式中的文本,用来控制内容到html的转换,还有清除内容。
插入内容:insertHtml(), insertPlainText(), append()。
设置当前character的属性: setFontUnderline()(设置字体下划线), setFontFamily()(设置字体类型), setFontPointSize()(设置字体点大小),setCurrentFont()(设置现在的字体).
二.QTextDocument组成
QTextDocument存放结构化的rich text文件,每个元素都有对应的格式对象。可以通过objectForFormat()来通过格式对象查找元素。QTextDocument能够忽略不能理解的标记。
可以通过QTextCursor来编程编辑QTextDocument对象,并对其进行填充。通过rootFrame()方法得到根节点再遍历其中的元素。如果只是浏览其中的文本文
档,就用begin(),end(),findBlock()方法。
文本的格式由documentLayout()决定.metaInformation()来的到文件的元信息。
toPlainText()和toHtml()方法能够得到它text形式的内容和html形式的内容。
在 QTextDocument 类中包括一些通用的元素,例如 QTextBlock(段落),QTextFrame(框架),QTextTable(表格) 和 QTextList(列表) 描述。
图片使用一种特殊的文本片段描述。在更低的层次上,这些元素都有自己的描述属性,如文本风格和对齐方式。
文档的基本构建单位是QTextBlock和QTextFrame。块本身就包含文本片段(QTextFragment),但是这不会直接影响到高层次的文档结构。
框架和表格用于组织其他结构,而文本块则包含真正的文本信息。每一个文档都包括一个根框架(root frame),以及至少一个文本块。
root frame决定显示的方式和布局。框架提供不同文档部分的逻辑分割,同时也提供了在渲染时如何显示的属性。一个表格就是一个特化的
框架,包含分布在不同行和列的多个单元。每个单元都能够包含更多的结构和文本。表格提供了灵活配置单元的管理和布局的特性。
文本块包含文本片段。每一个文本片段都有特定的文本和字符格式信息。文本属性在字符级别和块级别定义。在字符级别可以指定字体、颜
色和大小。在块级别可以指定更高一级的行为,例如文本流方向、对齐方式和背景色。
对文本块分组的是 QTextBlockGroup 的子类,对文本片段和其他元素分组的是 QTextFrame 的子类。
三.开始使用QTextDocument
1.创建富文本
QTextDocument *newDocument = new QTextDocument;
也可以通过已有的文本组件获得:
QTextEdit *editor = new QTextEdit;
QTextDocument *editorDocument = editor->document();
新元素的创建和插入可以通过使用 QTextCursor 以编程的方式实现,或者通过 QTextEdit 以用户可视化编辑的方式实现。元素可以在创建时
指定一个特定的样式,或者是直接使用当前光标所在位置的样式。
QTextDocumentFragment用来保存QTextDocument的任意片段的,可以包含段落,表格,甚至一个完整的QTextDocument。当用户做出选择时,可以通过QTextCursor::selection()来
获取用户选择的内容,它返回一个QTextDocumentFragment。
2.访问根框架
QTextDocument *textDocument;
QTextFrame *root = textDocument->rootFrame();
根框架提供了访问整个文档结构的能力。根下的每个框架都包含一个文本块(可能为空)。
四.元素详解
1.文本块
文本块由 QTextBlock 类提供。除最后一页外的其他也,在最后部分放入一个分页符。通过创建一个新的QTextBlockFormat来实现,并把它的分页策略设置成Page_AlwaysAfter;
QTextCursor::mergeBlockFormat()方法用传递给它的任意非默认设置覆盖当前块格式的设置。QTextCursor::mergeCharFormat()方法,用来合并字符格式的各种设置。
QTextCursor::insertText()可使用任何已起作用的有效格式插入文本。QTextCursor::insertBlock()即可接受文本块格式由可接受字符文本格式。
文本块可以将具有不同字符样式的文本分组,用于表示文档段落。典型的文本块具有若干个不同样式的文本片段。当文本插入文档时,文本块被
创建。在对文档进行编辑时,会增加更多的文本块。在块中,文档通过分割、合并、删除片段,有效地表现不同样式的文本。
qt通常把一个文本块(即便为空)当做一个框架或者表格间的分隔符。
一个文本块中的片段可以通过 QTextBlock::iterator 遍历:
QTextBlock::iterator it;
for(it = currentBlock.begin(); !(it.atEnd()); ++it) {
QTextFragment currentFragment = it.fragment();
if(currentFragment.isValid())
processFragment(currentFragment);
}
}
块自己的样式由 QTextBlockFormat 描述,包括文本对齐方式,缩进和背景色。只要我们有一个文档中的文本块,就可以通过这个文本块对文档中所有文本块以编写顺序进行导航:
QTextBlock currentBlock = textDocument->begin();
while(currentBlock.isValid()) {
processBlock(currentBlock);
currentBlock = currentBlock.next();
}
当你需要导出文档中所有富文本内容时,这个方法就十分有用。因为它会忽略框架、表格以及其他文档结构。
2.框架
框架由 QTextFrame 类提供。0个或多个QTextFragment组成一个文本块,这些文本的属性(字体,下划线等)存储在一个单独的QTextCharFormat中。
文本框架用于组织文本块和子框架。这是一种比段落更大一级的文档结构。框架的格式决定它如何被显示和在页面中的位置。每一个文档都有一个根框架,包含了文档的所有结构。
除根框架之外,所有框架都有父框架。
既然文本块用于分割文档结构,那么,每一个框架都将至少包含一个文本块,零个或者多个子框架。我们可以通过 QTextFrame::iterator 来遍历所有子元素:
QTextFrame::iterator it;
for(it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if(childFrame)
processFrame(frameElement, childFrame);
elseif(childBlock.isValid())
processBlock(frameElement, childBlock);
}
3.表格
表格由 QTextTable 类提供。QTextTable类的属性(对其,单元格填充,单元格间距,列表数等)存储在单独的QTextTableFormat中。表格单元由QTextTableCell类表示,它可以包含文
本块或框架。单元格知道自己在表格中的位置(她们所在的行和列),单元格还拥有列和行的宽度属性和一个QTextCharFormat。
表格是一个分布在行和列的单元的集合。每一个表格单元都是一个文档元素,拥有自己的字符样式,能够包含其他元素,例如框架和文本块。在表格构建,或者增加行或者列时,表格单
元被自动创建。表格单元也可以在两个表格之间移动。
QTextTable 是 QTextFrame 的子类,因此表格在文档中被作为框架处理,属性都存储在一个单独的QTextFrameFormat中。QTextTableCell::firstCursorPosition()在单元格中检索光标,
并使用此光标插入一个拥有我们创建的块格式的空段落,再使用QTextCursor::insertImage()方法把图片插入到这个段落中。如果我们需要处理文档中的每一个框架,我们需要对它们进行
区分,从而分别处理:
QTextFrame::iterator it;
for(it = frame->begin(); !(it.atEnd()); ++it) {
QTextFrame *childFrame = it.currentFrame();
QTextBlock childBlock = it.currentBlock();
if(childFrame) {
QTextTable *childTable = qobject_cast
if(childTable)
processTable(frameElement, childTable);
else
processFrame(frameElement, childFrame);
} else if (childBlock.isValid())
processBlock(frameElement, childBlock);
}
对于表格中已存在的单元,可以通过行和列进行遍历:
for(int row = 0; row < table->rows(); ++row) {
for(int column = 0; column < table->columns(); ++column) {
QTextTableCell tableCell = table->cellAt(row, column);
processTableCell(tableCell);
}
}
4.列表
列表由 QTextList 类提供。一个QTextList由一个或多个QTextBlock组成,这些QTextBlock的属性存储在一个单独的QTextListFormat中--包括段落的对其,边距,缩进等。
列表是一系列按照一般方法格式化的文本块,同时有一个列表的修饰,例如一个点和列表项。列表可以嵌套。如果列表格式指定了非零缩进,列表就会有一定的缩进。如果文本块代
表一个列表,QTextBlock::testList()方法返回一个指向QTextList的指针;否则返回0.
我们可以通过列表索引指定每一个列表项:
for(int index = 0; index < list->count(); ++index) {
QTextBlock listItem = list->item(index);
processListItem(listItem);
}
当我们遍历文档的所有文本块时,有可能它是一个列表中的一项。我们应当使用下面的代码进行区分:
QTextFrame::iterator it;
for(it = frame->begin(); !(it.atEnd()); ++it) {
QTextBlock block = it.currentBlock();
if(block.isValid()) {
QTextList *list = block.textList();
if(list) {
intindex = list->itemNumber(block);
processListItem(list, index);
}
}
}
5.图像
在 QTextDocument 中,图像当做一个文本片段,这个文本通过 Qt 资源机制指向图片的外部链接。图像用QTextFragment中包含的占位符来表示。这个占位符有一个用来保存图像
尺寸和名称的QTextImageFormat(QTextCharFormat子类)。名称是应用程序资源中一幅图像的名称。
图像通过光标接口创建,通过改变图像文本片段的样式进行修改:
if(fragment.isValid()) {
QTextImageFormat newImageFormat = fragment.charFormat().toImageFormat();
if(newImageFormat.isValid()) {
newImageFormat.setName(":/images/newimage.png");
QTextCursor helper = cursor;
helper.setPosition(fragment.position());
helper.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
helper.setCharFormat(newImageFormat);
}
}
表示图像的片段可以通过遍历包含图像的文本块的所有片段获得。
6.QTextCursor
QTextCursor是专门用来协助处理和获取QTextDocument内容的一组api. 它包含的信息既有QTextDocument内的光标位置(position()),以及所做的selection
(anchor() 和 position()之间)。最后得调用QPlainTextEdit::setTextCursor()来修改光标,让我们所做的修改应用到文档。QTextCursor::select()方法可以用来选择当前行
(QTextCursor::LineUnderCurso),当前段落(QTextCursor::BlockUnderCursor),甚至整个文档(QTextCursor::Document).QPlainTextEdit::cursorRext()方法返回文本光标的矩
形框,我们需要设定矩形框的宽度,让他足够显示弹出列表的第一列,同时考虑一个垂直滚动条的宽度。
current character是指position之前的那个character. current block是指包含position()位置的block.QTextCursor::movePosition()方法把光标移动到已完成的单词后面。
方法:
setPosition(), movePosition() 可以用来创建selection。取得selection的内容:selectionStart(), selectionEnd(), hasSelection(), clearSelection(), andremoveSelectedText().
取得format信息:charFormat(), blockFormat().
设置format信息:setCharFormat(),mergeCharFormat(),setBlockFormat() andmergeBlockFormat(). merge会把本来的格式合并。当当前有selection时,char format会对应
到所选中的内容上;即使block没有全选,block format会应用于整个block.
插入文本:insertText() function, insertBlock(). insertList(),insertTable(),insertImage(),insertFrame()
action可以分组(被undo/redo当作一个操作):beginEditBlock() and endEditBlock().
类QTextCursor可以用来插入table,list,text,还用来创建selection和修改selection。To select text between two points in the document, we need to position the cursor at
the first point then move it using a special mode (QTextCursor::MoveMode) with a move operation (QTextCursor::MoveOperation). When we select the text, we leave
the selection anchor at the old cursor position just as the user might do by holding down the Shift key when selecting text:
cursor.movePosition(QTextCursor::StartOfWord);
cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
QTextDocument provides a cursor-based interface for searching, making it easy to find and modify text in the style of a text editor. The
following code finds all the instances of a particular word in a document, and changes the color of each:
QTextCursor newCursor(document);
while (!newCursor.isNull() && !newCursor.atEnd()) {
newCursor = document->find(searchString, newCursor);
if (!newCursor.isNull()) {
newCursor.movePosition(QTextCursor::WordRight,
QTextCursor::KeepAnchor);
newCursor.mergeCharFormat(colorFormat);
}
}
QTextCursor的一些用法
if (!currentTextCursor.hasSelection()) {
currentTextCursor.insertText("**" + tr("Boldface") + "**");
currentTextCursor.movePosition(QTextCursor::Left, QTextCursor::MoveAnchor, 2);
currentTextCursor.movePosition(QTextCursor::WordLeft, QTextCursor::KeepAnchor, 1);
currentTextEdit->setTextCursor(currentTextCursor);
} else {
currentTextCursor.insertText("**" + currentTextCursor.selectedText() + "**");
}
1.在程序执行过程中去翻看前面的 信息,如果不把光标(虽然光标看不见)定位到最后一行,就会从翻看的位置打印信息。有没有把光标定位到最后的API?
解决:
QTextCursor cursor = this->textCursor();
if(!cursor.atEnd())
{
cursor.movePosition(QTextCursor::End,QTextCursor::MoveAnchor,1);
this->setTextCursor(cursor);
}
cursor.insertText(str);
QTextBlock:
组成QTextDocument的列表结构。
QTextBlock表示QTextDocument中的一个片断。它提供了其中的一个只读的block/paragraph. 它主要用来遍历text document来实现定制的layout或者重写一个新
的document. 可以通过text()和length()(包括了格式化的字符)得到文件内容的信息。
它的格式和QTextBlockFormat,QTehextCharFormat,QTextLayout都有关系。
如果要改变document的内容,请用QTextCursor接口。
五.打印
本质上讲,将内容画在屏幕上和画在打印机上是一样的,但打印机上的坐标是实实在在的厘米,英寸,还有需要换页,这就需要你在画的时候计算好大小。
有几个有用的函数:
setOrientation()打印机定向
setPaperSize()设置纸张大小
setResolution()设置DPI
newPage()新的一页
setNumCopies()打印多少份
需要注意的是:
1、当调用painter.begin后默认就会创建一个空白页,所以一开始不需要newpage,直接画就是了;
2、在一页画完以后直接调用print.newpage创建新页面
3、直到所有页面画完后才可以调用painter.end().
4、printer对象的pagerect返回的是去掉页边距后的矩形;paperrect返回的是纸张大小(单位可以设置)
5.QPrinter::paperRect()作为自己打印区域来给页码编数。
首先看一个简单的例子,打印一个QImage到一页纸上。
void PrintWindow::printImage(const QImage&image)
{
QPainter painter(&printer);
QRect rect=painter.viewport();
QSize size=image.size();
size.scale(rect.size(),Qt::KeepAspectRatio);
painter.setViewport(rect.x(),rect.y(),
size.width(),size.height());
painter.setWindow(image.rect());
painter.drawImage(0,0,image);
}
创建QPainter,绘图设备为QPrinter。设置窗口为所显示图形的矩形,视口也同样比例,然后在(0,0)绘制图像。
通常,QPainter的窗口自动进行了初始化,打印机和屏幕有着一致的分辨率,使控件的打印代码能够重用
调用printHtml()打印html:
void PrintWindow::printHtml(const QString&html)
{
QPainter painter(&printer);
QTextDocument textDocument;
textDocument.setHtml(html);
textDocument.print(&printer);
}
把文本转换为HTML文档用QTextDocument打印是最方便的一个方法。
调用printPage()按照顺序和打印份数打印每一页,设置了打印范围,或者要求逆序打印。我们需要在程序中考虑这些需求:
首先确定打印范围。QPrinter::fromPage()和toPage()返回用户选择的页面范围。如果没有选择,返回为0。我们进行了减1操作是因为我们的页面索引是从0开始的。
如果用户没有选定范围,则打印全部,firstPage和lastPage包含量所有的页面。
然后我们打印每一页。最外层循环为用户设定的打印的份数。对于那些支持多份打印的打印机,QPrinter::numCopies()总是返回1。如果打印机驱动程序不支持多份
打印,numCopies()返回到是用户指定的打印份数,有应用程序实现多份打印。
内层循环遍历打印的页数。如果页数不是第一页,调用newPage()清楚原来的页面开始填充新页面。调用printPage()打印每一页。
void PrintWindow::printPage(QPainter*painter,
const QStringList&entries,int pageNumber)
{
painter->save();
painter->translate(0,LargeGap);
foreach(QString entry,entries){
QStringList fields=entry.split(":");
QString title=fields[0];
QString body=fields[1];
printBox(painter,title,titleFont,Qt::lightGray);
printBox(painter,body,bodyFont,Qt::white);
painter->translate(0,MediumGap);
}
painter->restore();
painter->setFont(footerFont);
painter->drawText(painter->window(),
Qt::AlignHCenter|Qt::AlignBottom,
QString::number(pageNumber));
}
函数printPage()打印页面中的每一个条目。首先用printBox()打印标题,然后用printBox()打印描述。在每一页的底端打印页码。
void PrintWindow::printBox(QPainter*painter,const QString&str,
const QFont&font,const QBrush&brush)
{
painter->setFont(font);
int boxWidth=painter->window().width();
int textWidth=boxWidth-2*SmallGap;
int maxHeight=painter->window().height();
QRect textRect=painter->boundingRect(SmallGap,SmallGap,
textWidth,maxHeight,
Qt::TextWordWrap,str);
int boxHeight=textRect.height()+2*SmallGap;
painter->setPen(QPen(Qt::black,2,Qt::SolidLine));
painter->setBrush(brush);
painter->drawRect(0,0,boxWidth,boxHeight);
painter->drawText(textRect,Qt::TextWordWrap,str);
painter->translate(0,boxHeight);
}
printBox()首先绘制一个矩形框,然后在矩形框中绘制文本。