Knigi-for.me

Жасмин Бланшет - QT 4: программирование GUI на С++

Тут можно читать бесплатно Жасмин Бланшет - QT 4: программирование GUI на С++. Жанр: Программирование издательство -, год -. Так же Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте knigi-for.me (knigi for me) или прочесть краткое содержание, предисловие (аннотацию), описание и ознакомиться с отзывами (комментариями) о произведении.

01 void ProjectListWidget::dropEvent(QDropEvent *event)

02 {

03 ProjectListWidget *source =

04 qobject_cast<ProjectListWidget *>(event->source());

05 if (source && source != this) {

06 addItem(event->mimeData()->text());

07 event->setDropAction(Qt::MoveAction);

08 event->accept();

09 }

10 }

В DropEvent() мы используем функцию QMimeData::text() для получения перенесенного текста и создаем элемент с этим текстом. Нам также необходимо воспринять данное событие как «операцию перетаскивания», чтобы указать исходному виджету на то, что он может теперь удалить первоначальную версию перенесенного элемента.

«Drag-and-drop» — мощный механизм передачи данных между приложениями. Однако в некоторых случаях его можно реализовать, не используя предусмотренные в Qt средства механизма «drag-and-drop». Если нам требуется переносить данные внутри одного виджета некоторого приложения, во многих случаях мы можем просто переопределить функции mousePressEvent() и mouseReleaseEvent().

Поддержка пользовательских типов переносимых объектов

До сих пор в представленных примерах мы полагались на поддержку QMimeData распространенных типов MIME. Так, мы вызывали QMimeData::setText() для создания объекта переноса текста и использовали QMimeData:urls() для получения содержимого объекта переноса типа text/uri-list. Если мы хотим перетаскивать обычный текст, текст в формате HTML, изображения, адреса URL или цвета, мы можем спокойно использовать класс QMimeData. Но если мы хотим перетаскивать пользовательские данные, необходимо сделать выбор между следующими альтернативами:

1. Мы можем обеспечить произвольные данные в виде массива QByteArray, используя функцию QMimeData::setData(), и извлекать их позже, используя функцию QMimeData::data().

2. Мы можем создать подкласс QMimeData и переопределить функции formats() и retrieveData() для обработки наших пользовательских типов данных.

3. Для выполнения операций механизма «drag-and-drop» в рамках одного приложения мы можем создать подкласс QMimeData и хранить данные в любых структурах данных.

Первый подход не требует никаких подклассов, но имеет некоторые недостатки: нам необходимо преобразбвать наши структуры данных в тип QByteArray, даже если переносимый объект не принимается, а если требуется обеспечить несколько MIME—типов, чтобы можно было хорошо взаимодействовать с самыми разными приложениями, нам придется сохранять несколько копий данных (по одной на каждый тип MIME). Если данные имеют большой размер, это может излишне замедлять работу приложения. При использовании второго и третьего подходов можно избежать или свести к минимуму эти проблемы. В этом случае мы получаем полное управление и можем использовать эти два подхода совместно.

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

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—данных. Последовательность форматов обычно несущественна, однако на практике желательно первыми указывать «лучшие» форматы. Приложения, поддерживающие несколько форматов, иногда будут использовать первый подходящий.


Жасмин Бланшет читать все книги автора по порядку

Жасмин Бланшет - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки kniga-for.me.

Все материалы на сайте размещаются его пользователями.
Администратор сайта не несёт ответственности за действия пользователей сайта..
Вы можете направить вашу жалобу на почту knigi.for.me@yandex.ru или заполнить форму обратной связи.