我正在开发一个 GUI,其中有一个 QMainWindow,其布局包含三个垂直堆叠的小部件:顶部标题、图像和底部标题。顶部和底部标题是带有蓝色背景的自定义 QWidget,图像使用带有 QPixmap 的 QLabel 显示。该图像只是一个通用的 400x400 图像。
这是我的代码:
from PyQt6.QtWidgets import QMainWindow, QApplication, QLabel, QVBoxLayout, QHBoxLayout, QWidget, QSizePolicy, QSpacerItem
from PyQt6.QtGui import QPixmap, QColor, QPalette
from PyQt6.QtCore import Qt, QSize
class ColorWidget(QWidget):
def __init__(self, color):
super().__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.ColorRole.Window, QColor(color))
self.setPalette(palette)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
layout = QVBoxLayout()
layout.setSpacing(0)
# Top Header
top_header = ColorWidget('blue')
top_header_layout = QHBoxLayout()
top_header_layout.addWidget(QLabel(parent=top_header, text='Image name'))
top_header.setLayout(top_header_layout)
layout.addWidget(top_header)
# Image
self.image_label = QLabel()
self.pixmap = QPixmap('Images/Path')
self.image_label.setPixmap(self.pixmap)
self.image_label.setMinimumSize(QSize(100, 100))
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
self.image_label.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
layout.addWidget(self.image_label)
# Bottom Header
bottom_header = ColorWidget('blue')
bottom_header_layout = QHBoxLayout()
bottom_header_layout.addWidget(QLabel(parent=bottom_header, text='Caption'))
bottom_header.setLayout(bottom_header_layout)
layout.addWidget(bottom_header)
central_widget = QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def resizeEvent(self, event):
super().resizeEvent(event)
self.adjust_image_size()
def adjust_image_size(self):
container_size = self.image_label.parentWidget().size()
pixmap_width = self.pixmap.width()
pixmap_height = self.pixmap.height()
max_width = container_size.width()
max_height = container_size.height()
new_width = min(max_width, pixmap_width)
new_height = min(max_height, pixmap_height)
if new_width / pixmap_width > new_height / pixmap_height:
new_width = new_height * pixmap_width / pixmap_height
else:
new_height = new_width * pixmap_height / pixmap_width
self.image_label.setPixmap(self.pixmap.scaled(int(new_width), int(new_height), Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation))
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
我遇到了三个问题:
如果我垂直扩展窗口,顶部和底部框架会与图像标签分离。 如果我水平扩展窗口,顶部和底部框架扩展的速度比图像调整大小的速度快。 如果我将窗口大小调整到可能的最小尺寸,则图像看起来有点矩形。 为了解决第一个问题,我在布局中添加了间隔项以将所有内容夹在其中,这在大多数情况下都有效,除非我使窗口又窄又高。
为了解决第二个问题,我尝试设置最大宽度为 400 像素(照片的宽度)。这种工作方式是有效的,除非我使窗口变小,顶部和底部框架仍然拉伸得比图像宽度更远。
如何改进此代码,以便顶部和底部框架始终“粘在”图像上,并且整体调整大小?我希望这些小部件能够像单个小部件一样调整大小。
在实施一些可能的解决方案之后,这些小部件可以更加一致地调整大小,但仍然不像是同一个小部件。以下是编辑内容:
# Add this in Main Window Init method
self.setMaximumWidth(400)
self.setMaximumHeight(400)
# Add this statement before the Top Header
layout.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding))
# Add it again after the bottom header
layout.addSpacerItem(QSpacerItem(20, 20, QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Expanding))
from PyQt6.QtWidgets import QMainWindow, QApplication, QLabel, QVBoxLayout, QWidget
from PyQt6.QtGui import QPixmap, QColor, QPalette
from PyQt6.QtCore import Qt
class ColorWidget(QWidget):
def __init__(self, color):
super().__init__()
self.setAutoFillBackground(True)
palette = self.palette()
palette.setColor(QPalette.ColorRole.Window, QColor(color))
self.setPalette(palette)
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.InitUI()
def InitUI(self):
# Central Widget and Layout
central_widget = QWidget()
layout = QVBoxLayout(central_widget)
layout.setContentsMargins(0, 0, 0, 0) # Remove default margins
layout.setSpacing(0) # Remove spacing between widgets
self.setCentralWidget(central_widget)
# Top Header
self.top_header = ColorWidget('blue')
top_header_layout = QHBoxLayout(self.top_header)
top_header_layout.addWidget(QLabel("Image name"))
layout.addWidget(self.top_header)
# Image Label
self.image_label = QLabel()
self.pixmap = QPixmap('Images/Path').scaled(
400, 400, Qt.AspectRatioMode.KeepAspectRatio, Qt.TransformationMode.SmoothTransformation
)
self.image_label.setPixmap(self.pixmap)
self.image_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
layout.addWidget(self.image_label)
# Bottom Header
self.bottom_header = ColorWidget('blue')
bottom_header_layout = QHBoxLayout(self.bottom_header)
bottom_header_layout.addWidget(QLabel("Caption"))
layout.addWidget(self.bottom_header)
def resizeEvent(self, event):
super().resizeEvent(event)
# Calculate new image size based on available space
available_height = self.height() - self.top_header.height() - self.bottom_header.height()
new_width = int(available_height * self.pixmap.width() / self.pixmap.height())
new_height = available_height
# Update the image label's pixmap with the resized image
self.image_label.setPixmap(
self.pixmap.scaled(
new_width,
new_height,
Qt.AspectRatioMode.KeepAspectRatio,
Qt.TransformationMode.SmoothTransformation,
)
)
if __name__ == '__main__':
app = QApplication([])
window = MainWindow()
window.show()
app.exec()
Explanation:
- Layout Margins and Spacing:
-
We set the layout's margins and spacing to 0 to ensure the widgets are tightly packed without any extra space.
-
Image Scaling on Resize:
-
We override the
resizeEvent
to recalculate the image size whenever the window is resized. - The calculation ensures that the image maintains its aspect ratio while occupying the maximum available space vertically.
-
We subtract the heights of the top and bottom headers from the window height to determine the available space for the image.
-
Directly Setting Pixmap:
-
Instead of using
setMinimumSize
on the image label, we directly scale theQPixmap
and set it to the label. This provides better control over the displayed image size.
With these changes, the top and bottom headers will stick to the image, resizing harmoniously while preserving the image's aspect ratio. The layout will adjust dynamically, preventing gaps or misalignment during resizing.
标签:python,pyqt6 From: 78845424