实现一个能自由插入图片的文本编辑器。
qml的TextEdit是直接支持富文本的,可以直接插入图片,使用
<img src="" align="top,middle,bottom" width="" height="">
但是对于动图而言,解决办法之一就是手动换帧。
先上效果图:
对于简单的动图而言,自然想到使用Qt自带的QMovie进行解析。
思路是每插入一张动图,在它换帧的时候,将当前帧保存下来,并将其路径emit出去,然后在TextEdit的text中进行replace即可。
关键代码:(c++部分)
void GifHelper::addGif(QString gif) { int speed = 100; //默认为原始速度 if (gif.left(4) == "file") { gif = gif.mid(8); speed = 60; //插入的图片速度为0.6倍 } QMovie *movie = new QMovie(gif, "", this); movie->setCacheMode(QMovie::CacheAll); movie->setSpeed(speed); connect(movie, &QMovie::finished, movie, &QMovie::start); //循环播放 connect(movie, &QMovie::frameChanged, this, &GifHelper::disposeFrame); m_gifList.append(movie); movie->jumpToFrame(0); //开始前先缓存第一帧 movie->start(); } void GifHelper::disposeFrame(int frameNumber) { QMovie *movie = qobject_cast<QMovie *>(sender()); QString baseName = QFileInfo(movie->fileName()).baseName(); QImage image = movie->currentImage(); QString src = m_cachePath + baseName + "/" + QString::number(frameNumber) + ".png"; if (!QFile::exists(src)) //如果缓存图像不存在就缓存 { QDir dir; dir.mkpath(m_cachePath + baseName + "/"); image.save(src); } QString newData = baseName + "/" + QString::number(frameNumber) + ".png"; QString oldData; //前一帧 if (frameNumber == 0) oldData = baseName + "/" + QString::number(movie->frameCount() - 1) + ".png"; else oldData = baseName + "/" + QString::number(frameNumber - 1) + ".png"; emit updateGif(oldData, newData); }
qml部分:
TextEdit
{
id: editor
selectionColor: "#3399FF"
textFormat: TextEdit.RichText //使用富文本
selectByMouse: true
selectByKeyboard: true
wrapMode: TextEdit.Wrap
property alias cachePath: gifHelper.cachePath
function addImage(src, w, h)
{
var index1 = src.lastIndexOf(".");
var index2 = src.length;
var suffix = src.substring(index1 + 1, index2); //后缀名
if (suffix === "gif" || suffix === "GIF") //如果为动图
{
gifHelper.addGif(src)
var baseName = Api.baseName(src);
editor.insert(editor.cursorPosition, "<img src=\"file:///" +
gifHelper.cachePath + baseName + "/0" + ".png" +
"\" height=" + w + " width=" + h + ">"); //插入第一帧的图片
}
else editor.insert(editor.cursorPosition,
"<img src=\"" + src + "\" height=" + w + " width=" + h + ">")
}
GifHelper
{
id: gifHelper
onUpdateGif:
{
var pos = editor.cursorPosition;
var selstart = editor.selectionStart;
var selend = editor.selectionEnd;
editor.text = editor.text.replace(oldData, newData); //手动换帧
editor.cursorPosition = pos;
editor.select(selstart, selend);
}
}
}
总结:表面上看感觉还勉强可以,实际上动图过多时有严重的性能问题。Qt自带的例子有一个使用QTextObject的,然鹅qml目前好像没有找到相关的东东,唯一有关的就是TextEdit里的 textDocument : TextDocument,但是并不知道怎么用,以后学会了再写相关的。