2016-06-15 12 views
1

私は、など私がstartDrag()dragEnterEvent()dropEvent()を使用して変更QLabelにに修正QListWidgetから&ドロップアイテムをドラッグしてみましょうアプリケーションを、持っているドラッグアンドドロップ操作の有効期間を追跡するにはどうすればよいですか?

私は今 開始をドラッグしたときにのみ、通知を受けるしないようにしたい

が中断されたときにも(ESCを押すか、または空白のどこかにドロップすることによって)が中断されます。 (私の目標は、隠しウィジェットを発見することです。ドラッグ操作が中断されると、すぐに隠れるアイテムをドロップすることができます)

私はドキュメントをクロールしましたが、有望なものを見つけました。

すでにかなりsimilar questionがありますが、それは有用な回答を得られず、それは2歳です - Qt5によって導入された新しいトリッキーがいくつかありますか?

+0

この質問は全く別の意図を持っている:私はドラッグを知らさ&ドロップ操作得ることができる方法を知りたい終了した - 有効なターゲットにドロップすることにより、または中止されることによってどちらか(無効領域にまたはを押してドロップ'ESC')もう1つの質問は、ソースウィジェット' mimeData() 'メソッドが呼び出されるたびに、' QMimeData'の新しいインスタンスを作成することによるメモリリークを回避する方法です。 – frans

+0

これは誤解されています。 – AlexanderVX

+0

この質問を重複しないでください、またはタイトルを編集する必要がありますか? – frans

答えて

1

少なくとも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インスタンスで呼び出されたかどうかを知りたいと思います。したがって、制御がイベントループに戻る(戻りまたは再入力による)後、QDragインスタンスの存在を確認する必要があります。

QAbstractItemViewの子であるQDragを利用することができます。ドラッグが開始されたら、インスタンスを見つけてその存続時間を追跡できます。ライフモニタリングでは、現時点で疑似同期ドラッグの実装に対処するために、イベントループにファンクタをポストする必要があります。ドラッグが完全に非同期になると、以下のコードは動作します。

// 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" 
+0

http://stackoverflow.com/q/37846843/1668622のように、この回答は私のためには機能しません。ラベルテキストは設定されますがクリアされません。 – frans

+0

@frans逆に、答えはうまく起こっていることを示しています - Qtバグ。最初のコードスニペット(より簡単な 'startDrag')もドラッグの終了を知らせなければ、' QDrag'だけでなくイベントループが複数回再入力される非常に深刻なバグを示します。これは、 'deleteLater'が制御が最も外側のイベントループに戻るまで延期されるので、複数の他のメモリリークを引き起こします。 Qtバグと戦わないでください:修正したり報告したりしてください。あなたは間違って何もしていない、それは動作するはずであり、回避策の必要はありません。 –

+0

@frans IOW、これは間違いなく 'QDrag'の有効期間を追跡し、ドラッグが終了した後でも' QDrag'が保持されるバグを強調表示します。私はWindowsでチェックして、そこにも正しく動作します。あなたはX11関連のQtバグを見つけました。それを報告する。あなたはすでにテストケースを持っています。 –

関連する問題