このページでは

ドロップ先の例

この例では、ドラッグ&ドロップ操作で利用可能なさまざまなMIME形式を区別する方法を示しています。

「ドロップサイト」の例のスクリーンショット

「ドロップサイト」の例は、他のアプリケーションからのドロップを受け付け、ドラッグされたオブジェクトが提供するMIME形式を表示します。

このサンプルには、DropArea クラスとDropSiteWindow クラスの2つのクラス、およびmain() 関数が含まれています。DropArea オブジェクトはDropSiteWindow でインスタンス化され、DropSiteWindow オブジェクトはmain() 関数内で呼び出されます。

DropAreaクラスの定義

DropArea クラスは、QLabel のサブクラスであり、パブリックスロットclear() と、changed() シグナルを持っています。

class DropArea : public QLabel
{
    Q_OBJECT

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

public slots:
    void clear();

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

さらに、DropArea には、QWidget の4つのイベントハンドラが再実装されています:

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

これらのイベントハンドラについては、DropArea クラスの実装でさらに詳しく説明されています。

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

DropAreaクラスの実装

DropArea のコンストラクタでは、minimum size を 200x200 ピクセルに設定し、frame style をQFrame::Sunken およびQFrame::StyledPanel の両方に設定し、その内容を中央に配置します。

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

また、DropArea でドロップイベントを有効にするため、acceptDrops プロパティをtrue に設定します。その後、autoFillBackground プロパティを有効にし、clear() 関数を呼び出します。

dragEnterEvent() イベントハンドラは、ドラッグ操作が行われている最中にマウスがDropArea オブジェクト内に入ったときに呼び出されます。DropSite の例では、マウスがDropArea に入ったときに、そのテキストを「<drop content>」に設定し、背景をハイライト表示します。

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

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

次に、event に対してacceptProposedAction() を呼び出し、ドロップアクションを提案されたものに設定します。最後に、ドロップされたデータとその MIME タイプ情報をパラメータとして、changed() シグナルを発行します。

dragMoveEvent() では、提案されたQDragMoveEvent オブジェクトであるevent を、acceptProposedAction() を通じて受け取るだけです。

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

DropArea クラスにおけるdropEvent() の実装では、event の MIME データを抽出し、それに応じて表示します。

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

mimeData オブジェクトには、画像、HTMLテキスト、Markdownテキスト、プレーンテキスト、またはURLのリストのいずれかが含まれる可能性があります。

    if (mimeData->hasImage()) {
        setPixmap(qvariant_cast<QPixmap>(mimeData->imageData()));
    } else if (mimeData->hasColor()) {
        const auto color = mimeData->colorData().value<QColor>();
        setText(tr("Color: %1").arg(color.name()));
        setPalette(QPalette(color));
        setBackgroundRole(QPalette::Button);
    } 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"));
    }
  • mimeData に画像が含まれている場合、DropArea 内でsetPixmap() を使用してそれを表示します。
  • mimeData に HTML が含まれている場合は、setText() を使用して表示し、DropArea のテキスト形式をQt::RichText に設定します。
  • mimeData に Markdown が含まれている場合は、setText() を使用して表示し、DropArea のテキスト形式をQt::MarkdownText に設定します。
  • mimeData にプレーンテキストが含まれている場合は、setText()を使用して表示し、DropArea のテキスト形式をQt::PlainText に設定します。mimeData にURLが含まれている場合は、URLのリストを順に処理して、それぞれを個別の行に表示します。
  • mimeData に他の種類のオブジェクトが含まれている場合は、ユーザーに通知するため、`DropArea`のテキストを`setText()`で「データを表示できません」に設定します。

その後、DropArea のbackgroundRole をQPalette::Dark に設定し、event が提案したアクションを受け入れます。

    if (!mimeData->hasColor()) {
        setPalette({});
        setBackgroundRole(QPalette::Dark);
    }
    event->acceptProposedAction();
}

dragLeaveEvent() イベントハンドラは、ドラッグが進行中にマウスがウィジェットから離れたときに呼び出されます。

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

DropArea の実装では、clear() を明示的に呼び出した後、提案されたイベントを受け入れます。

clear() 関数は、DropArea 内のテキストを「<drop content>」に設定し、backgroundRole をQPalette::Dark に設定します。最後に、changed() シグナルを発行します。

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

    emit changed();
}

DropSiteWindow クラスの定義

DropSiteWindow クラスには、コンストラクタとパブリックスロット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;
};

また、このクラスには、DropArea 、dropArea 、QLabel 、abstractLabel 、QTableWidget 、formatsTable 、QDialogButtonBox 、buttonBox のプライベートインスタンスと、clearButton およびquitButton という2つのQPushButton オブジェクトが含まれています。

DropSiteWindowクラスの実装

DropSiteWindow のコンストラクタ内で、abstractLabel をインスタンス化し、そのwordWrap プロパティをtrue に設定します。また、adjustSize()関数を呼び出し、abstractLabel のサイズをその内容に合わせて調整します。

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();

次に、dropArea をインスタンス化し、そのchanged() シグナルをDropSiteWindow のupdateFormatsTable() スロットに接続します。

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

次に、QTableWidget オブジェクト「formatsTable 」を設定します。その横方向のヘッダーは、QStringList オブジェクト「labels 」を使用して設定されます。列数は2に設定され、テーブルは編集不可となります。また、formatTable の横方向のヘッダーは、2列目が利用可能な追加スペースを埋めるようにフォーマットされます。

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

3つのQPushButton オブジェクト(clearButton 、copyButton 、およびquitButton )がインスタンス化され、buttonBox (QDialogButtonBox オブジェクト)に追加されています。ここではQDialogButtonBox を使用して、プッシュボタンがプラットフォームのスタイルに準拠したレイアウトで表示されるようにしています。

    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);

`clicked()` のシグナルは、`copyButton`、`clearButton`、および `quitButton ` に対して、それぞれ `copy()`、`clear() `、および `close()` に接続されています。

レイアウトには、ウィジェットを縦方向に配置するために、QVBoxLayout (mainLayout )を使用します。また、ウィンドウのタイトルを「Drop Site」に設定し、最小サイズを350×500ピクセルに設定します。

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

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

次に、updateFormatsTable() 関数について説明します。この関数はformatsTable を更新し、DropArea オブジェクトにドロップされたオブジェクトのMIME形式を表示します。まず、QTableWidget のrowCount プロパティを0に設定します。次に、引数として渡されたQMimeData オブジェクトが有効なオブジェクトであるかどうかを検証します。

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

mimeData が有効であることを確認したら、そのサポートされているフォーマットを順に処理します。

注: formats() 関数は 、mimeData がサポートするすべてのフォーマットを含むQStringList オブジェクトを返します。

    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);

各反復処理内で、QTableWidgetItem 、formatItem を作成し、そのflags をQt::ItemIsEnabled に、text alignment をQt::AlignTop およびQt::AlignLeft に設定します。

QString オブジェクト(text )は、format の内容に基づいてデータを表示するようにカスタマイズされています。QString のsimplified()関数をtext に対して呼び出し、単語の前、後、または単語の間に余分なスペースが含まれていない文字列を取得します。

        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();
        }

format に URL のリストが含まれている場合は、スペースで区切ってそれらを順に処理します。一方、format に画像が含まれている場合は、テキストを 16 進数に変換してデータを表示します。

        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
}

text が適切なデータを含むようにカスタマイズされたら、setItem() を使用して、format とtext の両方をformatsTable に挿入します。最後に、formatsTable の最初の列に対してresizeColumnToContents() を呼び出します。

main() 関数

main() 関数内で、DropSiteWindow をインスタンス化し、そのshow()関数を呼び出します。

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

サンプルプロジェクト @ code.qt.io

© 2026 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.