Выбрать главу

Для демонстрации этих подходов мы покажем, как можно добавить возможности технологии «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. Ниже приводится определение нашего подкласса: