【问题标题】:Scale image directly under mouse in Qt 4在 Qt 4 中直接在鼠标下缩放图像
【发布时间】:2011-07-03 17:32:00
【问题描述】:

类似于 google.com/maps,我希望这样,如果我的鼠标位于 QGraphicsItem 上,那么当我前后移动滚轮鼠标时,鼠标下方的图像区域就是我的 QGraphicsView 的中心.

我可以在我创建的自定义 QGraphicsIte 的 wheelEvent 方法中完成这个吗?

我有一些这样的代码

update();
qreal factor = 1.2;
if (event->delta() < 0)
  factor = 1.0 / factor;
scale(factor, factor);
scaleFactor *=factor;
this->scene()->setSceneRect(0,0,this->boundingRect().width(), this->boundingRect().height());

我可以添加什么来达到预期的效果?

例如,在谷歌地图中,​​如果您将鼠标悬停在犹他州,并使用滚轮鼠标继续放大,最终犹他州是视口中唯一剩下的东西。

【问题讨论】:

    标签: c++ qt4 image-scaling


    【解决方案1】:

    另见setTransformationAnchor( QGraphicsView::AnchorUnderMouse );

    【讨论】:

      【解决方案2】:

      等式类似于 ,,,

      margin = -half_overflow + (((center_offset - click_offset) * resize_ratio) - (center_offset - click_offset));

      ...你必须为 x 和 y 这样做。

      下面我将粘贴一些代码,但请记住,此代码处理方形图像,因此我将宽度用于宽度和高度。 为了让您在矩形图像上使用它,您还需要获取高度并在我有宽度的所有 Y 计算中使用它,以及设置我正在使用的所有变量,如 content_width 等。但是算法都在那里并且您可以从代码中解决...

              zoomChart: function(e)
              {
                      var chart_max = 2048;
                      var zoom_max = egapp.user.options.zoom_multiplier || 2; // >= 2
                      var chart_bounds = $('#egapp_chart_bounds');
                      var chart_imgs = chart_bounds.find('img');
                      var width = chart_imgs.width();
                      if (width == chart_bounds.width()) { // zoom in
                              // margin = -half_overflow + (((center_offset - click_offset) * resize_ratio) - (center_offset - click_offset));
                              chart_bounds.removeClass('egapp_zoom_in');
                              if (width == chart_max)
                                      return;
                              chart_bounds.addClass('egapp_zoom_out');
                              var new_width = parseInt(width * zoom_max);
                              if (new_width > chart_max)
                                      new_width = chart_max;
                              var ratio = new_width / width;
                              var moveX = moveY = -((new_width - width) / 2);
                              var chart_offset = chart_bounds.offset();
                              var offsetX = (chart_offset.left + (width / 2)) - e.pageX;
                              var offsetY = (chart_offset.top + (width / 2)) - e.pageY;
                              moveX += parseInt((offsetX * ratio) - offsetX);
                              moveY += parseInt((offsetY * ratio) - offsetY);
                              chart_imgs.animate({width: new_width+'px', height: new_width+'px', marginLeft: moveX+'px', marginTop: moveY+'px'}, 'fast');
                              chart_bounds.addClass('egapp_zoom_out');
                      }
                      else { // zoom out
                              var new_width = egapp.content_width - 10;
                              chart_imgs.animate({width: new_width+'px', height: new_width+'px', marginLeft: 0, marginTop: 0}, 'fast');
                              chart_bounds.removeClass('egapp_zoom_out').addClass('egapp_zoom_in');
                      }
              },
      

      HTML 类似于 ...

      <div id="egapp_chart_bounds" style="width: 608px; height: 608px;" class="egapp_zoom_in">
          <img id="egapp_timeline_chart" src="some.image" class="egapp_chart" style="width: 608px; height: 608px; margin-left: 0px; margin-top: 0px;">
          <img id="egapp_expression_chart_9" src="overlay.image" class="egapp_chart_overlay" style="width: 608px; height: 608px;">
      </div>
      

      CSS 就像 ...

      #egapp_chart_bounds{
              overflow: hidden;
      }
      .egapp_chart, .egapp_chart_overlay{
              position: absolute;
      }
      
      .egapp_zoom_in{
              cursor: -moz-zoom-in;
              cursor: -webkit-zoom-in;
              cursor: zoom-in;
      }
      .egapp_zoom_out{
              cursor: -moz-zoom-out;
              cursor: -webkit-zoom-out;
              cursor: zoom-out;
      }
      

      【讨论】:

        【解决方案3】:

        让我们以更直接的方式重新表述您的目标。车轮事件:

        1. 场景应该放大/缩小
        2. 鼠标下的场景位置应保持在鼠标下

        您已经使用 scale 调用实现了 (1)。剩下的是(2)。要将视图滚动到某个位置,您需要执行以下操作:

        horizontalScrollbar().setValue(x);
        verticalScrollbar().setValue(y);
        

        这会滚动场景,使 (x, y) 位于视图的左上角。但是您希望 (x, y) 位于鼠标位置(相对于 QGraphicsView)。因此,您需要滚动到 (x-mx, y-my),其中 (mx, my) 是相对于 QGraphicsView 的鼠标位置, (x, y) 是滚轮事件之前鼠标下方的场景位置。

        这是未经测试的,可能在细节上是错误的(例如 QScrollBar::setValue 的确切行为),但数学概念是正确的,所以它应该足以让你让它工作。

        【讨论】:

        • 我可以在 QGraphicsItem 的 wheel 事件中执行此操作吗? Item 是其中包含 wheelEvent 的内容,而不是 QGraphicsView
        • 啊,我以为你的 wheelEvent 是在 QGV 中。如果它在 QGI 中,你应该仍然可以做到。唯一的区别在于您确定(x, y)(使用QGraphicsSceneMouseEvent::screenPos)和(mx, my)(使用QGraphicsSceneMouseEvent::scenePos)的方式。无论如何,我认为在 QGV 而不是 QGI 中实现你的 wheelEvent 更干净。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-01-30
        • 2015-06-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-05
        • 2020-05-28
        相关资源
        最近更新 更多