mieki256's diary



2016/10/27(木) [n年前の日記]

#1 [python] PySideでズーム表示を試しているところ

PySide の QGraphics* で、ズーム表示を試しているところ。

拡大縮小表示自体の処理。 :

とりあえず拡大したり縮小したりの表示はできるようになったのだけど…。要は、QGraphicsScene に登録された Item に、setTransform() で「拡大縮小しろや」と設定してやればいいようで。
    def changeScale(self, scale):
        """ ズーム変更 """
        global padding
        self.zoomv = scale

        t = QTransform()
        t.scale(self.zoomv, self.zoomv)  # スケールだけ反映
        self.bgItem.setTransform(t)

        bt = QTransform()
        bt.scale(self.zoomv, self.zoomv)
        self.brushItem.setTransform(bt)


しかし、欲を出して、中ボタンドラッグ(ホイールボタンドラッグ)でキャンバス相当をスクロールさせようとしたあたりでハマり始めて。

中ボタンドラッグでスクロール。 :

中ボタンドラッグでスクロールする方法は、以下が参考になった。

_python - How to scrolling QGraphicsScene in QGraphicsView by middle mouse? - Stack Overflow

要するに、マウス座標の変化分を offset としたとして、
self.horizontalScrollBar().setValue(self.horizontalScrollBar().value() + offset.x())
self.verticalScrollBar().setValue(self.verticalScrollBar().value() + offset.y())
みたいなことをしてやればいいらしい。

しかし、上手くいかない…。

今までは、QGraphicsScene 内でマウスイベントを取得してたけど。それだと、中ボタンドラッグ開始と同時にスクロールがガガガガガガガって感じになって、ずっと処理が返ってこなくなった。何が起きてるのだ…。

おそらくだけど、中ボタンドラッグを検知してスクロールバーの位置を変更 → スクロールバーが動いたから中のWidgetの位置も動く → マウスカーソルが動いたものとして扱われる → 中ボタンドラッグ処理がそのまま再度呼び出され、またスクロールバーの位置が変更されて、みたいなことが延々と起きて無限ループに陥ってる、ような気がする。

仕方ないので、QGraphicsScene の中でマウスイベントを受け取るのは諦めて、マウスイベント関係は全て QGraphicsView 側で処理するようにしてみたり。これで、前述のような不具合は起きなくなった。

ところが、コレはコレでマウスカーソル座標の扱いに関して別の問題が。

マウスカーソル座標取得の問題。 :

QGraphicsScene でマウスイベントを取る分には、「シーン内では、この辺にマウスカーソルがありますよ」的なイイ感じの座標取得ができたけど。QGraphicsView側で取ると、「シーンのオフセットその他モロモロなんてワシは知らんわい。とにかく QGraphicsView のガワに対してのマウスカーソル座標しか返さんぞ。つーかソレしか持ってないし」的な座標取得しかできない。

そこで、QGraphicsView 内のマウスカーソル座標+スクロールバーの値、みたいな座標値を求めて QGraphicsScene内でのマウスカーソル座標値を推測してやることに。

これで一見上手くいったように見えたものの、拡大表示をしてスクロールバーが存在しているうちはいいけれど、縮小表示をしてスクロールバーが無くなった際に正しいマウスカーソル座標値が得られなくなった。スクロールバーが無くなると、スクロールバーの値はずっと0を返すけど、実際には補正をしないといかんわけで…。

ということで泥臭いけど、おそらくは以下のようになってるのだろうと考えて、スクロールバーが有る時と無いときで座標値の求め方を変えることに。
qgview_viewport_about.jpg
  • self.viewport().rect().width() < self.scene().sceneRect().width() なら、スクロールバーが出ている(はず)。
  • self.viewport().rect().width() >= self.scene().sceneRect().width() なら、スクロールバーは出ていない(はず)。
後者の場合は、シーンが viewport内の中央に表示されてるはずだから…。得られたマウスカーソル座標が、viewportの中央からどれだけ離れてるかを計算して、シーン上でも、中央からどれだけ離れているかで座標を求める、みたいな処理に。

ズーム表示の基準位置問題。 :

ズームをする時は、今まで見えてた範囲の左上の位置を基準にして拡大縮小するようにしていたのだけど。どういう処理をしているかといえば、ズーム変更前に今までのスクロールバーの値を取得しておいて、ズーム変更後、さっき取得したスクロールバーの値に新しいズーム率を掛けて、その値でスクロールバーの位置を設定、みたいな。

が、ここで欲を出して、見えてる範囲の中心を基準にしてズームを変えようとしてハマり始めたり。色々試したけど上手くいかない…。どうもスクロールバーの値とシーン内の座標値との関係が自分はさっぱり把握できてない気がする。

以上です。

過去ログ表示

Prev - 2016/10 - Next
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31

カテゴリで表示

検索機能は Namazu for hns で提供されています。(詳細指定/ヘルプ


注意: 現在使用の日記自動生成システムは Version 2.19.6 です。
公開されている日記自動生成システムは Version 2.19.5 です。

Powered by hns-2.19.6, HyperNikkiSystem Project