接上篇文章,第一篇文章实现了几个常用的操作。这篇文章要说的是QTextEdit的复制粘贴等操作,个人认为这才是自定义数据在QTextEdit控件中操作的难点,因为要保证自定义数据的完整性和准确性。下面我们就来看一下自定义数据的复制粘贴。
- 首先我们要定义一个我们自己数据的格式,我这里声明了一些结构体
enum DataType
{
Type_Text = 0, //普通文本
Type_EmojiCode,//表情码
Type_Br, //换行符"\n"
Type_HyperLinkText, //超链接文本
/***当前编辑框使用***/
Type_EmojiImage,//表情图片
Type_File,//文件
Type_ScreenImage,//截图
/*****************/
Type_Default //默认
};
struct sSingleDataInfo //单条数据信息
{
QVariant m_var; //数据
DataType m_type; //数据类型
sSingleDataInfo()
{
m_type = Type_Default;
}
sSingleDataInfo(const sSingleDataInfo &parm)
{
this->m_var = parm.m_var;
this->m_type = parm.m_type;
}
sSingleDataInfo &operator=(const sSingleDataInfo &parm)
{
if (this == &parm)
{
return *this;
}
this->m_var = parm.m_var;
this->m_type = parm.m_type;
return *this;
}
void clear()
{
m_var.clear();
m_type = Type_Default;
}
};
struct sSingleCopyInfo //单个数据复制信息
{
QString m_var; //数据
int m_type; //数据类型
sSingleCopyInfo()
{
m_type = (int)Type_Default;
}
sSingleCopyInfo(const sSingleCopyInfo &parm)
{
this->m_var = parm.m_var;
this->m_type = parm.m_type;
}
sSingleCopyInfo &operator=(const sSingleCopyInfo &parm)
{
if (this == &parm)
{
return *this;
}
this->m_var = parm.m_var;
this->m_type = parm.m_type;
return *this;
}
void clear()
{
m_var.clear();
m_type = (int)Type_Default;
}
};
Q_DECLARE_METATYPE(sSingleCopyInfo)
当我们输入了自定义数据时,如图:在进行复制操作。如下
void EditDrop::slotcopy()
{
QTextDocumentFragment DocumentFragment = this->textCursor().selection();
CopyEditDataToClipboard(FormatProcessData(DocumentFragment));//处理自定义数据接口
}
/*!
* \brief 格式化处理在编辑框复制的数据
* \param DocumentFragment 需要格式化处理的数据
* \param RecoveryData 该字段表示在编辑框恢复上次的数据(例如回退、前进)的标记,默认为false。
*/
QList<sSingleCopyInfo> EditDrop::FormatProcessData(QTextDocumentFragment DocumentFragment, bool RecoveryData)
{
QTextEdit* TempTextEdit = new QTextEdit;
m_filePathList.clear();
TempTextEdit->textCursor().insertFragment(DocumentFragment);
QTextDocument* TextDocument = TempTextEdit->document();
QTextFrame* TextFrame = TextDocument->rootFrame();
QTextFrame::Iterator frameIt = TextFrame->begin();
QString strText = "";
QList<sSingleCopyInfo> DataList;
for (QTextFrame::Iterator it = frameIt;
!it.atEnd();)
{
if (it.currentBlock().isValid())
{
const QTextBlock block = it.currentBlock();
QTextBlock::Iterator it_1 = block.begin();
for (; !it_1.atEnd(); ++it_1)
{
const QTextFragment fragment = it_1.fragment();
const QTextCharFormat format = fragment.charFormat();
QString txt = fragment.text();
const bool isObject = txt.contains(QChar::ObjectReplacementCharacter);
const bool isImage = isObject && format.isImageFormat();
if (isObject)
{
for(int i = 0; isImage && i < txt.length(); ++i)
{
QTextImageFormat imgFmt = format.toImageFormat();
QString name = imgFmt.name();
if(name.contains("dropped_image_"))
{
QUrl url = QUrl::fromLocalFile(name);
name = url.toLocalFile();
strLength = strLength + 1;
sSingleCopyInfo info;
info.m_var = name;
info.m_type = Type_ScreenImage;
DataList.append(info);
if(RecoveryData)
{
QUrl tempxx = QUrl::fromLocalFile(name);
m_hash_Path[tempxx.toLocalFile()] = tempxx.toLocalFile();
m_filePathList.append(tempxx.toLocalFile());
}
}
else if(name.contains("EmojiImagesBig"))
{
strLength = strLength + 1;
sSingleCopyInfo info;
info.m_var = name;
info.m_type = Type_EmojiImage;
DataList.append(info);
if(RecoveryData)
{
m_list_emoji.append(name);
}
}
else
{
QUrl url = QUrl::fromLocalFile(name);
name = url.toLocalFile();
strLength = strLength + 1;
sSingleCopyInfo info;
info.m_var = name;
info.m_type = Type_File;
DataList.append(info);
if(RecoveryData && info.m_type == Type_File)
{
m_hash_Path[name] = name;
QUrl tempxx = QUrl::fromLocalFile(name);
m_hash_Path[tempxx.toLocalFile()] = tempxx.toLocalFile();
m_filePathList.append(tempxx.toLocalFile());
}
}
}
continue;
}
strLength = strLength + txt.length();
sSingleCopyInfo info;
info.m_var = txt;
info.m_type = Type_Text;
DataList.append(info);
}
++it;
if(!it.atEnd())
{
strLength = strLength + 1;
strText.append("\n");
sSingleCopyInfo info;
info.m_var = "\n";
info.m_type = Type_Br;
DataList.append(info);
}
continue;
}
++it;
}
return DataList;
}
/*!
* \brief 把编辑框复制的数据复制到系统剪切板
* \param copyInfoList 数据结构体
*/
void EditDrop::CopyEditDataToClipboard(QList<sSingleCopyInfo> copyInfoList)
{
QString dataStr = "";
foreach (sSingleCopyInfo varData, copyInfoList)
{
//普通文本
if (varData.m_type == Type_Text)
{
dataStr += varData.m_var;
}
}
//将复制的所有文本字符构成的字符串设到剪切板
QClipboard *pBoard = QApplication::clipboard();
if(nullptr== pBoard)
{
return;
}
//将复制的所有内容设置到剪切板
QMimeData *pCusData = new QMimeData();//自定义数据
QByteArray dataArray = getSingleCopyInfoListSerialize(copyInfoList);
pCusData->setData("EditText", dataArray);
pCusData->setData(QString("text/plain"), dataStr.toUtf8());
pBoard->setMimeData(pCusData);
}
粘贴自定义数据:
/*!
* \brief 处理编辑框自定义粘贴内容
* \return
*/
bool EditDrop::dealEditTextContentPaste()
{
bool bDeal = false;
QClipboard *pBoard = QApplication::clipboard();
if(nullptr == pBoard)
{
return bDeal;
}
QString qDebugStr = QString("");
const QMimeData *pMimeData = pBoard->mimeData();
if(pMimeData && pMimeData->hasFormat("EditText"))
{
bDeal = true;
QByteArray array = pMimeData->data("EditText");
QList<sSingleCopyInfo> copyInfoList = getSingleCopyInfoListDeserialize(array);
foreach (sSingleCopyInfo copyInfo, copyInfoList)
{
qDebugStr += copyInfo.m_var;
QString strValue = copyInfo.m_var;
switch ((DataType)copyInfo.m_type)
{
case Type_Text:
{
this->textCursor().insertText(strValue);
}break;
case Type_EmojiImage:
{
SetEmojiPath(strValue);
m_list_emoji.append(strValue);
}break;
case Type_ScreenImage:
{
ProcessEditTextImage(strValue);
}break;
case Type_File:
{
SetEditImage(strValue);
}break;
case Type_Br:
{
this->textCursor().insertText("\n");
}break;
default:
break;
}
}
//qDebug() << tr("粘贴内容: %1").arg(qDebugStr);
}
return bDeal;
}
复制时需要把我们自定义的格式序列化后传递给系统剪切板,粘贴时把剪切板数据反序列化回来解析到界面。
总结
QTextEdit的自定义数据的处理难点个人认为在数据的解析和处理上(大佬轻喷)。还需对QTextEdit内部对数据处理和存储有初步的认识以及对QT中文档相关类和xml处理解析类的数据存储结构和处理逻辑有初步的认识,俗话说知己知彼才能百战百胜。我也是站在巨人的肩膀上才能写出这俩篇文章,在此感谢csdn上各位前辈的无私奉献,特别感谢同事大佬的支持和解答。这也算是自己的成长。长路漫漫,砥砺前行!共勉
结语
编码可能不咋规范,编码规范这块还需提升,各位将就着看 哈哈。项目工程稍后会上传,可能会有bug还请各位海涵。