使用 PyQT5 调整 window 的大小 - 如何减小小部件的大小以允许 window 缩小?
Resizing a window with PyQT5 - how do I reduce the size of a widget to allow the window to be shrunk?
我正在尝试通过重新制作一个用于处理像素艺术的旧命令行 C 程序来学习它。
目前,主要 window 以单个 QLabel 集开始显示 10 x 10 白色图像的 300 x 300 放大版本。
我正在使用 resizeEvent(我也尝试过使用 paintEvent 来解决同样的问题)来重新缩放图像以在 window 尺寸增加时填充 window。
我的问题是,随着 window 尺寸的缩小,如何重新缩放图像以适应 window?就目前而言,window 无法调整为小于显示图像的小部件。本质上,我可以使 window(和图像)变大,但绝不会变小。
到目前为止,我的代码如下。目前它只根据 window 宽度的变化工作,只是为了在我解决这个问题时保持简单。有没有办法允许 window 调整为小于最大的小部件?或者有更好的方法来解决这个问题吗?
#Create white 10*10 image
image = QImage(10,10,QImage.Format.Format_ARGB32)
image_scaled = QImage()
image.fill(QColor(255,255,255))
class Window(QMainWindow):
#scale image to change in window width (image is window width * window width square)
def resizeEvent(self,event):
if self.imageLabel.width()>self.imageLabel.height():
self.image_scaled = image.scaled(self.imageLabel.width(),self.imageLabel.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
QWidget.resizeEvent(self, event)
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(100,100,300,300)
self.imageLabel = QLabel()
self.setCentralWidget(self.imageLabel)
self.image_scaled = image.scaled(self.imageLabel.width(),self.imageLabel.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
找到解决办法。事实证明,即使滚动条被禁用,将图像放在 QScrollArea 小部件中也可以使 window 小于它包含的图像。然后,随着 window 尺寸的缩小,图像可以重新缩放以适应 window。
class Window(QMainWindow):
#scale image to change in window width (image is window width * window width square)
def resizeEvent(self,event):
self.image_scaled = image.scaled(self.scroll.width(),self.scroll.height())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
QMainWindow.resizeEvent(self, event)
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(100,100,200,200)
self.imageLabel = QLabel()
self.scroll = QScrollArea()
self.scroll.setWidget(self.imageLabel)
self.setCentralWidget(self.scroll)
self.scroll.setWidgetResizable(True)
self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.image_scaled = image.scaled(self.scroll.width(),self.scroll.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
虽然 OP 提出的解决方案可能有效,但它有一个重要的缺点:它使用 QScrollArea 用于错误的目的(因为它从未用于 滚动 )。这种方法在调整大小时会产生不必要的开销,因为视图在“完成”调整大小事件(包括滚动条范围和几何形状)之前需要计算有关其内容的很多事情,最终将永远不会被实际使用。
主要问题来自 QLabel 不允许调整到小于原始像素图集的大小这一事实。要解决此问题,最简单的解决方案是创建一个自定义的 QWidget 子类,它自己绘制像素图。
class ImageViewer(QWidget):
pixmap = None
_sizeHint = QSize()
ratio = Qt.KeepAspectRatio
transformation = Qt.SmoothTransformation
def __init__(self, pixmap=None):
super().__init__()
self.setPixmap(pixmap)
def setPixmap(self, pixmap):
if self.pixmap != pixmap:
self.pixmap = pixmap
if isinstance(pixmap, QPixmap):
self._sizeHint = pixmap.size()
else:
self._sizeHint = QSize()
self.updateGeometry()
self.updateScaled()
def setAspectRatio(self, ratio):
if self.ratio != ratio:
self.ratio = ratio
self.updateScaled()
def setTransformation(self, transformation):
if self.transformation != transformation:
self.transformation = transformation
self.updateScaled()
def updateScaled(self):
if self.pixmap:
self.scaled = self.pixmap.scaled(self.size(), self.ratio, self.transformation)
self.update()
def sizeHint(self):
return self._sizeHint
def resizeEvent(self, event):
self.updateScaled()
def paintEvent(self, event):
if not self.pixmap:
return
qp = QPainter(self)
r = self.scaled.rect()
r.moveCenter(self.rect().center())
qp.drawPixmap(r, self.scaled)
class Window(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.imageLabel = ImageViewer(QPixmap.fromImage(image))
self.setCentralWidget(self.imageLabel)
我正在尝试通过重新制作一个用于处理像素艺术的旧命令行 C 程序来学习它。
目前,主要 window 以单个 QLabel 集开始显示 10 x 10 白色图像的 300 x 300 放大版本。
我正在使用 resizeEvent(我也尝试过使用 paintEvent 来解决同样的问题)来重新缩放图像以在 window 尺寸增加时填充 window。
我的问题是,随着 window 尺寸的缩小,如何重新缩放图像以适应 window?就目前而言,window 无法调整为小于显示图像的小部件。本质上,我可以使 window(和图像)变大,但绝不会变小。
到目前为止,我的代码如下。目前它只根据 window 宽度的变化工作,只是为了在我解决这个问题时保持简单。有没有办法允许 window 调整为小于最大的小部件?或者有更好的方法来解决这个问题吗?
#Create white 10*10 image
image = QImage(10,10,QImage.Format.Format_ARGB32)
image_scaled = QImage()
image.fill(QColor(255,255,255))
class Window(QMainWindow):
#scale image to change in window width (image is window width * window width square)
def resizeEvent(self,event):
if self.imageLabel.width()>self.imageLabel.height():
self.image_scaled = image.scaled(self.imageLabel.width(),self.imageLabel.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
QWidget.resizeEvent(self, event)
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(100,100,300,300)
self.imageLabel = QLabel()
self.setCentralWidget(self.imageLabel)
self.image_scaled = image.scaled(self.imageLabel.width(),self.imageLabel.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
找到解决办法。事实证明,即使滚动条被禁用,将图像放在 QScrollArea 小部件中也可以使 window 小于它包含的图像。然后,随着 window 尺寸的缩小,图像可以重新缩放以适应 window。
class Window(QMainWindow):
#scale image to change in window width (image is window width * window width square)
def resizeEvent(self,event):
self.image_scaled = image.scaled(self.scroll.width(),self.scroll.height())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
QMainWindow.resizeEvent(self, event)
def __init__(self, parent=None):
super().__init__(parent)
self.setGeometry(100,100,200,200)
self.imageLabel = QLabel()
self.scroll = QScrollArea()
self.scroll.setWidget(self.imageLabel)
self.setCentralWidget(self.scroll)
self.scroll.setWidgetResizable(True)
self.scroll.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.image_scaled = image.scaled(self.scroll.width(),self.scroll.width())
self.pixmap = QPixmap.fromImage(self.image_scaled)
self.imageLabel.setPixmap(self.pixmap)
app = QApplication(sys.argv)
win = Window()
win.show()
sys.exit(app.exec_())
虽然 OP 提出的解决方案可能有效,但它有一个重要的缺点:它使用 QScrollArea 用于错误的目的(因为它从未用于 滚动 )。这种方法在调整大小时会产生不必要的开销,因为视图在“完成”调整大小事件(包括滚动条范围和几何形状)之前需要计算有关其内容的很多事情,最终将永远不会被实际使用。
主要问题来自 QLabel 不允许调整到小于原始像素图集的大小这一事实。要解决此问题,最简单的解决方案是创建一个自定义的 QWidget 子类,它自己绘制像素图。
class ImageViewer(QWidget):
pixmap = None
_sizeHint = QSize()
ratio = Qt.KeepAspectRatio
transformation = Qt.SmoothTransformation
def __init__(self, pixmap=None):
super().__init__()
self.setPixmap(pixmap)
def setPixmap(self, pixmap):
if self.pixmap != pixmap:
self.pixmap = pixmap
if isinstance(pixmap, QPixmap):
self._sizeHint = pixmap.size()
else:
self._sizeHint = QSize()
self.updateGeometry()
self.updateScaled()
def setAspectRatio(self, ratio):
if self.ratio != ratio:
self.ratio = ratio
self.updateScaled()
def setTransformation(self, transformation):
if self.transformation != transformation:
self.transformation = transformation
self.updateScaled()
def updateScaled(self):
if self.pixmap:
self.scaled = self.pixmap.scaled(self.size(), self.ratio, self.transformation)
self.update()
def sizeHint(self):
return self._sizeHint
def resizeEvent(self, event):
self.updateScaled()
def paintEvent(self, event):
if not self.pixmap:
return
qp = QPainter(self)
r = self.scaled.rect()
r.moveCenter(self.rect().center())
qp.drawPixmap(r, self.scaled)
class Window(QMainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.imageLabel = ImageViewer(QPixmap.fromImage(image))
self.setCentralWidget(self.imageLabel)