您的位置:首页 > 编程语言 > Qt开发

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。第一种方法实现如下:
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直接得到表格中拖动数据。如果没有得到正确的指针,则按照标准方式处理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: