Qt 支持自定义数据类型的托拽(Supporting Custom Drag Types)
2014-04-10 21:54
856 查看
我们使用类QMimeData表示普通的MIME类型。调用QMimeData::setText()进行对文本的托拽,调用QMimeData::urls()得到托拽到url文本列表。如果我们想托拽普通的文本,HTML文本,图片,URLs,颜色等,都可以使用QMimeData类。但是如果我们需要对自定义的类型进行托拽,就需要使用下面的方法:
1. 用QByteArray表示任意数据,调用函数QMimeData::setData(),通过QMimeData::data()得到数据。
2. 定义QMimeData子类,重新实现函数formats()和retrieveData()处理自定义的数据类型。.
3. 对于只发生在一个应用程序内部的托拽,定义QMimeData子类,在这个子类中保存任意的数据类型。
第一个方法不需要继承类,但是有些缺点:即使托拽最终不被接受,我们也需要把数据类型转换为QByteArray,如果我们希望提供的MIME类型能够和大量的应用程序进行交互,我们需要把交互的数据保存多份(每一类MIME类型保存一份)。要是交互的数据量很大,那么程序的执行速度肯定会慢下来。第二种和第三种方法能够避免或者尽量减少这些问题。
我们用一个例子说明这些方法,让QTableWidget控件支持托拽。能够进行拖动的数据类型为:text/plain,text/html,text/csv。第一种方法实现如下:
函数mouseMoveEvent()中调用startDrag()开始进行拖动。我们调用函数setText(),setHtml()设置MIME类型为text/plain,text/html的数据,函数setData()保存text/csv类型的数据,setData()把任意的MIME数据类型保存为一个QByteArray类型的数据。函数selectionAsString()的实现与第四章中Spreadsheet::copy()相似。
函数toCsv()和toHtml()将tabs和newlines字符转换为vcsv格式的字符(用逗号分割数据)或者HTML字符。例如
转换为(CSV):
或者(HTML)
使用函数QString::replace(),使转换尽可能简单。函数Qt::escape()用来解释HTML中的特殊字符。
虽然我们提供了三种不同的数据格式,但在dropEvent()中我们只接受了其中的两种。如果用户从QTableWidget的一个网格中拖动一串HTML字符到一个HTML编译器,则把网格中的数据转换为HTML。如果用户拖动一个HTML到QTableWidget控件中,我们不想接受它。
要让这个例子顺利实现托拽,在MyTableWidget构造函数中还要调用setAcceptDrops(true)和setSelectionMode(ContiguousSelection)。
现在我们重新实现这个例子,这次,我们用QMineData作为基类,用QMineData的子类实现数据转换,避免了QTableWidgetItem和QByteArray之间的转换。下面是子类的定义:
在类中,我们保存了一个QTableWidgetSelectionRange对象和一个QTableWidget指针,用来得到托拽的数据。函数formats()和retriveData()是对QMineData函数的重写。在构造函数中实现对私有变量的初始化。
函数formats()返回一个能够支持的MIME类型的列表。类型之间的顺序对程序没有影响,但是把“最好”的格式放在第一个是很好的习惯。支持多种格式的程序一般使用第一个能够匹配的格式。
指定一个MIME类型,函数retrieveData()把拖动的数据作为一个QVariant数据返回。参数format的值一般是formats()返回列表中之一。我们并没有做这样的假设,应用程序也不会在拖动时检查MIME类型。函数text(),html(),urls(),image-Data(),colorData()和data()都是由QMimeData提供的。
参数preferedType用来给出一个QVariant类型的建议,这里我们忽略这个参数由QMimeData处理。
函数dropEvent()和本节前面写的dropEvent()相似。在这个函数中,我们首先把QMimeData安全转换为TableMimeData。如果qobject_cast<T>()返回了正确对指针,说明托拽发生在同一个应用程序中的MyTableWidget控件,我们根据QMimeData的API直接得到表格中拖动数据。如果没有得到正确的指针,则按照标准方式处理。
1. 用QByteArray表示任意数据,调用函数QMimeData::setData(),通过QMimeData::data()得到数据。
2. 定义QMimeData子类,重新实现函数formats()和retrieveData()处理自定义的数据类型。.
3. 对于只发生在一个应用程序内部的托拽,定义QMimeData子类,在这个子类中保存任意的数据类型。
第一个方法不需要继承类,但是有些缺点:即使托拽最终不被接受,我们也需要把数据类型转换为QByteArray,如果我们希望提供的MIME类型能够和大量的应用程序进行交互,我们需要把交互的数据保存多份(每一类MIME类型保存一份)。要是交互的数据量很大,那么程序的执行速度肯定会慢下来。第二种和第三种方法能够避免或者尽量减少这些问题。
我们用一个例子说明这些方法,让QTableWidget控件支持托拽。能够进行拖动的数据类型为:text/plain,text/html,text/csv。第一种方法实现如下:
voidMyTableWidget::mouseMoveEvent(QMouseEvent*event)
{
if(event->buttons()&Qt::LeftButton){
intdistance=(event->pos()-startPos).manhattanLength();
if(distance>=QApplication::startDragDistance())
startDrag();
}
QTableWidget::mouseMoveEvent(event);
}
voidMyTableWidget::startDrag()
{
QStringplainText=selectionAsPlainText();
if(plainText.isEmpty())
return;
QMimeData*mimeData=newQMimeData;
mimeData->setText(plainText);
mimeData->setHtml(toHtml(plainText));
mimeData->setData("text/csv",toCsv(plainText).toUtf8());
QDrag*drag=newQDrag(this);
drag->setMimeData(mimeData);
if(drag->start(Qt::CopyAction|Qt::MoveAction)==Qt::MoveAction)
deleteSelection();
}
函数mouseMoveEvent()中调用startDrag()开始进行拖动。我们调用函数setText(),setHtml()设置MIME类型为text/plain,text/html的数据,函数setData()保存text/csv类型的数据,setData()把任意的MIME数据类型保存为一个QByteArray类型的数据。函数selectionAsString()的实现与第四章中Spreadsheet::copy()相似。
QStringMyTableWidget::toCsv(constQString&plainText)
{
QStringresult=plainText;
result.replace("//","////");
result.replace("/"","///"");
result.replace("/t","/",/"");
result.replace("/n","/"/n/"");
result.prepend("/"");
result.append("/"");
returnresult;
}
QStringMyTableWidget::toHtml(constQString&plainText)
{
QStringresult=Qt::escape(plainText);
result.replace("/t","<td>");
result.replace("/n","/n<tr><td>");
result.prepend("<table>/n<tr><td>");
result.append("/n</table>");
returnresult;
}
函数toCsv()和toHtml()将tabs和newlines字符转换为vcsv格式的字符(用逗号分割数据)或者HTML字符。例如
RedGreenBlue
CyanYellowMagenta
转换为(CSV):
"Red","Green","Blue"
"Cyan","Yellow","Magenta"
或者(HTML)
<table>
<tr><td>Red<td>Green<td>Blue
<tr><td>Cyan<td>Yellow<td>Magenta
</table>
使用函数QString::replace(),使转换尽可能简单。函数Qt::escape()用来解释HTML中的特殊字符。
voidMyTableWidget::dropEvent(QDropEvent*event)
{
if(event->mimeData()->hasFormat("text/csv")){
QByteArraycsvData=event->mimeData()->data("text/csv");
QStringcsvText=QString::fromUtf8(csvData);
...
event->acceptProposedAction();
}elseif(event->mimeData()->hasFormat("text/plain")){
QStringplainText=event->mimeData()->text();
...
event->acceptProposedAction();
}
}
虽然我们提供了三种不同的数据格式,但在dropEvent()中我们只接受了其中的两种。如果用户从QTableWidget的一个网格中拖动一串HTML字符到一个HTML编译器,则把网格中的数据转换为HTML。如果用户拖动一个HTML到QTableWidget控件中,我们不想接受它。
要让这个例子顺利实现托拽,在MyTableWidget构造函数中还要调用setAcceptDrops(true)和setSelectionMode(ContiguousSelection)。
现在我们重新实现这个例子,这次,我们用QMineData作为基类,用QMineData的子类实现数据转换,避免了QTableWidgetItem和QByteArray之间的转换。下面是子类的定义:
classTableMimeData:publicQMimeData
{
Q_OBJECT
public:
TableMimeData(constQTableWidget*tableWidget,
constQTableWidgetSelectionRange&range);
constQTableWidget*tableWidget()const{returnmyTableWidget;}
QTableWidgetSelectionRangerange()const{returnmyRange;}
QStringListformats()const;
protected:
QVariantretrieveData(constQString&format,
QVariant::TypepreferredType)const;
private:
staticQStringtoHtml(constQString&plainText);
staticQStringtoCsv(constQString&plainText);
QStringtext(introw,intcolumn)const;
QStringrangeAsPlainText()const;
constQTableWidget*myTableWidget;
QTableWidgetSelectionRangemyRange;
QStringListmyFormats;
};
在类中,我们保存了一个QTableWidgetSelectionRange对象和一个QTableWidget指针,用来得到托拽的数据。函数formats()和retriveData()是对QMineData函数的重写。在构造函数中实现对私有变量的初始化。
TableMimeData::TableMimeData(constQTableWidget*tableWidget,
constQTableWidgetSelectionRange&range)
{
myTableWidget=tableWidget;
myRange=range;
myFormats<<"text/csv"<<"text/html"<<"text/plain";
}
QStringListTableMimeData::formats()const
{
returnmyFormats;
}
函数formats()返回一个能够支持的MIME类型的列表。类型之间的顺序对程序没有影响,但是把“最好”的格式放在第一个是很好的习惯。支持多种格式的程序一般使用第一个能够匹配的格式。
QVariantTableMimeData::retrieveData(constQString&format,
QVariant::TypepreferredType)const
{
if(format=="text/plain"){
returnrangeAsPlainText();
}elseif(format=="text/csv"){
returntoCsv(rangeAsPlainText());
}elseif(format=="text/html"){
returntoHtml(rangeAsPlainText());
}else{
returnQMimeData::retrieveData(format,preferredType);
}
}
指定一个MIME类型,函数retrieveData()把拖动的数据作为一个QVariant数据返回。参数format的值一般是formats()返回列表中之一。我们并没有做这样的假设,应用程序也不会在拖动时检查MIME类型。函数text(),html(),urls(),image-Data(),colorData()和data()都是由QMimeData提供的。
参数preferedType用来给出一个QVariant类型的建议,这里我们忽略这个参数由QMimeData处理。
voidMyTableWidget::dropEvent(QDropEvent*event)
{
constTableMimeData*tableData=
qobject_cast<constTableMimeData*>(event->mimeData());
if(tableData){
constQTableWidget*otherTable=tableData->tableWidget();
QTableWidgetSelectionRangeotherRange=tableData->range();
...
event->acceptProposedAction();
}elseif(event->mimeData()->hasFormat("text/csv")){
QByteArraycsvData=event->mimeData()->data("text/csv");
QStringcsvText=QString::fromUtf8(csvData);
...
event->acceptProposedAction();
}elseif(event->mimeData()->hasFormat("text/plain")){
QStringplainText=event->mimeData()->text();
...
event->acceptProposedAction();
}
QTableWidget::mouseMoveEvent(event);
}
函数dropEvent()和本节前面写的dropEvent()相似。在这个函数中,我们首先把QMimeData安全转换为TableMimeData。如果qobject_cast<T>()返回了正确对指针,说明托拽发生在同一个应用程序中的MyTableWidget控件,我们根据QMimeData的API直接得到表格中拖动数据。如果没有得到正确的指针,则按照标准方式处理。
相关文章推荐
- Qt: Session management error: None of the authentication protocols specified are supported
- 【Qt编程】Qt版扫雷
- 【Qt编程】Qt版扫雷
- VS2010静态编译安装Qt5.1.1+openssl
- Qt信号量QSemaphore
- Qt的QWaitCondition
- 基于Qt的QZXing源码的Mac osx编译
- QTableView派生类重载dropEvent方法无效的解决办法
- Qt 之 show,hide,setVisible,setHidden,close 等小结
- QT里定时器QTimer的用法
- 【转】QT#include <GL/gl.h>错误解决办法
- QT 读写sqllite数据库
- Qt学习笔记常用容器
- Qt5 新特性
- QT 的信号与槽机制介绍
- Qt学习笔记常用容器
- 【亲测可用】Qt4.8.5+QtCreator2.8.0傻瓜安装...
- qt超强绘图控件qwt - 安装及配置
- 如何在QTP中添加和使用环境变量(1)
- Qt5官方demo解析集9——Analog Clock Window Example