Drop-Site-Beispiel

Das Beispiel zeigt, wie die verschiedenen MIME-Formate unterschieden werden können, die bei einem Drag&Drop-Vorgang verfügbar sind.

Screenshot of the Drop Site example

Das Drop-Site-Beispiel akzeptiert Ablegevorgänge aus anderen Anwendungen und zeigt die MIME-Formate an, die durch das Drag-Objekt bereitgestellt werden.

In diesem Beispiel gibt es zwei Klassen, DropArea und DropSiteWindow, und eine Funktion main(). Ein DropArea Objekt wird in DropSiteWindow instanziiert; ein DropSiteWindow Objekt wird dann in der Funktion main() aufgerufen.

DropArea-Klassendefinition

Die Klasse DropArea ist eine Unterklasse von QLabel mit einem öffentlichen Slot, clear(), und einem Signal changed().

class DropArea : public QLabel
{
    Q_OBJECT

public:
    explicit DropArea(QWidget *parent = nullptr);

public slots:
    void clear();

signals:
    void changed(const QMimeData *mimeData = nullptr);

Darüber hinaus enthält DropArea Reimplementierungen von vier QWidget Event-Handlern:

  1. dragEnterEvent()
  2. dragMoveEvent()
  3. dragLeaveEvent()
  4. dropEvent()

Diese Ereignishandler werden in der Implementierung der Klasse DropArea näher erläutert.

protected:
    void dragEnterEvent(QDragEnterEvent *event) override;
    void dragMoveEvent(QDragMoveEvent *event) override;
    void dragLeaveEvent(QDragLeaveEvent *event) override;
    void dropEvent(QDropEvent *event) override;
};

Implementierung der DropArea-Klasse

Im DropArea -Konstruktor setzen wir minimum size auf 200x200 Pixel, frame style auf QFrame::Sunken und QFrame::StyledPanel und richten den Inhalt in der Mitte aus.

DropArea::DropArea(QWidget *parent)
    : QLabel(parent)
{
    setMinimumSize(200, 200);
    setFrameStyle(QFrame::Sunken | QFrame::StyledPanel);
    setAlignment(Qt::AlignCenter);
    setAcceptDrops(true);
    setAutoFillBackground(true);
    clear();
}

Außerdem aktivieren wir Drop-Ereignisse in DropArea, indem wir die Eigenschaft acceptDrops auf true setzen. Dann aktivieren wir die Eigenschaft autoFillBackground und rufen die Funktion clear() auf.

Der Event-Handler dragEnterEvent() wird aufgerufen, wenn ein Ziehen im Gange ist und die Maus in das Objekt DropArea eintritt. Für das Beispiel DropSite setzen wir, wenn die Maus in DropArea eintritt, den Text auf "<Inhalt ablegen>" und heben den Hintergrund hervor.

void DropArea::dragEnterEvent(QDragEnterEvent *event)
{
    setText(tr("<drop content>"));
    setBackgroundRole(QPalette::Highlight);

    event->acceptProposedAction();
    emit changed(event->mimeData());
}

Dann rufen wir acceptProposedAction() auf event auf und setzen die Drop-Aktion auf den vorgeschlagenen Wert. Zum Schluss wird das Signal changed() mit den abgelegten Daten und den MIME-Typ-Informationen als Parameter ausgegeben.

Für dragMoveEvent() akzeptieren wir einfach das vorgeschlagene QDragMoveEvent Objekt, event, mit acceptProposedAction().

void DropArea::dragMoveEvent(QDragMoveEvent *event)
{
    event->acceptProposedAction();
}

Die Implementierung von dropEvent() in der Klasse DropArea extrahiert die MIME-Daten von event und zeigt sie entsprechend an.

void DropArea::dropEvent(QDropEvent *event)
{
    const QMimeData *mimeData = event->mimeData();

Das Objekt mimeData kann eines der folgenden Objekte enthalten: ein Bild, HTML-Text, Markdown-Text, reinen Text oder eine Liste von URLs.

    if (mimeData->hasImage()) {
        setPixmap(qvariant_cast<QPixmap>(mimeData->imageData()));
    } else if (mimeData->hasFormat(u"text/markdown"_s)) {
        setText(QString::fromUtf8(mimeData->data(u"text/markdown"_s)));
        setTextFormat(Qt::MarkdownText);
    } else if (mimeData->hasHtml()) {
        setText(mimeData->html());
        setTextFormat(Qt::RichText);
    } else if (mimeData->hasText()) {
        setText(mimeData->text());
        setTextFormat(Qt::PlainText);
    } else if (mimeData->hasUrls()) {
        QList<QUrl> urlList = mimeData->urls();
        QString text;
        for (qsizetype i = 0, count = qMin(urlList.size(), qsizetype(32)); i < count; ++i)
            text += urlList.at(i).path() + u'\n';
        setText(text);
    } else {
        setText(tr("Cannot display data"));
    }
  • Wenn mimeData ein Bild enthält, wird es in DropArea mit setPixmap() angezeigt.
  • Wenn mimeData HTML enthält, wird es mit setText() angezeigt und das Textformat von DropArea wird auf Qt::RichText gesetzt.
  • Wenn mimeData Markdown enthält, wird es mit setText() angezeigt, und das Textformat von DropArea wird auf Qt::MarkdownText gesetzt.
  • Wenn mimeData reinen Text enthält, wird er mit setText() angezeigt und das Textformat von DropArea wird auf Qt::PlainText gesetzt. Falls mimeData URLs enthält, wird die Liste der URLs durchlaufen, um sie in einzelnen Zeilen anzuzeigen.
  • Wenn mimeData andere Arten von Objekten enthält, setzen wir den Text von DropArea mit setText() auf "Cannot display data", um den Benutzer zu informieren.

Wir setzen dann DropArea's backgroundRole auf QPalette::Dark und akzeptieren event's vorgeschlagene Aktion.

    setBackgroundRole(QPalette::Dark);
    event->acceptProposedAction();
}

Der dragLeaveEvent()-Ereignishandler wird aufgerufen, wenn ein Ziehen stattfindet und die Maus das Widget verlässt.

void DropArea::dragLeaveEvent(QDragLeaveEvent *event)
{
    clear();
    event->accept();
}

Für die Implementierung von DropArea rufen wir clear() auf und akzeptieren dann das vorgeschlagene Ereignis.

Die Funktion clear() setzt den Text in DropArea auf "<Inhalt ablegen>" und setzt backgroundRole auf QPalette::Dark. Schließlich gibt sie das Signal changed() aus.

void DropArea::clear()
{
    setText(tr("<drop content>"));
    setBackgroundRole(QPalette::Dark);

    emit changed();
}

Definition der DropSiteWindow-Klasse

Die Klasse DropSiteWindow enthält einen Konstruktor und einen öffentlichen Slot, updateFormatsTable().

class DropSiteWindow : public QWidget
{
    Q_OBJECT

public:
    DropSiteWindow();

public slots:
    void updateFormatsTable(const QMimeData *mimeData);
    void copy();

private:
    DropArea *dropArea;
    QLabel *abstractLabel;
    QTableWidget *formatsTable;

    QPushButton *clearButton;
    QPushButton *copyButton;
    QPushButton *quitButton;
    QDialogButtonBox *buttonBox;
};

Die Klasse enthält außerdem eine private Instanz von DropArea, dropArea, QLabel, abstractLabel, QTableWidget, formatsTable, QDialogButtonBox, buttonBox und zwei QPushButton Objekte, clearButton und quitButton.

Implementierung der DropSiteWindow-Klasse

Im Konstruktor von DropSiteWindow instanziieren wir abstractLabel und setzen die Eigenschaft wordWrap auf true. Wir rufen auch die Funktion adjustSize() auf, um die Größe von abstractLabel entsprechend seinem Inhalt anzupassen.

DropSiteWindow::DropSiteWindow()
{
    abstractLabel = new QLabel(tr("This example accepts drags from other "
                                  "applications and displays the MIME types "
                                  "provided by the drag object."));
    abstractLabel->setWordWrap(true);
    abstractLabel->adjustSize();

Dann instanziieren wir dropArea und verbinden sein changed() -Signal mit dem updateFormatsTable() -Slot von DropSiteWindow.

    dropArea = new DropArea;
    connect(dropArea, &DropArea::changed,
            this, &DropSiteWindow::updateFormatsTable);

Wir richten nun das Objekt QTableWidget ein, formatsTable. Seine horizontale Kopfzeile wird über ein QStringList Objekt, labels, festgelegt. Die Anzahl der Spalten wird auf zwei festgelegt und die Tabelle ist nicht editierbar. Außerdem wird die horizontale Kopfzeile von formatTable so formatiert, dass sich die zweite Spalte ausdehnt, um den zusätzlich verfügbaren Platz zu belegen.

    formatsTable = new QTableWidget;
    formatsTable->setColumnCount(2);
    formatsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
    formatsTable->setHorizontalHeaderLabels({tr("Format"),  tr("Content")});
    formatsTable->horizontalHeader()->setStretchLastSection(true);

Drei QPushButton Objekte, clearButton, copyButton und quitButton, werden instanziiert und zu buttonBox - einem QDialogButtonBox Objekt - hinzugefügt. Wir verwenden QDialogButtonBox hier, um sicherzustellen, dass die Drucktasten in einem Layout dargestellt werden, das dem Stil der Plattform entspricht.

    clearButton = new QPushButton(tr("Clear"));
    copyButton = new QPushButton(tr("Copy"));
    quitButton = new QPushButton(tr("Quit"));

    buttonBox = new QDialogButtonBox;
    buttonBox->addButton(clearButton, QDialogButtonBox::ActionRole);
    buttonBox->addButton(copyButton, QDialogButtonBox::ActionRole);
#if !QT_CONFIG(clipboard)
    copyButton->setVisible(false);
#endif

    buttonBox->addButton(quitButton, QDialogButtonBox::RejectRole);

    connect(quitButton, &QAbstractButton::clicked, this, &QWidget::close);
    connect(clearButton, &QAbstractButton::clicked, dropArea, &DropArea::clear);
    connect(copyButton, &QAbstractButton::clicked, this, &DropSiteWindow::copy);

Die clicked()-Signale für copyButton, clearButton und quitButton werden mit copy(), clear() bzw. close() verbunden.

Für das Layout verwenden wir ein QVBoxLayout, mainLayout, um unsere Widgets vertikal anzuordnen. Außerdem setzen wir den Fenstertitel auf "Drop Site" und die Mindestgröße auf 350x500 Pixel.

    QVBoxLayout *mainLayout = new QVBoxLayout(this);
    mainLayout->addWidget(abstractLabel);
    mainLayout->addWidget(dropArea);
    mainLayout->addWidget(formatsTable);
    mainLayout->addWidget(buttonBox);

    setWindowTitle(tr("Drop Site"));
    resize(700, 500);
}

Weiter geht es mit der Funktion updateFormatsTable(). Diese Funktion aktualisiert formatsTable und zeigt die MIME-Formate des Objekts an, das auf das Objekt DropArea abgelegt wurde. Zuerst setzen wir die Eigenschaft rowCount von QTableWidget auf 0. Dann überprüfen wir, ob das übergebene Objekt QMimeData ein gültiges Objekt ist.

void DropSiteWindow::updateFormatsTable(const QMimeData *mimeData)
{
    formatsTable->setRowCount(0);
    copyButton->setEnabled(false);
    if (!mimeData)
        return;

Sobald wir sicher sind, dass mimeData gültig ist, gehen wir die unterstützten Formate durch.

Hinweis: Die Funktion formats() gibt ein QStringList Objekt zurück, das alle von mimeData unterstützten Formate enthält.

    const QStringList formats = mimeData->formats();
    for (const QString &format : formats) {
        QTableWidgetItem *formatItem = new QTableWidgetItem(format);
        formatItem->setFlags(Qt::ItemIsEnabled);
        formatItem->setTextAlignment(Qt::AlignTop | Qt::AlignLeft);

In jeder Iteration erstellen wir ein QTableWidgetItem, formatItem und setzen sein flags auf Qt::ItemIsEnabled und sein text alignment auf Qt::AlignTop und Qt::AlignLeft.

Ein QString -Objekt, text, wird so angepasst, dass es Daten entsprechend dem Inhalt von format anzeigt. Wir rufen die Funktion simplified() von QString auf text auf, um eine Zeichenkette zu erhalten, die keine zusätzlichen Leerzeichen vor, nach oder zwischen den Wörtern enthält.

        QString text;
        if (format == u"text/plain") {
            text = mimeData->text().simplified();
        } else if (format == u"text/markdown") {
            text = QString::fromUtf8(mimeData->data(u"text/markdown"_s));
        } else if (format == u"text/html") {
            text = mimeData->html().simplified();
        } else if (format == u"text/uri-list") {
            QList<QUrl> urlList = mimeData->urls();
            for (qsizetype i = 0, count = qMin(urlList.size(), qsizetype(32)); i < count; ++i)
                text.append(urlList.at(i).toString() + u' ');
        } else {
            QByteArray data = mimeData->data(format);
            if (data.size() > 32)
                data.truncate(32);
            text = QString::fromLatin1(data.toHex(' ')).toUpper();
        }

Wenn format eine Liste von URLs enthält, werden diese durchlaufen und durch Leerzeichen getrennt. Enthält format dagegen ein Bild, werden die Daten durch Konvertierung des Textes in Hexadezimalzahlen angezeigt.

        int row = formatsTable->rowCount();
        formatsTable->insertRow(row);
        formatsTable->setItem(row, 0, new QTableWidgetItem(format));
        formatsTable->setItem(row, 1, new QTableWidgetItem(text));
    }

    formatsTable->resizeColumnToContents(0);
#if QT_CONFIG(clipboard)
    copyButton->setEnabled(formatsTable->rowCount() > 0);
#endif
}

Nachdem text so angepasst wurde, dass es die entsprechenden Daten enthält, fügen wir sowohl format als auch text mit setItem() in formatsTable ein. Schließlich rufen wir resizeColumnToContents() für die erste Spalte von formatsTable auf.

Die Funktion main()

Innerhalb der Funktion main() instanziieren wir DropSiteWindow und rufen die Funktion show() auf.

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    DropSiteWindow window;
    window.show();
    return app.exec();
}

Beispielprojekt @ code.qt.io

© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.