EntryNavi : « Qt Quickアプリで特定のファイルをデプロイするには | メイン | Rewit for Qt ver0.7更新 »

CategoryNavi : メイン -> コンピューター -> 開発 -> Qt

QML(Qt)のListViewのDelegateにMouseAreaを配置したときの話

よくわからないので教えてぷりーず。

ListViewのdelegateプロパティに指定したレイアウト情報にMouseAreaを配置した場合の謎動作について。
マウスカーソルがエリア外に出た時に発生するシグナルの「onExited」と押してたマウスが離された時に発生する「onReleased」が発生しない時があるのです。

実際に下のサンプルを動かすとわかるのですが。

普通にRectangleとかにMouseAreaを配置して以下の操作をします。
1.カーソルを四角の上に持ってく
2.マウスダウン(押しっぱなし)
3.カーソル移動して四角の外へ
4.マウスアップ(放す)

この時のログの流れはこんな感じ。
1.rect:onEntered
2.rect:onPressed
3.rect:onExited
4.rect:onReleased
操作の番号とイベント発生タイミングは一致してます。

なんとなく納得な流れ。
カーソルをウインドウの外まで持って行ってもマウスアップ時にonReleased発生します。


ListViewのdelegateに配置した場合のログの対応をとるとこんな感じ。
1.delegate:onEntered
2.delegate:onPressed
3.何も起きない
4.何も起きない

リストをうにょーーんと引っ張れるようになっているせいなのかなんなのか。
試しにサンプルでコメントして入れてありますが、ListViewの中に全体にMouseAreaをはっつけても同じでした。
当然その場合は、各delegateが直接シグナルを受け取れないのでいろいろ頑張る必要があります。
Qt Quick 1.1の機能で「preventStealing」を使うと意図した動作をするのですが、リストのスクロールがマウスのホイールのみになってドラッグできなくなります。

そんな訳でぜっさんお悩み中です。


でしたが、「onCanceled」をひろうといいよと聞いたので試したところ。

1.delegate:onEntered
2.delegate:onPressed
3.delegate:onCanceled
4.何も起きない

となりました。
リリースはわからないもののListViewのマウスダウンした時のアイテムの外にでると「onCanceled」が発生するので期待する動きに近い感じになります。


サンプルの本体。
import QtQuick 1.0

Rectangle {
    id:_root
    width: 360
    height: 360

    // 比較に普通の四角
    Rectangle{
        id: _rectSample
        width: 100
        height: 50
        x: 10
        y: 50
        color: "#0000dd"
        // こっちにもマウスエリアを配置
        MouseAreaLog{
            tag: "rect:"
        }
    }


    // リストモデル
    ListModel{
        id: _model
        // 2つくらいリストに登録
        ListElement{
            _message: "homuhomu"
        }
        ListElement{
            _message: "hogehoge"
        }
    }
    // リスト用レイアウト
    Component{
        id: _delegate
        Rectangle {
            width: _list.width
            height: _text.paintedHeight * 2
            border.color: "#dddddd"
            border.width: 1
            Text{
                id: _text
                anchors.centerIn: parent
                text: _message
            }
            // これでリストの各項目でクリックイベントを拾う
            MouseAreaLog{
                tag: "delegate:" + _message + ":"
            }
        }
    }
    // リスト
    ListView{
        id: _list
        anchors.top: _rectSample.bottom
        anchors.left: _root.left
        anchors.right: _root.right
        anchors.bottom: _root.bottom
        clip: true
        model: _model
        delegate: _delegate

//        MouseAreaLog{
//            anchors.fill: _list
//            tag: "listview:"
//        }
    }
}


イベントログを出しやすくしたエレメント
// MouseAreaLog.qml
import QtQuick 1.0
//import QtQuick 1.1

MouseArea {
    anchors.fill: parent
    hoverEnabled: true
//  preventStealing: true

    property string tag: ""

    // 追加
    onCanceled: {
        console.debug(tag + "onCanceled");
    }

    //クリック時にハイライトさせる
    onPressed: {
        console.debug(tag + "onPressed");
    }
    onReleased: {
        console.debug(tag + "onReleased");
    }
    //マウスオーバー
    onEntered: {
        console.debug(tag + "onEntered");
    }
    onExited: {
        console.debug(tag + "onExited");
    }
    // 長押し
    onPressAndHold: {
        console.debug(tag + "onPositionChanged");
    }
    //クリック
    onClicked: {
        console.debug(tag + "onClicked");
    }
}
<Category : Qt>

コメント (2)

Masaya TAKAHASHI:

今更なのかもしれませんが、おそらく
(ListViewの継承元である)Flickableのせいです。
interactiveがtrueのとき、
mousePressとmouseMoveとmouseReleaseのイベントを内部でacceptするよ、と書いてあります(/src/declarative/graphicsitems/qdeclarativeflickable.cpp)。
なのでそれより後にイベントハンドラは呼ばれません。
うにょーんと動かす処理でイベントを使っているということですかね。

なので、ListViewがうにょーんと動かないよう、interactive:falseで固定してやるとRectangleと同じになると思います。

あやね:

> Masaya TAKAHASHI さん
情報ありがとうございます。
たしかに、interactive=falseにするとイベントが起きるのですが、うにょーんだけじゃなくて通常のスクロールもできなくなるっぽいので使える状況が限られる技かもしれませんね。

コメントを投稿

検索

Google

サイドフィード

track feed 理ろぐ
人気ブログランキング - 理ろぐ
Powered by
Movable Type 3.34