繁体   English   中英

如何跟踪拖放操作的生命周期?

[英]How to track the lifetime of a Drag/Drop operation?

我有一个应用程序,让我使用startDrag()dragEnterEvent()dropEvent()等将项目从修改后的QListWidget拖放到修改后的QLabel

现在,我不仅要在开始拖动得到通知,而且还要在拖动被中断时得到通知(通过按ESC或将其放在空白处)。 (我的目标是发现一个隐藏的小部件,我可以在拖动操作中断后立即放下可再次隐藏的项目。)

我抓取了文档,但发现有希望的东西-有人已经做到了吗?

已经有一个非常类似的问题,但是它没有得到有用的答案,而且已经有两年历史了,所以Qt5也许引入了一些新的技巧?

在至少直到Qt 5.7的Qt 4中,拖动是伪同步的。 它从输入QListWidget::startDrag并调用QDrag::exec() ,到QListWidget::startDrag返回时结束。 因此,您可能具有:

void startDrag(Qt::DropActions supportedActions) override {
   emit dragStarted();
   QListWidget::startDrag(supportedActions); // reenters the event loop
   emit dragStopped();
}

轻松实现,如果它忽略拖动是否实际发生(可以将其滤除)。

但是这种实现可能会发生变化,并且确实应该发生变化:重新进入事件循环是一团糟。 而且我们还想知道QDrag::exec()是否真的在QDrag实例上调用了。 因此,在控件返回到事件循环之后(通过返回或重新进入),我们需要检查QDrag实例是否存在。

我们可以利用QDrag作为QAbstractItemView的子级。 拖动开始后,您可以找到实例并跟踪其生命周期。 生命周期监视需要将函子发布到事件循环中,以应对当前的伪同步拖动实现。 如果/当拖动变为完全异步时,下面的代码仍然可以使用。

// https://github.com/KubaO/stackoverflown/tree/master/questions/drag-lifetime-37846521
#include <QtWidgets>

template <typename F>
static void postToThread(F && fun, QObject * obj = qApp) {
   QObject src;
   QObject::connect(&src, &QObject::destroyed, obj, std::forward<F>(fun),
                    Qt::QueuedConnection);
}

struct MyListWidget : QListWidget {
   Q_SIGNAL void dragStarted();
   Q_SIGNAL void dragStopped();
   MyListWidget() {
      setDragEnabled(true);
      addItem("item1");
      addItem("item2");
   }
   void startDrag(Qt::DropActions supportedActions) override {
      postToThread([this]{
         auto drag = findChild<QDrag*>();
         if (drag) {
            emit dragStarted();
            connect(drag, &QObject::destroyed, this, &MyListWidget::dragStopped);
         }
      }, this);
      QListWidget::startDrag(supportedActions); // reenters the event loop
   }
   Q_OBJECT
};

int main(int argc, char **argv) {
   QApplication app(argc, argv);
   QWidget gui;
   QVBoxLayout layout(&gui);
   MyListWidget list;
   QLabel label;
   layout.addWidget(&list);
   layout.addWidget(&label);
   QObject::connect(&list, &MyListWidget::dragStarted, [&]{ label.setText("Drag Active"); });
   QObject::connect(&list, &MyListWidget::dragStopped, [&]{ label.clear(); });
   gui.show();
   return app.exec();
}
#include "main.moc"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM