QTextEdit是用来编辑和展示文本和富文本的一个控件。我之前一直拿它当纯文本编辑器(QPlainTextEdit)使,一直没啥机会去用一下他的富文本功能。
这次有时间了,准备做一个可以添加图片的编辑框:拖入即可添加到编辑框。
有两种方式,一种是根据动作想到了Drag 、Drop来实现;另一种是QTextEdit自带的方法实现。
一般在光标处添加图片,代码为
QImage img = ...
textDocument->addResource(QTextDocument::ImageResource, QUrl("myimage"), img);
cursor.insertImage("myimage");
现在我们重写QTextEdit,命名为MyTextEdit,然后在落下事件中,获取MineData,将其转化为QImage,最后根据上面的方法,也就实现了拖入图片功能了
void MyTextEdit::dragEnterEvent(QDragEnterEvent *e)
{
e->acceptProposedAction();
}
void MyTextEdit::dropEvent(QDropEvent *e)
{
QString url=e->mimeData()->urls().first().toLocalFile();
if(e->mimeData()->hasImage())
{
//这只是个名字 供后续调用的名字
QUrl name ( QString ( "file://%1" ).arg ( url ) );
//获取图片 并插入到光标处
QImage image = QImageReader ( url ).read();
QTextDocument * textDocument = this->document();
document()->addResource( QTextDocument::ImageResource, name, QVariant ( image ) );
textCursor().insertImage(name.toString());
}
}
后来,我发现QTextEdit对插入图片等数据都有固定的方法可实现。通过方法canInsertFromMimeData对插入的数据进行筛选,
然后在insertFromMimeData方法中根据不同类的数据进行操作添加。不过我经过测试发现:source->hasImage()条件的,不知情况下能满足,经过我拖入的或者复制粘贴的,都不是hasImage(),所以谁能解决我的疑问?!
bool MyTextEdit::canInsertFromMimeData(const QMimeData *source) const
{
return source->hasImage()||source->hasUrls()||QTextEdit::canInsertFromMimeData(source);
}
void MyTextEdit::insertFromMimeData(const QMimeData *source)
{
if(source->hasImage())
{
qDebug()<<"hasImage-------------------";
static int i=1;
QUrl name(QString("imgName_%1").arg(i));
QImage img=qvariant_cast(source->imageData());
document()->addResource(QTextDocument::ImageResource,name,img);
textCursor().insertImage(name.toString());
i++;
}
else if (source->hasUrls())
{
qDebug()<<"urls-----------------------------";
foreach (QUrl url, source->urls())
{
QFileInfo info(url.toLocalFile());
if (QImageReader::supportedImageFormats().contains(info.suffix().toLower().toLatin1()))
{
QImage image(info.filePath());
if (!image.isNull())
{
document()->addResource(QTextDocument::ImageResource, url, image);
textCursor().insertImage(url.toString());
}
}
else{
QFile file(url.toLocalFile());
if(file.open(QIODevice::ReadOnly|QIODevice::Text))
textCursor().insertText(file.readAll());
}
}
}else{
qDebug()<<"insertFromMimeData--------------------";
QTextEdit::insertFromMimeData(source);
}
}
我在QTextEdit看到了以下一段话,解释了我以上两个方法的可行性:
QTextEdit also supports custom drag and drop behavior. By default, QTextEdit will insert plain text, HTML and rich text when the user drops data of these MIME types onto a document. Reimplement canInsertFromMimeData() and insertFromMimeData() to add support for additional MIME types.
还有我很好奇,QTextEdit底层是如何写的canInsertFromMimeData和insertFromMimeData方法:它是另写了一个控制类QWidgetTextControl来操作,从以下源码中,我们可以清楚的看到它能够支持什么类型插入,还有根据不同的数据类型,进行的不同的处理,这些都是默认自带的。
bool QWidgetTextControl::canInsertFromMimeData(const QMimeData *source) const
{
Q_D(const QWidgetTextControl);
if (d->acceptRichText)
return (source->hasText() && !source->text().isEmpty())
|| source->hasHtml()
|| source->hasFormat(QLatin1String("application/x-qrichtext"))
|| source->hasFormat(QLatin1String("application/x-qt-richtext"));
else
return source->hasText() && !source->text().isEmpty();
}
void QWidgetTextControl::insertFromMimeData(const QMimeData *source)
{
Q_D(QWidgetTextControl);
if (!(d->interactionFlags & Qt::TextEditable) || !source)
return;
bool hasData = false;
QTextDocumentFragment fragment;
#ifndef QT_NO_TEXTHTMLPARSER
if (source->hasFormat(QLatin1String("application/x-qrichtext")) && d->acceptRichText) {
// x-qrichtext is always UTF-8 (taken from Qt3 since we don't use it anymore).
const QString richtext = QLatin1String("")
+ QString::fromUtf8(source->data(QLatin1String("application/x-qrichtext")));
fragment = QTextDocumentFragment::fromHtml(richtext, d->doc);
hasData = true;
} else if (source->hasHtml() && d->acceptRichText) {
fragment = QTextDocumentFragment::fromHtml(source->html(), d->doc);
hasData = true;
} else {
QString text = source->text();
if (!text.isNull()) {
fragment = QTextDocumentFragment::fromPlainText(text);
hasData = true;
}
}
#else
fragment = QTextDocumentFragment::fromPlainText(source->text());
#endif // QT_NO_TEXTHTMLPARSER
if (hasData)
d->cursor.insertFragment(fragment);
ensureCursorVisible();
}
还有就是QTextEdit支持剪贴板(clipboard)的,从源码中,你可以看到它对复制粘贴等的一系列处理。 这个我就不列举源码了。
感觉每次深入研究一个经常用的小控件,都收获满满(*^▽^*)!