Для демонстрации этих подходов мы покажем, как можно добавить возможности технологии «drag-and-drop» в виджет QTableWidget. Будет поддерживаться перенос следующих типов MIME: text/plain, text/html и text/csv. При применении первого подхода инициирование переноса выглядит следующим образом:
01 void MyTableWidget::mouseMoveEvent(QMouseEvent *event)
02 {
03 if (event->buttons() & Qt::LeftButton) {
04 int distance = (event->pos() - startPos).manhattanLength();
05 if(distance >= QApplication::startDragDistance())
06 startDrag();
07 }
08 QTableWidget::mouseMoveEvent(event);
09 }
10 void MyTableWidget::startDrag()
11 {
12 QString plainText= selectionAsPlainText();
13 if (plainText.isEmpty())
14 return;
15 QMimeData *mimeData = new QMimeData;
16 mimeData->setText(plainText);
17 mimeData->setHtml(toHtml(plainText));
18 mimeData->setData("text/csv", toCsv(plainText).toUtf8());
19 QDrag *drag = new QDrag(this);
20 drag->setMimeData(mimeData);
21 if (drag->start(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction)
22 deleteSelection();
23 }
Закрытая функция startDrag() вызывается из mouseMoveEvent() для инициирования переноса выделенной прямоугольной области. Мы устанавливаем типы MIME text/plain и text/html, используя функции setText() и setHtml(), а тип text/csv мы устанавливаем функцией setData(), которая принимает произвольный тип MIME и массив QByteArray. Программный код для функции selectionAsString() более или менее совпадает с кодом функции Spreadsheet::copy(), рассмотренной в главе 4.
01 QString MyTableWidget::toCsv(const QString &plainText)
02 {
03 QString result = plainText;
04 result.replace("\\", "\\\\");
05 result.replace("\"", "\\\"");
06 result.replace("\t", "\", \"")
07 result.replace("\n", "\"\n\"");
08 result.prepend("\"");
09 result.append("\"");
10 return result;
11 }
12 QString MyTableWidget::toHtml(const QString &plainText)
13 {
14 QString result = Qt::escape(plainText);
15 result.replace("\t", "<td>");
16 result.replace("\n", "\n<tr><td>");
17 result.prepend("<table>\n<tr><td>");
18 result.append("\n</table>");
19 return result;
20 }
Функции toCsv() и toHtml() преобразуют строку со знаками табуляции и конца строки в формат CSV (comma—separated values — значения, разделенные запятыми) и HTML соответственно. Например, данные
Red Green Blue
Cyan Yellow Magenta
преобразуются в
"Red", "Green", "Blue"
"Cyan", "Yellow", "Magenta"
или в
<table>
<tr><td>Red<td>Green<td>Blue
<tr><td>Cyan<td>Yellow<td>Magenta
</table>
Преобразование выполняется самым простым из возможных способов с применением функции QString::replace(). Для удаления специальных символов формата HTML мы используем функцию Qt::escape().
01 void MyTableWidget::dropEvent(QDropEvent *event)
02 {
03 if (event->mimeData()->hasFormat("text/csv")) {
04 QByteArray csvData = event->mimeData()->data("text/csv");
05 QString csvText = QString::fromUtf8(csvData);
06 …
07 event->acceptProposedAction();
08 } else if (event->mimeData()->hasFormat("text/plain")) {
09 QString plainText = event->mimeData()->text();
10 …
11 event->acceptProposedAction();
12 }
13 }
Хотя мы предоставляем данные в трех разных форматах, мы принимаем в dropEvent() только два из них. Если подьзователь переносит ячейки из таблицы QTableWidget в редактор HTML, нам нужно, чтобы ячейки были преобразованы в таблицу HTML. Но если пользователь переносит произвольный текст HTML в таблицу QTableWidget, мы не станем его принимать.
Для того чтобы этот пример заработал, нам потребуется также вызвать setAcceptDrops(true) и setSelectionMode(ContiguousSelection) в конструкторе MyTableWidget.
Теперь мы переделаем этот пример, но на этот раз мы создадим подкласс QMimeData, чтобы отложить или избежать (потенциально затратных) преобразований между элементами QTableWidgetltem и массивом QByteArray. Ниже приводится определение нашего подкласса: