Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. International
  3. Japanese
  4. [SOLVED] Drag and Drop の動作,実装方法など
QtWS25 Last Chance

[SOLVED] Drag and Drop の動作,実装方法など

Scheduled Pinned Locked Moved Japanese
4 Posts 1 Posters 9.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • A Offline
    A Offline
    Atsushi4
    wrote on 6 Aug 2011, 06:03 last edited by
    #1

    特にQGraphicsView周りのD&Dイベント処理がややこしかったので覚書。
    Qt4.7.2,Windows7Homeで確認。その他の環境は未確認。
    acceptする,しないはevent->accept()をコールする,しないの意味。
    実装方法は,各クラスを継承した自作クラスで(一つのクラスのみで)D&Dを実装する方法。

    ※※※ 筆者は残念なプログラマなので信憑性もそれに順ずる。

    • QWidget:
      acceptDrops既定値はfalse。acceptDropsをtrueにしないとハンドラが呼ばれない。
      TopLevelWidgetかつ子WidgetにacceptDropsがtrueのWidgetを持つ場合は
      Window表示時に自動でsetAcceptDrops(true)される。
      dragEnterEventでacceptしないとその他のハンドラが呼ばれない。
      dragMoveEventは処理しなくても良い。
       * 実装方法:
       dragEnterEventでaccept,
       dropEventでdrop時の処理を実装して,acceptDropsをtrueにする。

    • QGraphicsView:
      acceptDrops既定値はtrue。acceptDropsをfalseにすればハンドラは呼ばれない。
      Sceneがセットされていない時はQWidgetと同じ。Sceneがセットされると以下の動作をする。
      dragEnterEventでacceptしなくてもdragMoveEventは呼ばれる。
      各ハンドラではイベントをScene用にマッピングしてSceneに渡す。
      dragMoveEventではSceneの処理結果でacceptを上書き(setAccept)する。
      結果,dragEnterEventでacceptしてもdragMoveEventで上書きされてしまう。
       * 実装方法1(ViewのみでD&Dを受付け,Sceneにイベントを渡さない):
       dragEnterEvent,dragMoveEvent,dragLeaveEvent,dropEventを,基底クラスの関数を呼ばないように上書きする。
       あとはQWidgetと同じ。
       * 実装方法2(Viewの全域でD&Dを受け付けるがSceneにもイベントを渡す):
       dragMoveEventで基底クラスの関数を呼んだ後にacceptする。
       dropEventではdrop時の処理を実装し,基底クラスの関数を呼ぶ。

    • QGraphicsScene
      各ハンドラはViewを経由して呼び出される。
      Sceneにポジションマッピング済みのイベントを受け取るので,Scene上の位置が必要ならこちらが便利。
      dragMoveEventではItemのacceptDropsがtrueの場合のみ
      ItemのdragEnterEvent,dragMoveEvent,dragLeaveEventを呼び出す。
      有効なItemが無ければeventはisAcceptedはfalseかつIgnoreActionをセットされる。
       * 実装方法1(SceneのみでD&Dを受付け,Itemにイベントを渡さない):
       dragMoveEventでacceptし,基底クラスの関数を呼び出さない。
       dropEventではdrop時の処理を実装する(基底クラスの関数は呼んでもItemにイベントは渡らない)。
       * 実装方法2(Scene全域でD&Dを受付けるがItemにもイベントを渡す):
       dragMoveEventで基底クラスの関数を呼んだ後に
       event->accept()とevent->setDropAction(Qt::DropAction)を呼ぶ。
       DropActionはCopyActionなら+付き,LinkActionなら矢印付き,MoveActionなら何もつかない四角形の
       アイコン(マウスカーソル)になる(Windows7の場合)。
       ※ Item上ではItem固有のアイコンにする場合は,dropActionがIgnoreActionの場合のみsetDropActionする。

    • QGraphicsItem
      acceptDrops既定値はfalse。
      acceptDropsをtrueにしておくと,dragEnterEvent又はdragMoveEventでevent->ignoreしない限りdropEventは呼ばれる。
       * 実装方法:
       dropEventにdrop時の処理を実装して,acceptDropsをtrueにする。

    その他:
     QGraphicsViewやQTextEditなど,acceptDropsの既定値がtrueのWidgetを置くと
     親WidgetでD&Dイベントを受け取れなくなる。
     親WidgetでD&Dイベントを処理するならこれらのWidgetにsetAcceptDrops(false)するか,
     必要に応じてevent->ignore()するように再定義した派生クラスに変える必要がある。(ignoreすると親Widgetにイベントが渡る)

    なんとなくまとめ:
     QGraphicsView関連では,特定のItemのみD&Dを受付ける場合はItemに,
     Scene上のポジションマッピングを使う場合はSceneに,
     Sceneごとゴッソリ入れ替える(特にSceneの型を変える)場合はViewに実装するのがいいのかな,と思いました(まる)

    1 Reply Last reply
    0
    • A Offline
      A Offline
      Atsushi4
      wrote on 6 Aug 2011, 15:29 last edited by
      #2

      動作確認しつつちょっと修正。
      調べれば調べる程ヤヤコシイ。

      1 Reply Last reply
      0
      • A Offline
        A Offline
        Atsushi4
        wrote on 6 Aug 2011, 22:29 last edited by
        #3

        QWidgetで動作確認できるサンプル書いてみました。
        コード行が少なくなるように書いてるので,コーディングマナーはアレですが。
        .proは
        SOURCES += d_d_widget.cpp
        だけで動くはず。

        d_d_widget.cpp
        @
        #include <QtGui>

        class Widget : public QWidget
        {
        Q_OBJECT
        public:
        Widget()
        {
        setAcceptDrops(true);
        setLayout(new QVBoxLayout);
        layout()->addWidget(new QLabel(".cppファイルを受付けます。複数ファイルもOK。"));
        layout()->addWidget(editor = new QTextEdit);
        editor->setAcceptDrops(false);
        }
        protected:
        void dragEnterEvent(QDragEnterEvent *event)
        {
        if (event->mimeData()->hasUrls())
        foreach (QUrl url, event->mimeData()->urls())
        if (QFileInfo(url.toLocalFile()).suffix() == "cpp")
        {
        event->accept();
        break;
        }
        }
        void dropEvent(QDropEvent *event)
        {
        editor->clear();
        foreach (QUrl url, event->mimeData()->urls())
        if (QFileInfo(url.toLocalFile()).suffix() == "cpp")
        open(url);
        else
        error(url);
        }
        private:
        void open(QUrl url) {editor->append("○ " + QFileInfo(url.toLocalFile()).fileName());}
        void error(QUrl url) {editor->append("× ..." + url.path().right(10));}
        QTextEdit *editor;
        };

        int main(int argc, char **argv)
        {
        QApplication app(argc, argv);
        QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());
        Widget w;
        w.show();
        return app.exec();
        }

        #include "d_d_widget.moc"

        @

        1 Reply Last reply
        0
        • A Offline
          A Offline
          Atsushi4
          wrote on 6 Aug 2011, 22:30 last edited by
          #4

          WIKIにしたらDrag and Dropだけで1カテゴリできちゃいそうですなぁ。
          とてもまとめる能力が無い。。。

          1 Reply Last reply
          0

          1/4

          6 Aug 2011, 06:03

          • Login

          • Login or register to search.
          1 out of 4
          • First post
            1/4
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved