我正在戴上一台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
复制相似问题