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

标签 c++ qt drag-and-drop qt5

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

我现在不仅想在拖动开始时收到通知,而且在拖动中断时收到通知(通过按ESC或拖放到某处在虚空)。 (我的目标是发现一个隐藏的小部件,一旦拖动操作被打断,我就可以将其放置在其上的项目再次隐藏。)

我抓取了文档,但发现了任何有希望的东西 - 有人已经完成了吗?

有一个相当similar question已经但是它没有得到有用的答案而且它已经两年了 - 所以也许 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"

关于c++ - 如何跟踪拖放操作的生命周期?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37846521/

相关文章:

jquery - 如何显示在html5中拖动内容时显示的标签?

c++ - str.find() 似乎忽略了字符串中的第一个字符

jQuery 拖放 - 删除的元素不能再次删除

c++ - 是否建议显式地使重写函数成为虚拟的?

c++ - 没有线程安全开销的 QSharedPointer?

qt - QCheckBox 自动换行

c++ - 如何获得 QTreeWidget 内部项目移动的通知?

iphone - 拖放 TableView Cell 到 Tapkus 日历

c++ - 到 GC 或不到 GC

c++ - CPPCheck 返回不一致的结果