01 class TableMimeData : public QMimeData
02 {
03 Q_OBJECT
04 public:
05 TableMimeData(const QTableWidget *tableWidget,
06 const QTableWidgetSelectionRange &range);
07 const QTableWidget *tableWidget() const
08 { return myTableWidget; }
09 QTableWidgetSelectionRange range() const { return myRange; }
10 QStringList formats() const;
11 protected:
12 QVariant retrieveData(const QString &format,
13 QVariant::Type preferredType) const;
14 private:
15 static QString toHtml(const QString &plainText);
16 static QString toCsv(const QString &plainText);
17 QString text(int row, int column) const;
18 QString rangeAsPlainText() const;
19 const QTableWidget *myTableWidget;
20 QTableWidgetSelectionRange myRange;
21 QStringList myFormats;
22 };
Вместо реальных данных мы храним объект QTableWidgetSelectionRange, который определяет область переносимых ячеек и сохраняет указатель на QTableWidget. Функции formats() и retrieveData() класса QMimeData переопределяются.
01 TableMimeData::TableMimeData(const QTableWidget *tableWidget,
02 const QTableWidgetSelectionRange &range)
03 {
04 myTableWidget = tableWidget;
05 myRange = range;
06 myFormats << "text/csv" << "text/html" << "text/plain";
07 }
В конструкторе мы инициализируем закрытые переменные.
01 QStringList TableMimeData::formats() const
02 {
03 return myFormats;
04 }
Функция formats() возвращает список MIME—типов, находящихся в объекте MIME—данных. Последовательность форматов обычно несущественна, однако на практике желательно первыми указывать «лучшие» форматы. Приложения, поддерживающие несколько форматов, иногда будут использовать первый подходящий.
01 QVariant TableMimeData::retrieveData(const QString &format,
02 QVariant::Type preferredType) const
03 {
04 if (format == "text/plain") {
05 return rangeAsPlainText();
06 } else if (format =="text/csv") {
07 return toCsv(rangeAsPlainText()); }
08 else if (format == "text/html") {
09 return toHtml(rangeAsPlainText());
10 } else {
11 return QMimeData::retrieveData(format, preferredType);
12 }
13 }
Функция retrieveData() возвращает данные для заданного MIME—типа в виде объекта QVariant. Параметр format обычно содержит одну из строк, возвращенных функцией formats(), однако нам не следует на это рассчитывать, поскольку не все приложения проверяют MIME—тип на соответствие форматам функции formats(). Предусмотренные в классе QMimeData функции получения данных text(), html(), urls(), imageData(), colorData() и data() реализуются с помощью функции retrieveData().
Параметр preferredType определяет тип, который следует поместить в объект QVariant. Здесь мы его игнорируем и рассчитываем на то, что QMimeData преобразует при необходимости возвращенное значение в требуемый тип.
01 void MyTableWidget::dropEvent(QDropEvent *event)
02 {
03 const TableMimeData *tableData =
04 qobject_cast<const TableMimeData *>(event->mimeData());
05 if (tableData) {
06 const QTableWidget *otherTable = tableData->tableWidget();
07 QTableWidgetSelectionRange otherRange = tableData->range();
08 …
09 event->acceptProposedAction();
10 } else if (event->mimeData()->hasFormat("text/csv")) {
11 QByteArray csvData = event->mimeData()->data("text/csv");
12 QString csvText = QString::fromUtf8(csVData);
13 …
14 event->acceptProposedAction();
15 } else if (event->mimeData()->hasFormat("text/plain")) {
16 QString plainText = event->mimeData()->text();
17 …
18 event->acceptProposedAction();
19 }
20 QTableWidget::mouseMoveEvent(event);
21 }
Функция dropEvent() аналогична функции с тем же названием, которую мы рассматривали ранее в данном разделе, но на этот раз мы ее оптимизируем, делая вначале проверку возможности приведения типа QMimeData в тип TableMimeData. Если qobject_cast<T>() срабатывает, это значит, что перенос был инициирован виджетом MyTableWidget, расположенным в том же самом приложении, и мы можем получить непосредственный доступ к данным таблицы вместо того, чтобы пробираться сквозь программный интерфейс класса QMimeData. Если приведение типов оказывается неудачным, мы извлекаем данные стандартным способом.
В этом примере мы кодировали CSV—текст, используя кодировку UTF-8. Если бы мы хотели быть уверенными в применении правильной кодировки, мы могли бы использовать параметр charset в MIME—типе text/plain для явного задания типа кодировки. Ниже приводится несколько примеров: