我正在戴上一台QScrollArea a QLabel。然后我把图像放到QLabel上。当我放大图像时,它会左右移动,因为QScrollArea是如此对齐。怎样才能让增长朝着中心发生呢?下面是我使用的代码:
import sys
import cv2
import imutils
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5 import uic
from PyQt5 import QtCore, QtWidgets, QtGui
class MyWin(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
self.ui = uic.loadUi("gui.ui", self)
self.image = None
self.height = None
self.ui.openIm.clicked.connect(self.load)
self.ui.zoomIn.clicked.connect(self.on_zoom_in)
self.ui.zoomOut.clicked.connect(self.on_zoom_out)
def on_zoom_in(self):
self.height += 100
self.resize_image()
def on_zoom_out(self):
self.height -= 100
self.resize_image()
def resize_image(self):
scaled_pixmap = self.orig.pixmap().scaledToHeight(self.height)
self.orig.setPixmap(scaled_pixmap)
def load(self):
filename = QFileDialog.getOpenFileName(self, 'Select File')
self.image = cv2.imread(str(filename[0]))
frame = cv2.cvtColor(self.image, cv2.COLOR_BGR2RGB)
self.image = QImage(frame, frame.shape[1], frame.shape[0], frame.strides[0], QImage.Format_RGB888)
self.ui.orig.setPixmap(QPixmap.fromImage(self.image))
self.height = self.image.height()
self.ui.res.setPixmap(QPixmap.fromImage(self.image))
if __name__ == '__main__':
app = QApplication(sys.argv)
dlgMain = MyWin()
dlgMain.show()
sys.exit(app.exec_())下面是我用来连接Python代码的gui.ui文件代码。
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>420</width>
<height>600</height>
</rect>
</property>
<property name="windowTitle">
<string>MainWindow</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QGridLayout" name="gridLayout_4">
<item row="0" column="0">
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QPushButton" name="openIm">
<property name="text">
<string>Load</string>
</property>
</widget>
</item>
<item row="3" column="0">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item row="0" column="1" rowspan="4">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QScrollArea" name="areaOrig">
<property name="layoutDirection">
<enum>Qt::LeftToRight</enum>
</property>
<property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAsNeeded</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::AdjustIgnored</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>154</width>
<height>556</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0">
<widget class="QLabel" name="orig">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<widget class="QScrollArea" name="areaRes">
<property name="widgetResizable">
<bool>true</bool>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<widget class="QWidget" name="scrollAreaWidgetContents_2">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>153</width>
<height>556</height>
</rect>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<item row="0" column="0">
<widget class="QLabel" name="res">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item row="1" column="0">
<widget class="QPushButton" name="zoomIn">
<property name="text">
<string>ZoomIn</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QPushButton" name="zoomOut">
<property name="text">
<string>ZoomOut</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<widget class="QStatusBar" name="statusbar"/>
</widget>
<resources/>
<connections/>
</ui>发布于 2021-09-19 14:31:48
不幸的是,您不能在调整内容大小后立即设置滚动条位置,因为滚动区域需要一段未指定的“时间”来调整其内容,然后最终使用新的范围更新滚动条。
理论上的解决方案可能是确保清除当前事件队列,然后根据需要更新滚动条。
这可以通过以下方式实现:
while QApplication.hasPendingEvents():
QApplication.processEvents()
vBar = self.areaRes.verticalScrollBar()
if vBar.maximum():
vBar.setValue(vBar.maximum() * .5)
hBar = self.areaRes.horizontalScrollBar()
if hBar.maximum():
hBar.setValue(hBar.maximum() * .5)不幸的是,虽然上面的方法行得通,但你不应该这样做,因为有两个重要的原因,这是不好的: do:
由于线程争用条件的问题,
hasPendingEvents已过时(并且由于Qt6而被弃用),因此不应该使用anymore;正确的解决方案是使用滚动条的rangeChanged信号,并根据使用currentRange * (previousValue / previousRange)计算的前一个范围的比率来更新当前值。
要实现这一点,应该在更改范围之前存储当前比率,然后再次存储,但是对于两个滚动条来说,这可能会变得有点太复杂,所以更好的解决方案是为滚动条创建一个新的子类,它自己实现这个概念:
这个类是这样的:
class KeepPositionScrollBar(QScrollBar):
defaultRatio = .5
ratio = .5
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.rangeChanged.connect(self.restoreRatio)
self.valueChanged.connect(self.updateRatio)
def restoreRatio(self):
absValue = (self.maximum() - self.minimum()) * self.ratio
self.setValue(round(self.minimum() + absValue))
def updateRatio(self):
if self.maximum() - self.minimum():
absValue = self.value() - self.minimum()
self.ratio = absValue / (self.maximum() - self.minimum())
else:
self.ratio = self.defaultRatio然后,您只需将滚动条安装到视图中:
class MyWin(QtWidgets.QMainWindow):
def __init__(self):
QtWidgets.QMainWindow.__init__(self)
uic.loadUi("gui.ui", self)
self.areaRes.setVerticalScrollBar(
KeepPositionScrollBar(QtCore.Qt.Vertical, self.areaRes))
self.areaRes.setHorizontalScrollBar(
KeepPositionScrollBar(QtCore.Qt.Horizontal, self.areaRes))不相关的注释:
ui的引用是没有意义的,因为它只在设置阶段使用,你可以直接从self访问所有的ui元素:self.orig,self.res等;你可以直接调用uic.loadUi("gui.ui", self)而不赋值,就像我做的那样,因为使用了非常特殊类型的图像文件,Qt成像插件完全能够处理几乎任何标准的图像文件和颜色格式,所以你通常不需要使用cv;另外,文件对话框返回的路径已经是一个字符串,没有必要做self.image = QPixmap(filename[0]);self.height之前,str()应该检查路径是否不为空(当文件对话框被取消时)对于所有小部件来说,这是一个现有的标准动态属性,你不应该用其他东西覆盖它;self.height -= 100是错误的,因为它可能返回负大小,这将使图像为空;你至少应该确保该值大于0或可能使用比例比例;self.orig.setPixmap,这是错误的,因为您在每次缩放时都会覆盖用作调整大小的源的同一图像:结果是您尝试缩小,并且在几次中,图像变得完全像素化;您可能希望执行self.res.setPixmap (或使用原始self.image ),以便始终保留源;https://stackoverflow.com/questions/69239311
复制相似问题