【写在前面】
实现一个能自由插入图片的文本编辑器。
注意,在后面使用更好的方法实现:QML实现的支持动图的编辑器(比之前要好)
【正文开始】
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,但是并不知道怎么用,以后学会了再写相关的。