Seminarium Informatyka Prowadzący dr Grzegorz Wójcik

1 Seminarium 2008. Informatyka Prowadzący dr Grzegorz Wój...
Author: Jarosława Trzebiatowski
0 downloads 1 Views

1 Seminarium 2008. Informatyka Prowadzący dr Grzegorz WójcikRozdział 9. Drag and drop. Seminarium 2008. Informatyka Prowadzący dr Grzegorz Wójcik

2 Plan Omówienie działania drag & drop’u Implementacja drag & drop’u„File reader” „Choose project” Drag & drop + niestandardowe obiekty Drag & drop + schowek

3 Zasada Drag & Dropu Przeciągnięcie obiektu i upuszczenie go na Widget, bądź jego komponenty. Źródło: Komponent tej samej aplikacji Zewnętrzna aplikacja

4 File reader Aplikacja umożliwia przeciągnięcie listy URI (czylinajprościej mówiąc zaznaczonego pliku/ów) na QTextBox’a, co skutkuje wczytaniem pliku i odpowiednio ustawieniem tytułu Widgeta.

5 File reader Definicja głównego oknaclass MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(); protected: void dragEnterEvent(QDragEnterEvent *event); void dropEvent(QDropEvent *event); private: bool readFile(const QString &fileName); QTextEdit *textEdit; };

6 File reader Konstruktor. Ustawienie TextBoxa w centrum.Ustawienie (nie)akceptowanych akcji. MainWindow::MainWindow() { textEdit = new QTextEdit; setCentralWidget(textEdit); textEdit->setAcceptDrops(false); setAcceptDrops(true); setWindowTitle(tr("Text Editor")); }

7 File reader dragEnterEvent. Sprawdzenie formatu przeciąganego obiektu.Pozwolenie na wykonanie akcji. void MainWindow::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat("text/uri-list")) event->acceptProposedAction(); }

8 File reader dropEvent. void MainWindow::dropEvent(QDropEvent *event) {QList urls = event->mimeData()->urls(); if (urls.isEmpty()) return; QString fileName = urls.first().toLocalFile(); if (fileName.isEmpty()) if (readFile(fileName)) setWindowTitle(tr("%1 - %2").arg(fileName) .arg(tr("Drag File"))); }

9 Choose project Aplikacja umożliwia przeciągnięcie pracowników, abypracowali przy odpowiednich projektach.

10 Choose project Definicja klasyclass ProjectListWidget : public QListWidget { Q_OBJECT public: ProjectListWidget(QWidget *parent = 0); protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void dragEnterEvent(QDragEnterEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); private: void startDrag(); QPoint startPos; };

11 Choose project Konstruktor.ProjectListWidget::ProjectListWidget(QWidget *parent) : QListWidget(parent) { setAcceptDrops(true); }

12 Choose project Akcja wciśnięcia przycisku myszy na widget’ie.void ProjectListWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) startPos = event->pos(); QListWidget::mousePressEvent(event); }

13 Choose project Akcja przesuwania myszy po widget’ie.void ProjectListWidget::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) startDrag(); } QListWidget::mouseMoveEvent(event);

14 Choose project Rozpoczęcie drag’a. void ProjectListWidget::startDrag(){ QListWidgetItem *item = currentItem(); if (item) { QMimeData *mimeData = new QMimeData; mimeData->setText(item->text()); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); drag->setPixmap(QPixmap(":/images/person.png")); if (drag->start(Qt::MoveAction) == Qt::MoveAction) delete item; }

15 Choose project Akcja rozpoczęcia drag’a na widget’ie.void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event) { ProjectListWidget *source = qobject_cast(event->source()); if (source && source != this) { event->setDropAction(Qt::MoveAction); event->accept(); }

16 Choose project Akcja drag’a na widget’ie.void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event) { ProjectListWidget *source = qobject_cast(event->source()); if (source && source != this) { event->setDropAction(Qt::MoveAction); event->accept(); }

17 Choose project Akcja drop’u na widget’ie.void ProjectListWidget::dropEvent(QDropEvent *event) { ProjectListWidget *source = qobject_cast(event->source()); if (source && source != this) { addItem(event->mimeData()->text()); event->setDropAction(Qt::MoveAction); event->accept(); }

18 Drag & drop + niestandardowe obiektyDlaczego? QMimeData nie wystarcza Typowe dane Pliki Zwykły tekst Chcemy przeciągać niestandardowe dane

19 Drag & drop + niestandardowe obiektyJak to zrobić? Możemy kodować nasz dane np. do QByteArray, a następnie używać QMimeData::setData() i QMimeData::data() Możemy stworzyć podklase QMimeData i nadpisać formats() i retrieveData() W przypadku akcji w obrębie jednej aplikacji, możemy stworzyć podklase QMimeData i trzymać dane w jakiejkolwiek strukturze

20 QTableWidget Widget ma możliwość konwertowania przeciąganiadanych. W przypadku przeciągania danych zaznaczanych na widget’ie konwertuje je i wyświetla w odpowiednim formacie.

21 QTableWidget – I wersjavoid MyTableWidget::mouseMoveEvent(QMouseEvent *event) { if (event->buttons() & Qt::LeftButton) { int distance = (event->pos() - startPos).manhattanLength(); if (distance >= QApplication::startDragDistance()) startDrag(); } QTableWidget::mouseMoveEvent(event);

22 QTableWidget – I wersjavoid MyTableWidget::startDrag() { QString plainText = selectionAsPlainText(); //analogicznie jak w Rozdziale 4. copy() if (plainText.isEmpty()) return; QMimeData *mimeData = new QMimeData; mimeData->setText(plainText); mimeData->setHtml(toHtml(plainText)); mimeData->setData("text/csv", toCsv(plainText).toUtf8()); QDrag *drag = new QDrag(this); drag->setMimeData(mimeData); if (drag->start(Qt::CopyAction | Qt::MoveAction) == Qt::MoveAction) deleteSelection(); }

23 QTableWidget – I wersjaQString MyTableWidget::toCsv(const QString &plainText) { QString result = plainText; result.replace("\\", "\\\\"); result.replace("\"", "\\\""); result.replace("\t", "\", \""); result.replace("\n", "\"\n\""); result.prepend("\""); result.append("\""); return result; }

24 QTableWidget – I wersjaQString MyTableWidget::toHtml(const QString &plainText) { QString result = Qt::escape(plainText); result.replace("\t", ""); result.replace("\n", "\n"); result.prepend("

\n
"); result.append("\n
"); return result; }

25 QTableWidget – I wersjaRed Green Blue //plainText Cyan Yellow Magenta "Red", "Green", "Blue„ //CSV "Cyan", "Yellow", "Magenta"

//HTML (prawie jak :-)
RedGreenBlue
CyanYellowMagenta

26 QTableWidget – I wersjavoid MyTableWidget::dropEvent(QDropEvent *event) { if (event->mimeData()->hasFormat("text/csv")) { QByteArray csvData = event->mimeData()- >data("text/csv"); QString csvText = QString::fromUtf8(csvData); ... event->acceptProposedAction(); } else if (event->mimeData()->hasFormat("text/plain")) { QString plainText = event->mimeData()->text(); }

27 QTableWidget – I wersjaAkceptujemy tylko 2 formaty. HTML – możemy przeciągnąć poza QTableWidget, ale na QTableWidget już nie przyjmujemy.

28 QTableWidget – II wersjaPotencjalnie szybsza. W I wersji kosztowna może być konwersja na QByteArray. W II tworzymy podklasę QMimeData.

29 QTableWidget – II wersjaclass TableMimeData : public QMimeData { Q_OBJECT public: TableMimeData(const QTableWidget *tableWidget, const QTableWidgetSelectionRange &range); const QTableWidget *tableWidget() const { return myTableWidget; } QTableWidgetSelectionRange range() const { return myRange; } QStringList formats() const; protected: QVariant retrieveData(const QString &format, QVariant::Type preferredType) const; private: static QString toHtml(const QString &plainText); static QString toCsv(const QString &plainText); QString text(int row, int column) const; QString rangeAsPlainText() const; const QTableWidget *myTableWidget; QTableWidgetSelectionRange myRange; QStringList myFormats; };

30 QTableWidget – II wersjaPrzechowujemy wskaźnik do naszej tabeli oraz zakres, czyli zbiór komórek. Ponadto, jak wspomniano powyżej, musimy ponownie zaimplementować funkcje formats() i retrieveData().

31 QTableWidget – II wersjaPrzepisujemy i przypisujemy odpowiednie dane. TableMimeData::TableMimeData(const QTableWidget *tableWidget, const QTableWidgetSelectionRange &range) { myTableWidget = tableWidget; myRange = range; myFormats << "text/csv" << "text/html" << "text/plain"; }

32 QTableWidget – II wersjaQStringList TableMimeData::formats() const { return myFormats; }

33 QTableWidget – II wersjaZwracamy dane w odpowiednim formacie. QVariant TableMimeData::retrieveData(const QString &format, QVariant::Type preferredType) const { if (format == "text/plain") { return rangeAsPlainText(); } else if (format == "text/csv") { return toCsv(rangeAsPlainText()); } else if (format == "text/html") { return toHtml(rangeAsPlainText()); } else { return QMimeData::retrieveData(format, preferredType); }

34 QTableWidget – II wersjavoid MyTableWidget::dropEvent(QDropEvent *event) { const TableMimeData *tableData = qobject_cast(event->mimeData()); if (tableData) { const QTableWidget *otherTable = tableData->tableWidget(); QTableWidgetSelectionRange otherRange = tableData->range(); ... event->acceptProposedAction(); } else if (event->mimeData()->hasFormat("text/csv")) { QByteArray csvData = event->mimeData()->data("text/csv"); QString csvText = QString::fromUtf8(csvData); } else if (event->mimeData()->hasFormat("text/plain")) { QString plainText = event->mimeData()->text(); } QTableWidget::mouseMoveEvent(event);

35 Drag & drop + schowek Znajdziemy pod QApplication::clipboard().QClipboard posiada metody: setPixmap(), pixmap() setText(), text() setImage(), image() QTextEdit posiada metody: cut() copy() paste()

36 Drag & drop + schowek Czasem nie wystarcza nam zwykły schowek, gdy np. mamy dane nie będące tekstem, ani obrazem. Problem rozwiązujemy podobnie jak przed kilkoma slajdami. Tworzymy podklasę QClipboard i implementujemy odpowiednie metody, np. setMimedata(), mimedata()

37 Drag & drop + schowek Selection Supportowane tylko na X11Aby uzyskać dostęp do zaznaczonego tekstu należy: sprawdzić czy Selection jest supportowane przekazać w parametrze QClipboard::Selection

38 Drag & drop + schowek void MyTextEditor::mouseReleaseEvent(QMouseEvent *event) { QClipboard *clipboard = QApplication::clipboard(); if (event->button() == Qt::MidButton && clipboard->supportsSelection()) { QString text = clipboard->text(QClipboard::Selection); pasteText(text); }

39 Rozdział 9. Drag and drop. Dziękuje