Chyba każdy wie jak działa system drag&drop czyli popularne „przeciągnij i upuść”. Jest to bardzo pożyteczna rzecz, szczególnie przy dodawaniu jakiś elementów do aplikacji np plików. Wiele aplikacji pracujących z plikami udostępnia takie dodawanie, więc czemu w swojej aplikacji napisanej w Qt nie zrobić tego samego. Dziś skupię się na przechwytywaniu elementów z innej aplikacji. Oczywiście nie jest to nic trudnego.
Reimplementujemy cztery zdarzenia:
- dragEnterEvent()
- dragMoveEvent()
- dragLeaveEvent()
- dropEvent()
dragEnterEvent() - Zdarzenie wywoływane kiedy „przeciągamy element” i kursor myszy znajdzie się nad widżetem.
dragMoveEvent() - Zdarzenie wywoływane kiedy poruszamy kursorem myszy z „przeciąganym elementem” nad widżetem.
dragLeaveEvent() - Zdarzenie wywoływane kiedy kursor myszy z „przeciąganym elementem” opuści widżet.
dropEvent() - Zdarzenie wywoływane kiedy „upuścimy” przeciągany element.
Aby było to możliwe tworzymy sobie dowolną klasę, która dziedziczy pośrednio lub bezpośrednio po klasie QWidget. Następnie zabieramy się za reimplementacje zdarzeń.
class dropWidget : public QLabel { Q_OBJECT public: explicit dropWidget(QWidget *parent = 0); protected: void dragEnterEvent(QDragEnterEvent *event); void dragLeaveEvent(QDragLeaveEvent *event); void dragMoveEvent(QDragMoveEvent *event); void dropEvent(QDropEvent *event); };
Aby system działał musimy jeszcze w konstruktorze ustawić wartość acceptDrops na true.
this->setAcceptDrops(true);
Reagować będziemy w zdarzeniu dropEvent() czyli „upuszczeniu elementu przeciąganego”. W innych zdarzeniach nie podejmujemy żadnych konkretnych akcji, dlatego ich ciała wyglądają następująco:
void dropWidget::dragEnterEvent(QDragEnterEvent *event) { //tutaj reagujemy na zdarzenie (jeśli chcemy) ... event->acceptProposedAction(); } void dropWidget::dragLeaveEvent(QDragLeaveEvent *event) { //tutaj reagujemy na zdarzenie (jeśli chcemy) ... event->accept(); } void dropWidget::dragMoveEvent(QDragMoveEvent *event) { //tutaj reagujemy na zdarzenie (jeśli chcemy) ... event->acceptProposedAction(); }
Wywołanie:
event->acceptProposedAction();
powoduje ustawienie „upuszczenia” jako proponowanej akcji. Przechwycony elementy, czyli obiekt typu QMineData może zawierać 4 rzeczy:
- obraz
- HTML tekst
- zwykły tekst
- listę URL-i
Sprawdzamy co odebraliśmy i zależnie od tego obsługujemy zdarzenie:
void dropWidget::dropEvent(QDropEvent *event) { const QMimeData *mimeData = event->mimeData(); if (mimeData->hasImage()) { //reakcja w przypadku obrazu setPixmap(qvariant_cast<QPixmap>(mimeData->imageData())); qDebug("image"); } else if (mimeData->hasHtml()) { //reakcja w przypadku kodu html setText(mimeData->html()); setTextFormat(Qt::RichText); qDebug("html"); } else if (mimeData->hasText()) { //reakcja w przypadku tekstu setText(mimeData->text()); setTextFormat(Qt::PlainText); qDebug("text"); } else if (mimeData->hasUrls()) { //reakcja w przypadku url QList<QUrl> urlList = mimeData->urls(); QString text; for (int i = 0; i < urlList.size(); ++i) { QString url = urlList.at(i).path(); text += url + QString("\n"); } setText(text); qDebug("url"); } else { setText(tr("Nieznany typ")); } }
Oczywiście możemy reagować na swój własny sposób