ドロップサイトの例

この例では、ドラッグ&ドロップ操作で利用可能なさまざまなMIMEフォーマットを区別する方法を示します。

Screenshot of the Drop Site example

ドロップ・サイトの例では、他のアプリケーションからのドロップを受け付け、ドラッグ・オブジェクトが提供するMIMEフォーマットを表示します。

この例では、DropAreaDropSiteWindow の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 には、4つのQWidget イベント・ハンドラの再実装が含まれています:

  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 styleQFrame::SunkenQFrame::StyledPanel の両方に設定し、その内容を中央に揃えます。

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

また、acceptDrops プロパティをtrue に設定することで、DropArea のドロップ・イベントを有効にします。次に、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());
}

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

dragMoveEvent()については、提案されたQDragMoveEvent オブジェクト、eventacceptProposedAction()で受け入れるだけである。

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->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 に画像が含まれている場合、DropAreasetPixmap() で表示します。
  • mimeData にHTMLが含まれている場合は、setText() で表示し、DropArea のテキスト・フォーマットをQt::RichText に設定する。
  • mimeData にMarkdownが含まれている場合は、setText() で表示し、DropArea のテキスト・フォーマットをQt::MarkdownText とします。
  • mimeData にプレーン・テキストが含まれている場合、setText() で表示し、DropArea のテキスト・フォーマットをQt::PlainText に設定します。mimeData に URL が含まれている場合は、URL のリストを繰り返し、個々の行に表示する。
  • mimeData に他の種類のオブジェクトが含まれている場合、DropArea のテキストを、setText() を "Cannot display data" に設定して、ユーザーに通知する。

次に、DropArea'のbackgroundRoleQPalette::Dark に設定し、event'のアクション案を受け入れる。

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

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

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

DropArea'の実装では、clear() をクリアしてから、提案されたイベントを受け入れます。

clear() 関数は、DropArea のテキストを "<drop content>" に設定し、backgroundRoleQPalette::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;
};

また、DropAreadropAreaQLabelabstractLabelQTableWidgetformatsTableQDialogButtonBoxbuttonBox 、2つのQPushButton オブジェクト、clearButtonquitButton のプライベート・インスタンスも含まれています。

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() シグナルをDropSiteWindowupdateFormatsTable() スロットに接続する。

    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 オブジェクト、clearButtoncopyButtonquitButton がインスタンス化され、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);

copyButtonclearButtonquitButtonclicked() シグナルは、それぞれcopy()clear()close() に接続されている。

レイアウトには、QVBoxLayoutmainLayout を使い、ウィジェットを縦に並べる。また、ウィンドウのタイトルを "Drop Site "に設定し、最小サイズを350x500ピクセルに設定します。

    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 フォーマットを表示します。まず、QTableWidgetrowCount プロパティを 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);

各反復の中で、QTableWidgetItemformatItem を作成し、flagsQt::ItemIsEnabled に、text alignmentQt::AlignTopQt::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 が適切なデータを含むようにカスタマイズされたら、formattext の両方をsetItem() で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

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