【问题标题】:QT - QPixmap not rescaling with current parent sizeQT - QPixmap 不使用当前父大小重新缩放
【发布时间】:2017-08-15 05:13:35
【问题描述】:

我正在尝试构建一个 topBar 以放入其他小部件 layout 但我不知道为什么 `QPixmap 在我们更改应用程序窗口大小时没有重新缩放。代码如下:

QPixmap 位于 QHBoxLayoutQWidget 内的 QLabel 内,即 centralWidgetQMainWindow

QT 5.8 - Python 3.6

我已在 2017 年 3 月 24 日更新了此代码并删除了之前的版本。

0 - 依赖项

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys

1 - 主窗口

class MainWindow(QMainWindow):
    def __init__(self):
        print("I've been in main window")
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setWindowTitle("I'm here, the main window")

2 - 顶栏

class topBar(QWidget):
    def __init__(self):
        print("I've been in topBar")
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setObjectName("topBar")
        self.setStyleSheet("""
        QWidget {background-color: pink;}
        QLabel {background-color: green; }""")

    def resizeEvent(self,event):
        resizeHandler(self,event) # You'll see this little dude right next

3 - resizeEvent 处理程序,我认为 问题

def resizeHandler(self,event):
    print(" I've been in resizeHandler")
    if self.objectName() == "topBar":
        print("I've been resizing the topBar")
        logo = QPixmap('some_Image')
        # Debug
        # You'll be able to see that it does re-scale, but it's not updating the Pixmap.
        logo.scaled(event.size(),Qt.KeepAspectRatio).save("pixmap.png")
        # ...
        logoContainer = QLabel()
        logoContainer.setPixmap(logo.scaled(event.size(),Qt.KeepAspectRatio,Qt.FastTransformation))  
        logoContainer.setMaximumSize(logo.width(),logo.height())

        containerLayout = QHBoxLayout()
        containerLayout.addWidget(logoContainer,0)

        container = QWidget()
        container.setLayout(containerLayout)

        # Layout
        layout = QHBoxLayout()
        layout.addWidget(container,0)

        self.setLayout(layout)

        main.setCentralWidget(self)

4 - 测试

if __name__ == '__main__':
    print("I've been in __main__")
    app = 0
    app = QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)
    app.setWindowIcon(QIcon('someIcon'))

    main = MainWindow() 
    main.layout().setSizeConstraint(QLayout.SetNoConstraint)

    bar = topBar()
    main.setCentralWidget(bar)
    main.show()
    app.exec_()

如果可能的话,我还想限制topBar itself 垂直不超过当前屏幕尺寸的 20%(setMaximumHeight?但基于什么?)但我不确定如何。

谢谢!

【问题讨论】:

  • 是什么让您认为container 没有缩放?将self.setStyleSheet(""" 更改为container.setStyleSheet(""",您将看到container 缩放直到达到您设置的最大大小。真正的问题不是logo 没有缩放吗?
  • 有一刻我以为容器没有随着当前屏幕的缩小或扩大而调整大小。在过去的 3 天里,我一直在尝试解决这个非常简单的问题的许多方法,但我无法解决它。我删除了setScaledContents(True) 并尝试重新定义resizeEvent 以将像素图更新为pixmap.scaled(main.width(),main.height(),Qt.KeepAspectRatio) 的最新方法,但这也不起作用=/。 (主要是QMainWindowtopBarCentralWidget
  • @G.M.我已经更新了问题和代码,看来真正的问题是QPixmap 没有更新它的大小。

标签: qt python-3.x pyqt qt5 pyqt5


【解决方案1】:

要让小部件填充容器,您需要将垂直和水平尺寸策略设置为最小、扩展、最小扩展或忽略。 http://doc.qt.io/qt-5/qsizepolicy.html#Policy-enum

就第二个问题而言,它不是 Qt 小部件的内置功能。使用 QML 或 Web 引擎可能会获得更好的运气。您可以创建一个使用 setGeometry() 和一些窗口计算来限制其大小的 QWidget 子类。

【讨论】:

  • 尝试了[*].setSizePolicy([policy1],[policy2]),策略是一对QSizePolicy.MinimumExpandingQSizePolicy.Expanding,但它仍然没有重新缩放。我不知道QLabel 是否没有重新缩放或者是否是container QWidget。感谢您的回复!
【解决方案2】:

我认为您在尝试诊断问题时在这里看错了。

您最后的评论说...

真正的问题是 QPixmap 没有更新它的大小

这是因为显示它的QLabel 没有调整大小。回到你原来的代码,我想你需要做的就是在containerQLabellogo之间插入一个布局...

class topBar(QWidget):
def __init__(self,parent):
    super().__init__()

    container = QWidget()
    container.setMaximumSize(587,208)
    container.setMinimumSize(0,0)

    ## Logo
    logo = QLabel(container)
    #logo = QLabel(container_layout)
    logo.setPixmap(QPixmap('.some_image_in_the_current_working_dir.png'))
    logo.setScaledContents(1)

    # G.M.
    container_layout = QHBoxLayout(container)
    container_layout.addWidget(logo)

    # Layout
    ## to center content horizontally in wrapper w/o preventing rescale
    layout = QHBoxLayout(self)
    layout.addWidget(container)

    self.setStyleSheet("""
    QWidget {background-color: red;}
    QLabel {background-color: green; Qt::KeepAspectRatio;}""")

if __name__ == '__main__':
    app = 0
    app = QApplication(sys.argv)
    app.aboutToQuit.connect(app.deleteLater)
    test = topBar(None)
    test.show()
    app.exec_()

(寻找 G.M. 的评论)

上面的代码只是为container 创建了一个布局container_layout,并使logo 成为它的一个子级。这似乎解决了我认为您所描述的问题。

【讨论】:

  • 我之前已经设法实现了与您的代码相同的输出,但它仍然没有保持纵横比,我猜 StyleSheet 上的 Qt::KeepAspectRatio 对此没有帮助。跨度>
  • 至于 new 代码,我已经尝试过 logoContainer.setStyleSheet(".Qlabel {background-color: purple;}") 并且我看到 QLabel 正在调整大小,QPixmap 仍然没有。
【解决方案3】:

经过大量调试和到处阅读后,我想出了以下解决方案(使用numpy 帮助重新缩放):

def resizeHandler(self,event):
    if self.objectName() == "topBar":
        # Wiping the old layout
        temp = QWidget()
        temp.setLayout(self.layout())

        # Pixmap
        logoPixmap = QPixmap('./img/exampleImage.png')

        # Label
        logoLabel = QLabel()
        logoLabel.setPixmap(logoPixmap)
        logoLabel.setScaledContents(True)

        ## Label Container Layout
        containerLayout = QHBoxLayout()
        containerLayout.addWidget(logoLabel,0)

        # Label Container
        logoContainer = QWidget()
        logoContainer.setLayout(containerLayout)

        # Finding the width and height of the scaled box
        # Image unit vectors
        imageSize = np.array((logoPixmap.width(),logoPixmap.height()))
        screenSize = np.array((event.size().width(),event.size().height()))

        # Proportion of each dimension in relation to the smallest side
        # Note that one will always be the unit vector and the other greater than a unit
        screenUVec = screenSize / screenSize.min()
        imageUVec = imageSize / imageSize.min()


        # minBorder 11 is the distance between the Application vertical border and the central widget
        # 22 is the minimum height where the CentralWidget begins to appear 
        # Which should vary according to the height of menubar and statsbar of the QMainWindow
        minBorder = np.array([11,22]) *2
        screenSize -= minBorder
        for axis,size in enumerate(screenSize):
            if size < 0:
                screenSize[axis] = 0
        maxSize = np.zeros(2)

        # Ideal ratio based on the maxSide
        ratio =  int(round(screenSize[imageUVec.argmax()] / imageUVec.max() - 0.49999999))

        if ratio >=1 and 0 not in screenSize: # Image is scalable on the current screen
            maxSize[imageUVec.argmin()] = min(screenSize[imageUVec.argmin()],ratio) # We should add imageSize[imageUVec.argmin()] if we want to limit the maxSize to the maximum size of the image
            maxSize[imageUVec.argmax()] = maxSize[imageUVec.argmin()] * imageUVec.max()
            sizeUVec = maxSize / maxSize.min()


        # Layout
        layout = QHBoxLayout()
        layout.addWidget(logoContainer,0)
        logoLabel.setMaximumSize(QSize(maxSize[0],maxSize[1]))
        self.setLayout(layout)

特别感谢@alexisdm,他向我展示了HERE,我们应该首先擦除旧布局。当我开始看globals时,我看到几个布局是堆叠的。

至于重新缩放的部分,我仍然走的是一条非常规的道路,但它的表现正是我想要的。

【讨论】:

    猜你喜欢
    • 2016-10-09
    • 2021-12-20
    • 2013-04-18
    • 1970-01-01
    • 2016-06-09
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    相关资源
    最近更新 更多