質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.50%

  • Python

    7996questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    6405questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

KivyのScrollViewで中クリックによるドラッグでスクロールさせたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 297

brsice

score 1

 前提・実現したいこと

KivyのScrollViewの内部で、左クリックによるドラッグ操作を使いたいため、中クリック(ホイールクリック)によるドラッグでスクロールさせたいと思っています。
右クリックで赤い丸が出ないように、
Config.set('input', 'mouse', 'mouse,disable_multitouch')
でマルチタッチを無効にしたのですが、右クリック、中クリックともに左クリックと同様に扱われてしまいスクロールには使えません。
中クリックは左クリックとは扱わず、スクロール用として使えるようにしたいです。

簡単なScrollViewのコードを載せておきます。

 該当のソースコード

from kivy.config import Config
Config.set("graphics", "width", 600)
Config.set("graphics", "height", 600)
Config.set('input', 'mouse', 'mouse,disable_multitouch')

from kivy.app import App


class TestApp(App):
    pass

if __name__ == '__main__':
    TestApp().run()

test.kv

FloatLayout:
    ScrollView:
        scroll_type: ['bars', 'content']
        size_hint: None, None
        size: root.size

        GridLayout:
            rows:2
            cols:2
            size_hint: None, None
            size: 1000,1000

            Widget:
                canvas:
                    Color:
                        rgb: 1, 0, 0
                    Rectangle
                        size: self.size
                        pos: self.pos
            Widget:
                canvas:
                    Color:
                        rgb: 0, 0, 1
                    Rectangle
                        size: self.size
                        pos: self.pos
            Widget:
                canvas:
                    Color:
                        rgb: 0, 1, 0
                    Rectangle
                        size: self.size
                        pos: self.pos
            Widget:
                canvas:
                    Color:
                        rgb: 1, 1, 1
                    Rectangle
                        size: self.size
                        pos: self.pos

 補足情報(FW/ツールのバージョンなど)

Python: v3.6.5
Kivy: v1.10.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

0

コメントだとMarkdown使えないのでこっちに書きますね。

このコードでは確かにそう捉えられてしまいますね、すみません、説明不足でした。
右クリック・中クリックでも問題なくスクロールできております。

あっ今わかりました。右クリック・中クリックでもボタンが反応してしまうのが困るという意味だったんですよね多分。

KivyにおいてMouseのような画面上の位置を指す類の入力はWidgetTreeの親から子へ順番に伝わっていくので、ボタンの祖先(直接の親とそのさらに上の親達)のWidgetのどれかを右クリック・中クリックを子に伝えないようにすればいいです。ただScrollViewでは中クリックを使いたいはずなので、ScrollViewの子孫でなおかつボタンの祖先であるWidget(上のコードでいうならGridLayout)にそのような仕事をさせてあげればいいです。

具体的には例えば以下のような入力を選別するClassを作って

from kivy.factory import Factory
from kivy.properties import ListProperty

# 入力を選別するClass
class TouchFilter:
    mouse_button_filter = ListProperty()

    def on_touch_down(self, touch):
        if touch.button in self.mouse_button_filter:
            return super().on_touch_down(touch)

    def on_touch_move(self, touch):
        if touch.button in self.mouse_button_filter:
            return super().on_touch_move(touch)

    def on_touch_up(self, touch):
        if touch.button in self.mouse_button_filter:
            return super().on_touch_up(touch)


# TouchFilterをKv言語でも使えるようにする
Factory.register('TouchFilter', cls=TouchFilter)

それを組み込んだGridLayoutを作って、元のGridLayoutと置き換えることで実現できます。

<CustomGridLayout@TouchFilter+GridLayout>:  # TouchFilterを組み込んだGridLayout

FloatLayout:
    ScrollView:
        
        CustomGridLayout:  # 元のGridLayoutを置き換える
            mouse_button_filter: ['left', ]  # 子には左ボタンの入力しか伝わらなくする
            

左ドラッグを使いたいという件ですが、ソースコードは載せられないのですが、大まかには「ボタンがたくさん並んでいて、それをドラッグでなぞっただけで動作させたい」という認識で大丈夫です。
on_pressだと難しそうなので、on_touch_downとon_touch_move内でcollide_pointを使って実現しています。

なるほど、わかりました。kivy.uix.button.Buttonを使うか否かは悩むところですね。Buttonの持つ機能の内stateプロパティは役に立ちそうですが、touchに関する処理は全て自前で実装することになりそうなので。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/12 00:46

    今思ったのですが、別に

    > 右クリック・中クリックでもボタンが反応してしまうのが困るという意味

    ではなかったですね。一応上記のコードのようにする事で中クリックや右クリックではボタンをなぞれなくなるので、参考までに。

    キャンセル

  • 2018/06/13 19:06

    「クリックの種類によってscroll_typeを変更するScrollViewの派生class」の中に、「クリックを選別するclassを継承したGridLayout」を配置することで、スクロールは左クリック以外、ボタンは左クリックのみの動作を実現することができました。
    ありがとうございます。
    プログラミング自体初心者ですが、GUIで何かを作るのは初めてなので、入力も継承されるというのは考え至りませんでした、勉強になります。
    とりあえずScrollVeiwの問題を先に解決したかっただけで、GridLayout内での右クリック・中クリックをどうするかというのも後々考える必要があったので助かりました。

    Buttonに関しては私も使う意味が薄いと考えており、Widgetにcanvasで色付けしたものを使用しているのですが、何か他に適したものはあるでしょうか?
    Widgetの数は1000個以上に増やすこともあるので、少しでも適したものをと思っています。
    大きなWidgetを作成して内部でどこをクリックしたか判断する形にした方が軽くなるのかなとは思っているのですが・・・。

    キャンセル

  • 2018/06/19 11:03 編集

    > 入力も継承されるというのは考え至りませんでした

    いえ、私が言いたかったのは親Widgetが子Widget達のon_touch_xxx()を再帰的に呼ぶ事で入力が伝わっていくという事です。下のリンクは全てのWidgetの基底Classであるkivy.uix.widget.Widgetのon_touch_xxx()の実装なんですが、そうなっているのが分かると思います。
    https://github.com/kivy/kivy/blob/master/kivy/uix/widget.py#L443-L483




    > 何か他に適したものはあるでしょうか?

    その方法で問題ないかと思います。



    > 1000以上の

    それだけの数になるのならRecycleViewが適切かと。

    キャンセル

  • 2018/06/22 15:05

    わざわざ仕組みまで教えていただいてありがとうございます。
    困ったら付近の実装を確かめるのも大事そうですね。
    RecycleViewに関しては使い方もどのように表示されるのかも全く知らないので、時間がある時に試してみようと思います。

    キャンセル

  • 2018/06/22 17:10

    http://www.asakura.co.jp/books/isbn/978-4-254-12896-3/
    最近出たKivyの本でRecycleViewを扱っているので参考になるかも知れないです、私はまだ読んでませんが。

    キャンセル

0

でマルチタッチを無効にしたのですが、右クリック、中クリックともに左クリックと同様に扱われてしまいスクロールには使えません。

マルチタッチはあくまで複数のタッチを実現するだけで、個々のボタンの役割が変わったりしないはずです。なので無効にしようがしまいが右クリック・中クリックでスクロールできるはずなのですが(実際私の環境ではできています)、主さんの環境でできていないのは確かですか?

あとマウスの入力をScrollViewの内部でどのように扱いたいか、細かく以下の7つ

  • 左クリック
  • 右クリック
  • 中クリック
  • 左ドラッグ
  • 右ドラッグ
  • 中ドラッグ
  • ホイールを回す

について分かりますか?

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/10 19:49

    このコードでは確かにそう捉えられてしまいますね、すみません、説明不足でした。
    右クリック・中クリックでも問題なくスクロールできております。
    上のサンプルコードはScrollViewについて試行錯誤するために作成したもので、仮にscroll_type: ['bars', 'content']としていますが、私が求める挙動は以下のようなものです。

    ・左クリック・左ドラッグでは'bars'の動作
    ・中クリック・中ドラッグでは'content'の動作
     あるいはオートスクロールのような動作でも可
    ・ホイール操作は通常のスクロール

    左ドラッグはon_touch_moveで使用しているため、スクロールには使いたくないのです。
    右クリックについては特に使用予定はないので、左クリック同様の動作でも使用不可でも構いません。

    キャンセル

  • 2018/06/10 20:47 編集

    > 左クリック・左ドラッグでは'bars'の動作
    > 中クリック・中ドラッグでは'content'の動作

    これはScrollViewの派生Classを作って、on_touch_down()を上書きする方法しか思いつかないですね。
    on_touch_down()の仮引数touchのbutton属性を見て、ScrollViewのscroll_typeプロパティを変更してあげればできると思います。


    > 右クリックについては特に使用予定はないので、左クリック同様の動作でも使用不可でも構いません。

    使用不可にしたいなら上の派生Classを使った方法か、ScrollViewの親Widgetとして右ボタン入力を伝搬しないWidgetを作って用意してあげればできそうです。追記:もしアプリ全体に渡って右ボタンが要らないのなら、rootのWidgetを右ボタン入力を伝搬しないようにしてしまえばいいと思います。因みに右ボタン入力の伝搬を止めるには以下のようなメソッドを書いてあげればできます。

    def on_touch_down(self, touch):
    ____if touch.button != 'right':
    ________return super().on_touch_down(touch)


    > 左ドラッグはon_touch_moveで使用しているため、スクロールには使いたくないのです。

    これがよくわからないのですが、ソースコードは載せられますか?

    キャンセル

  • 2018/06/11 05:28

    >> 左クリック・左ドラッグでは'bars'の動作
    >> 中クリック・中ドラッグでは'content'の動作
    >
    >これはScrollViewの派生Classを作って、on_touch_down()を上書きする方法しか思いつかないですね。
    >on_touch_down()の仮引数touchのbutton属性を見て、ScrollViewのscroll_typeプロパティを変更してあげればできると思います。

    ありがとうございます。
    今すぐに試せないのですが、その方法で思ったとおりの動作にできそうです。
    恥ずかしながらクリックの種類を見分ける方法をリファレンスから見つけられなかったもので、下に書いていただいているコードで歯がゆかったところに手が届きそうです。

    左ドラッグを使いたいという件ですが、ソースコードは載せられないのですが、大まかには「ボタンがたくさん並んでいて、それをドラッグでなぞっただけで動作させたい」という認識で大丈夫です。
    on_pressだと難しそうなので、on_touch_downとon_touch_move内でcollide_pointを使って実現しています。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.50%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    7996questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    6405questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。