English 日本語

QGraphicsView でスムースなズーム機能の作り方

QGraphicsView を使ったプログラムですばらしい機能とはもちろん(例えば、Google Earth のような)スムースなズーム機能です。その実装のためには、QGraphicsView を継承した独自ウィジェットを作成する必要があります。

その基本的な考えはユーザがマウスのホイールをひとつ「動かす」たびに、新たに「スケーリングアクション」を作成するというものです。スケーリングする合計数は _numScheduledScalings に格納します。

もちろん、wheelEvent の再実装が必要です。まずはそのコードを示します。説明はその後に行います。

  1. void MyQGraphicsView::wheelEvent ( QWheelEvent * event )
  2. {
  3.     int numDegrees = event->delta() / 8;
  4.     int numSteps = numDegrees / 15;  // QWheelEvent のドキュメントを参照してください
  5.     _numScheduledScalings += numSteps;
  6.     if (_numScheduledScalings * numSteps < 0)  // ホイールが逆方向に動いた場合には、それまでに予定していたスケーリングをリセットします
  7.         _numScheduledScalings = numSteps;
  8.  
  9.     QTimeLine *anim = new QTimeLine(350, this);
  10.     anim->setUpdateInterval(20);
  11.  
  12.     connect(anim, SIGNAL(valueChanged(qreal)), SLOT(scalingTime(qreal)));
  13.     connect(anim, SIGNAL(finished()), SLOT(animFinished()));
  14.     anim->start();
  15. }

ホイールの移動の「勢い」を計算して、_numScheduledScalings に加えます。QTimeLine のオブジェクトを作成して、 350ms の寿命の間に 20ms 毎に scalingTime() 関数を呼び出します。

  1. void MyQGraphicsView::scalingTime(qreal x)
  2. {
  3.     qreal factor = 1.0 + qreal(_numScheduledScalings) / 300.0;
  4.      scale(factor, factor);
  5. }

倍率(factor)はシーンをどのくらいズームしたいかによって決まります。ほんの少しだけズームしたいときには、ホイールをとても繊細に動かさなくてはならないでしょう。_numScheduledScalings は小さくなり、 factor はほとんど 1 になるでしょう。その逆に、ホイールを勢いよく回転させた場合には、_numScheduledScalings は大きくなり、シーンのズームは速くなるでしょう。

もちろん、動的に作成した QTimeLine の処理も必要です。

  1. void MyQGraphicsView::animFinished()
  2. {
  3.     if (_numScheduledScalings > 0)
  4.         _numScheduledScalings--;
  5.     else
  6.         _numScheduledScalings++;
  7.     sender()->~QObject();
  8. }

Categories: