动态调整 QIcon 的大小而不调用 setSizeIcon()

Posted

技术标签:

【中文标题】动态调整 QIcon 的大小而不调用 setSizeIcon()【英文标题】:Dynamically resize QIcon without calling setSizeIcon() 【发布时间】:2015-07-31 09:03:11 【问题描述】:

我目前正在努力解决应该很容易解决的问题。许多小部件支持某种 QSizePolicy。这包括 QPushbutton。在我的例子中,我在网格布局中有多个按钮,所有这些按钮的 QSizePolicy 都将 vertical 和 Horizo​​ntal 调整大小设置为 expanding。这会导致按钮的大小根据网格布局所属的小部件的大小进行调整。

问题来自于 Qt 中图标的处理方式。 QIcon 没有 QSizePolicy 属性(或者至少我在 Qt4 的官方文档中找不到关于 QIcon 和 QAbstractButton 的属性)。唯一的方法似乎是使用 setIconSize() ,您可以在其中提供图标的最大尺寸。此外,必须手动实施有关如何更新大小的例程。在这种情况下,它将是(此处抽象写作)icon.size == button.size-CONSTANT,其中 CONSTANT 是某种预定义因子 (>= 0)。也可以为所选图标预定义各种尺寸(QIcons 列表),但仍然不是一个好的选择(请阅读下面的原因)。

这似乎有点过头了,特别是因为 QPushbutton 支持 QSizePolicy 并且开发人员根本不需要在这个部门进行修补,除非他/她想要进行一些特殊的调整大小。这也与 QIcon 中对 SVG 文件的支持相矛盾,因为我们知道,SVG = 矢量图形 = 您可以在不损失质量的情况下随意拉伸它们。 p>

有没有人知道一种简单的方法来做到这一点,而无需添加额外的偶数句柄来调整大小、提供所选图标的比例列表或将大小限制为最大大小?

PS:我也研究了 QPixmap - 那里仍然存在同样的问题。

编辑: 我忘了提到我发现如何做我想做的事的一种方法(但结果并不像我想要的那样漂亮) - 在QPushbutton 的样式表中使用 image 属性。但是,这不会创建图标!如果一个人并不真正需要一个真正的图标并且可以只使用一个绘制按钮,那么使用此属性可以在调整大小方面提供巨大的灵活性,尤其是在使用 SVG 时。

【问题讨论】:

QIconQPixmap 没有 sizePolicy,因为它们不是小部件,不能放入布局中。不幸的是QPushButtonQToolButton 无法缩放他们的图标。您可以尝试将其中一个子类化并更改paintEvent 实现,以便缩放图标。您也可以使用QLabel 显示缩放的像素图,但它不能像按钮一样。 太复杂了。我想我会坚持调整大小事件并简单地使用 setIconSize() 为 QPushbutton 调整图标大小。 @PavelStrakhov 您能否发表您的评论作为答案,以便我接受。它准确地回答了这个问题:QIcon、QPixmap 没有 sizePolicy,因为它们不是小部件(所以实际上只有小部件有 sizePolicy,说实话我不知道)。 【参考方案1】:

子类QPushButton,正如@Pavel 在评论中所建议的那样,似乎是解决您的问题的合理选择。下面我提供了一个简单的示例,说明如何在PySide 中完成此操作。

import sys
from PySide import QtGui, QtCore

class myContainter(QtGui.QWidget):
    def __init__(self, parent=None):
        super(myContainter, self).__init__(parent)

        icon = QtGui.QIcon('process-stop.png')

        grid = QtGui.QGridLayout()

        for i in range(3):
            button = myPushButton()
            button.setIcon(icon) 

            grid.addWidget(button, i, 0)

            grid.setRowStretch(i, i)

        self.setLayout(grid)


class myPushButton(QtGui.QPushButton):
    def __init__(self, label=None, parent=None):
        super(myPushButton, self).__init__(label, parent)

        self.pad = 4     # padding between the icon and the button frame
        self.minSize = 8 # minimum size of the icon

        sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding,
                                       QtGui.QSizePolicy.Expanding)
        self.setSizePolicy(sizePolicy)

    def paintEvent(self, event):

        qp = QtGui.QPainter()
        qp.begin(self)

        #---- get default style ----

        opt = QtGui.QStyleOptionButton()
        self.initStyleOption(opt)

        #---- scale icon to button size ----

        Rect = opt.rect

        h = Rect.height()
        w = Rect.width()
        iconSize = max(min(h, w) - 2 * self.pad, self.minSize)

        opt.iconSize = QtCore.QSize(iconSize, iconSize)

        #---- draw button ----

        self.style().drawControl(QtGui.QStyle.CE_PushButton, opt, qp, self)

        qp.end()

if __name__ == '__main__':

    app = QtGui.QApplication(sys.argv)

    instance = myContainter()  
    instance.show()    

    sys.exit(app.exec_())

结果:

图标的最大尺寸受png 的尺寸限制,该png 用作QIcon 中的输入。如果svg 用作QIcon 的输入,则图标的缩放将不受大小限制。但是,svg 图标似乎在 Windows7 中不受支持,但它们在 Ubuntu 中。

如果将标签添加到按钮,则需要扩展上面的代码。此外,如果需要,还可以将标签的字体大小缩放为按钮大小。

【讨论】:

我只在 Linux 上开发,因此 Windows 的 SVG 问题并不重要(可怜的 Windows)。坦率地说,您的解决方案使用了太多代码。 LOL 只需设置QWidget的resizeEvent调用QPushbutton的setIconSize(),图标的大小由按钮的大小定义。真的是单线。另外,我的问题主要是是否可以在不编写任何额外事件处理的情况下做到这一点。它更像是“这个功能是开箱即用的吗?”一种问题。我可以使用paintEvent 和resizeEvent 来做到这一点,这根本不是问题。仍然感谢您的意见! @rbaleksandar 坦率地说,您的问题用词太多了:P。本来可以更简洁,认真直奔主题。感谢您提供有关使用 resizeEvent 的意见。我仍然更喜欢在paintEvent 中处理它,如果它超越了简单的图标缩放,它会提供更大的灵活性。 XD 你是对的。我只是很恼火,一个人必须做额外的工作,而 Qt 的另一个组件有这个开箱即用的功能。 :X【参考方案2】:

致在 C++ 中工作的人。非常感谢!

pushbuttoniconautoresize.h

#ifndef PUSHBUTTONIMAGEAUTOMATICRESIZE_H
#define PUSHBUTTONIMAGEAUTOMATICRESIZE_H

#include <QPushButton>

class PushButtonIconAutoResize : public QPushButton

    Q_OBJECT

public:
    PushButtonIconAutoResize(const QString &text, QWidget *parent=0);
    ~PushButtonIconAutoResize();

private:
    void paintEvent(QPaintEvent *event);

    int pad;
    int minSize;
;

#endif // PUSHBUTTONIMAGEAUTOMATICRESIZE_H

pushbuttoniconautoresize.cpp

#include "pushbuttoniconautoresize.h"

#include <QSize>
#include <QSizePolicy>
#include <QStylePainter>
#include <QStyleOptionButton>
#include <QtGlobal>

PushButtonIconAutoResize::PushButtonIconAutoResize(const QString &text, QWidget *parent)
    : QPushButton(text, parent)

    pad = 4;
    minSize = 8;

    this->setSizePolicy(QSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding));


PushButtonIconAutoResize::~PushButtonIconAutoResize()




void PushButtonIconAutoResize::paintEvent( QPaintEvent *event )

    QStylePainter painter(this);

    QStyleOptionButton opt;
    this->initStyleOption(&opt);

    QRect r = opt.rect;

    int h = r.height();
    int w = r.width();
    int iconSize = qMax(qMin(h, w) - 2 * this->pad, this->minSize);

    opt.iconSize = QSize(iconSize, iconSize);

    painter.drawControl(QStyle::CE_PushButton, opt);

【讨论】:

以上是关于动态调整 QIcon 的大小而不调用 setSizeIcon()的主要内容,如果未能解决你的问题,请参考以下文章

动态调整单个形状的大小而不缩放整个 SVG

JAVA:如何调整JPanel的大小

调整图像大小并显示而不保存

动态调整 pixi 舞台的大小及其在窗口调整大小和窗口加载时的内容

java组件的方法,比如setSize(),怎么用了这个方法整个窗口大小都变了,这是组件的方法呀?小弟刚接触java

调用 reloadData() 后自行调整动态 UICollectionViewCell 高度的大小不正确