交换图像时,在QGraphicsView中维护视图/滚动位置

时间:2012-01-20 09:36:59

标签: python scroll pyqt pyqt4 qgraphicsview

我在使用QGraphicsView缩放加载到QGraphicsPixmapItem的TIFF图片时遇到问题。

问题是如何保持图像质量以及不会使应用程序窒息的变焦速度。首先,我只是用缩放的QPixmap替换图像 - 当用户按住水平滑块时使用Qt.FastTransformation,然后当滑块释放时,使用另一个缩放的像素图再次替换像素图Qt.SmoothTransformation。这给出了一个质量很好的缩放图像,但在图像尺寸开始增大到大于其原始尺寸后,变焦是不稳定的;缩小图像很好。

使用QGraphicsView上的QTransform.fromScale()可以提供更加平滑的缩放,但质量较低的图像,即使将.setRenderHints(QPainter.Antialiasing | QPainter.SmoothPixmapTransform | QPainter.HighQualityAntialiasing)应用于QGraphicsView也是如此。

我的最新方法是将两种方法结合起来,并使用QTransform上的QGraphicsView进行平滑缩放,但当用户释放滑块时,请替换QGraphicsView中的图像缩放的像素图。这很好用,但是视图中的位置丢失了 - 用户放大到一个区域,并且因为缩放的像素图较大,当释放滑块时视图跳转到另一个位置,并且更高质量的缩放像素图替换前一个图像。 / p>

我认为由于两个图像中的宽度高度比相同,我可以在图像交换之前采用滚动条的百分比,并在交换后应用相同的百分比,事情应该可以正常工作。这种方法效果很好,但仍有时候视图会跳跃'交换图像后。

我很确定我在这里做了一些非常错误的事情。有没有人知道更好的方法来做到这一点,或者任何人都可以在下面的代码中找到可能导致跳跃的东西?

这是保存/恢复滚动条位置的代码。它们是子类QGraphicsView

的方法
def store_scrollbar_position(self):
    x_max = self.horizontalScrollBar().maximum()
    if x_max:
        x = self.horizontalScrollBar().sliderPosition()
        self.scroll_x_percentage = x * (100 / float(x_max))

    y_max = self.verticalScrollBar().maximum()
    if y_max:
        y = self.verticalScrollBar().sliderPosition()
        self.scroll_y_percentage = y * (100 / float(y_max))


def restore_scrollbar_position(self):
    x_max = self.horizontalScrollBar().maximum()
    if self.scroll_x_percentage and x_max:
        x = x_max * (float(self.scroll_x_percentage) / 100)
        self.horizontalScrollBar().setSliderPosition(x)

    y_max = self.verticalScrollBar().maximum()
    if self.scroll_y_percentage and y_max:
        y = y_max * (float(self.scroll_y_percentage) / 100)
        self.verticalScrollBar().setSliderPosition(y)

以下是我如何进行扩展。 self.imageFileQPixmapself.imageQGraphicsPixmapItem。同样,是子类QGraphicsView的一部分。该方法附加到滑块移动,highQuality参数设置为False。在滑块释放时再次调用它,highQualityTrue以交换图像。

def setImageScale(self, scale=None, highQuality=True):
    if self.imageFile.isNull():
        return
    if scale is None:
        scale = self.scale
    self.scale = scale

    self.image.setPixmap(self.imageFile)
    self.scene.setSceneRect(self.image.boundingRect())
    self.image.setPos(0, 0)
    if not highQuality:
        self.setTransform(QTransform.fromScale(self.scaleFactor, self.scaleFactor))
        self.store_scrollbar_position()
    else:
        self.image.setPixmap(self.imageFile.scaled(self.scaleFactor * self.imageFile.size(),
                                                   Qt.KeepAspectRatio, Qt.SmoothTransformation))
        self.setTransform(self.transform)
        self.scene.setSceneRect(self.image.boundingRect())
        self.image.setPos(0, 0)
        self.restore_scrollbar_position()
    return

任何帮助将不胜感激。我现在开始对此感到非常沮丧。

1 个答案:

答案 0 :(得分:1)

我找到了一个比我第一次发布的代码更好的解决方案。它仍然不完美,但有很大的改进。以防万一其他人试图解决类似的问题...

设置低质量图像时,我将此方法调用添加到我的QGraphicsView:

def get_scroll_state(self):
    """
    Returns a tuple of scene extents percentages. 
    """
    centerPoint = self.mapToScene(self.viewport().width()/2,
                                  self.viewport().height()/2)
    sceneRect = self.sceneRect()
    centerWidth = centerPoint.x() - sceneRect.left()
    centerHeight = centerPoint.y() - sceneRect.top()
    sceneWidth =  sceneRect.width()
    sceneHeight = sceneRect.height()

    sceneWidthPercent = centerWidth / sceneWidth if sceneWidth != 0 else 0
    sceneHeightPercent = centerHeight / sceneHeight if sceneHeight != 0 else 0
    return sceneWidthPercent, sceneHeightPercent

这将存储在self.scroll_state中。设置高质量图像时,我调用另一个函数来恢复上一个函数中使用的百分比。

def set_scroll_state(self, scroll_state):
    sceneWidthPercent, sceneHeightPercent = scroll_state
    x = (sceneWidthPercent * self.sceneRect().width() +
         self.sceneRect().left())
    y = (sceneHeightPercent * self.sceneRect().height() +
         self.sceneRect().top())
    self.centerOn(x, y)

这会将中心位置设置为与交换图像前相同的位置(百分比)。