首页 > 编程问答 >如何在 PyQt6 中调整窗口大小期间将标题和图像粘合在一起

如何在 PyQt6 中调整窗口大小期间将标题和图像粘合在一起

时间:2024-08-08 03:55:43浏览次数:10  
标签:python pyqt6

我正在开发一个 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 像素(照片的宽度)。这种工作方式是有效的,除非我使窗口变小,顶部和底部框架仍然拉伸得比图像宽度更远。

如何改进此代码,以便顶部和底部框架始终“粘在”图像上,并且整体调整大小?我希望这些小部件能够像单个小部件一样调整大小。

Issue number 1 Issue number 2 Issue number 3

在实施一些可能的解决方案之后,这些小部件可以更加一致地调整大小,但仍然不像是同一个小部件。以下是编辑内容:

# 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:

  1. Layout Margins and Spacing:
  2. We set the layout's margins and spacing to 0 to ensure the widgets are tightly packed without any extra space.

  3. Image Scaling on Resize:

  4. We override the resizeEvent to recalculate the image size whenever the window is resized.
  5. The calculation ensures that the image maintains its aspect ratio while occupying the maximum available space vertically.
  6. We subtract the heights of the top and bottom headers from the window height to determine the available space for the image.

  7. Directly Setting Pixmap:

  8. Instead of using setMinimumSize on the image label, we directly scale the QPixmap 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

相关文章

  • Python + Svelte,如何使用本地文件系统
    总结一下,我有一个用python编写的应用程序。它在输入时需要一堆视频文件。使用一些魔法并生成合并的视频文件输出。我没有找到一个好的GUI解决方案(tkinter,QT,TUI等),所以我选择Svelte框架。但是出现了一个问题,我如何使用本地文件系统。在GUI(svelte)上,我必须上......
  • 如何在Python中绘制伪球面
    目标是使用meshgrid和numpy库生成伪球体的三维图形,但我使用下面的代码生成的图形不完整u=np.linspace(0,np.pi,50)v=np.linspace(0,2*np.pi,100)x,y=np.meshgrid(u,v)X=np.arccos(x)*np.cos(y)Y=np.arccos(x)*np.sin(y)Z=x-np.tan(x)fig=plt.f......
  • 18:Python集合属性
    #Python3集合#集合(set)是一个无序的不重复元素序列。#集合中的元素不会重复,并且可以进行交集、并集、差集等常见的集合操作。#集合中元素必须是不可变类型,也就说里面不能是列表和字典#可以使用大括号{}创建集合,元素之间用逗号,分隔,或者也可以使用set()函数创建集合。s......
  • Python爬虫案例与实战:爬取源代码练习评测结果
    Python爬虫案例与实战:爬取源代码练习评测结果本章案例将介绍用Python编写程序实现简单网站的模拟登录,然后保持登录后的网页会话,并在会话中模拟网页表单提交,之后使用Requests库的高级特性爬取提交之后的返回结果。在HTTP网页中,如登录、提交和上传等操作一般通过向网页发送......
  • Python爬虫案例与实战:爬取豆瓣电影简介
    Python爬虫案例与实战:爬取豆瓣电影简介本章案例将介绍如何爬取豆瓣电影简介,以此帮助读者学习如何通过编写爬虫程序来批量地从互联网中获取信息。本案例中将借助两个第三方库----Requests库和BeautifulSoup库。通过Requests库获取相关的网页信息,通过BeautifulSoup库解析大......
  • 趣味Python游戏编程:第3章 递归函数的威力:扫雷
    趣味Python游戏编程:第3章递归函数的威力:扫雷在第2章中,我们制作了一个拼图游戏,玩家通过鼠标操作图片块移动。本章设计一款扫雷游戏,玩法是在一个方块阵列中随机埋设一定数量的地雷,然后由玩家逐个打开方块,并以排除所有地雷为最终游戏目标。如果玩家打开的方块中有地雷,则游戏......
  • Python 依赖管理神器 Poetry 深入指南
    Poetry依赖管理详细教程引言在现代软件开发中,依赖管理是项目成功的关键。Python开发者现在有了一个新的选择:Poetry。Poetry是一个现代的Python包管理工具,旨在简化Python项目的创建、打包和发布。它提供了一种更直观和高效的方式来管理项目的依赖关系,相较于传统的p......
  • python的函数、魔法方法和案例
    1.python函数中self的用法在Python中,self 是一个对当前实例(对象)的引用,用于访问属于该类的变量和方法。在定义类的方法时,通常需要将 self 作为第一个参数。这允许在类的实例上调用方法时,自动将实例本身作为参数传递给方法。classPerson:def__init__(self,name......
  • 【视频讲解】Python灰色关联度分析直播带货效用、神经退行性疾病数据
    原文链接:https://tecdat.cn/?p=37273原文出处:拓端数据部落公众号 分析师:JiayiDeng 本文展示如何用灰色关联度分析的直播带货效用及作用机制研究,并结合一个分析神经退行性疾病数据实例的代码数据,为读者提供一套完整的实践数据分析流程。一、研究难点直播带货作为新兴产业,缺......
  • 线性方程组迭代算法的Python实现
    更多精彩,关注博客园主页,不断学习!不断进步!我的主页csdn很少看私信,有事请b站私信博客园主页-发文字笔记-常用有限元鹰的主页内容:ABAQUS数值模拟相关Python科学计算开源框架,编程学习笔记哔哩哔哩主页-发视频-常用FE-有限元鹰的个人空间内容:模拟案例网格划分游戏视频,......