【问题标题】:Increasing addAction icon size PyQt5增加 addAction 图标大小 PyQt5
【发布时间】:2020-12-11 21:30:26
【问题描述】:

我有 QLineEdit,我想在它的末尾添加一个清除按钮。我在 QLineEdit 中启用了清除按钮,它工作正常。我需要在 QLineEdit 的末尾添加一个自定义清除按钮,所以我使用了 QLineEdit 的 addAction() 并添加了我的自定义图标。问题是我找不到增加尺寸的解决方案,我尝试增加图像尺寸但它不起作用。

class TextBox(QFrame):
    def __init__(self, parent):
        super(TextBox, self).__init__(parent=parent)
        self.setObjectName("textBox")

        self.isActive = False

        self.lineEdit = QLineEdit()

        self.lineEdit.addAction(QIcon("assets/icons/clear@3x.png"), QLineEdit.TrailingPosition)

【问题讨论】:

    标签: python pyqt pyqt5


    【解决方案1】:

    QIcon 没有特定的大小,因为它仅由使用它的小部件“决定”。虽然大多数使用图标的小部件都有 iconSize 属性,但 QLineEdit 中的操作图标以不同的方式显示。

    在 Qt 5.11(排除)之前,如果行编辑小于 34 像素,则大小被硬编码为 16 像素,如果更高,则被硬编码为 32。

    从 Qt 5.11 开始,使用样式(通过pixelMetric())检索大小,并且可以使用代理样式覆盖:

    class Proxy(QtWidgets.QProxyStyle):
        def pixelMetric(self, metric, opt=None, widget=None):
            if (metric == self.PM_SmallIconSize and 
                isinstance(widget, QtWidgets.QLineEdit)):
                    size = widget.property('iconSize')
                    if size is not None:
                        return size
                    return widget.fontMetrics().height()
            return super().pixelMetric(metric, opt, widget)
    
    
    class LineEdit(QtWidgets.QLineEdit):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.setProperty('iconSize', 64)
            # ...
    

    不过,对于以前版本的 Qt,事情有点棘手。我想出的唯一解决方案是在所有作为行编辑子项的 QToolButton 上安装事件过滤器(每个操作都使用内部 QToolButton,包括清除操作),手动设置它们的几何图形(正确的单击操作所需)在事件过滤器中绘制它。

    如果当前版本如前所述正确支持它,以下包括 proxystyle 实现:

    from PyQt5 import QtWidgets, QtCore, QtGui
    
    if int(QtCore.QT_VERSION_STR.split('.')[1]) > 11:
        IconSizeFix = False
    else:
        IconSizeFix = True
    
    
    class Proxy(QtWidgets.QProxyStyle):
        def pixelMetric(self, metric, opt=None, widget=None):
            if (metric == self.PM_SmallIconSize and 
                isinstance(widget, QtWidgets.QLineEdit)):
                    size = widget.property('iconSize')
                    if size is not None:
                        return size
                    return widget.fontMetrics().height()
            return super().pixelMetric(metric, opt, widget)
    
    
    class LineEdit(QtWidgets.QLineEdit):
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.setProperty('iconSize', 64)
            self.setClearButtonEnabled(True)
            self.addAction(QtGui.QIcon("icon.png"), self.TrailingPosition)
            font = self.font()
            font.setPointSize(48)
            self.setFont(font)
    
        def checkButtons(self):
            for button in self.findChildren(QtWidgets.QToolButton):
                button.installEventFilter(self)
    
        def actionEvent(self, event):
            super().actionEvent(event)
            if IconSizeFix:
                self.checkButtons()
    
        def eventFilter(self, source, event):
            if event.type() == QtCore.QEvent.Paint:
                if (source.defaultAction().objectName() == '_q_qlineeditclearaction' and 
                    not self.text()):
                        return True
                qp = QtGui.QPainter(source)
                state = QtGui.QIcon.Disabled
                if source.isEnabled():
                    state = QtGui.QIcon.Active if source.isDown() else QtGui.QIcon.Normal
                iconSize = QtCore.QSize(*[self.property('iconSize')] * 2)
                qp.drawPixmap(source.rect(), source.icon().pixmap(
                    self.windowHandle(), iconSize, state, QtGui.QIcon.Off))
                return True
            return super().eventFilter(source, event)
    
        def resizeEvent(self, event):
            if not IconSizeFix:
                return
            self.checkButtons()
            buttons = self.findChildren(QtWidgets.QToolButton)
            if not buttons:
                return
    
            left = []
            right = []
            center = self.rect().center().x()
            for button in buttons:
                geo = button.geometry()
                if geo.center().x() < center:
                    left.append(button)
                else:
                    right.append(button)
            
            left.sort(key=lambda x: x.geometry().x())
            right.sort(key=lambda x: x.geometry().x())
    
            iconSize = self.property('iconSize')
    
            margin = iconSize / 4
            top = (self.height() - iconSize) / 2
            leftMargin = rightMargin = 0
            if left:
                x = margin
                leftEdge = left[-1].geometry().right()
                for button in left:
                    geo = QtCore.QRect(x, top, iconSize, iconSize)
                    button.setGeometry(geo)
                    x += iconSize + margin
                leftMargin = x - leftEdge - margin
            if right:
                rightEdge = self.width() - margin
                x = rightEdge - len(right) * iconSize - (len(right) - 1) * margin
                rightMargin = self.width() - rightEdge + margin
                for button in right:
                    geo = QtCore.QRect(x, top, iconSize, iconSize)
                    button.setGeometry(geo)
                    x += iconSize + margin
            self.setTextMargins(leftMargin, 0, rightMargin, 0)
    
    
    if __name__ == '__main__':
        import sys
        app = QtWidgets.QApplication(sys.argv)
        app.setStyle(Proxy())
        w = LineEdit()
        w.show()
        sys.exit(app.exec_())
    

    考虑以下几点:

    • 使用 5.11 之前的解决方法,定位不是像素完美的,我尝试模仿 QLineEdit 所做的以使代码尽可能简单;
    • 这幅画完全不一样,最重要的是图标在单击时缺少“突出显示”阴影,如果样式对清除按钮使用淡入/淡出效果,则这些效果不会'不可用;
    • QProxyStyle方法也会影响QLineEdit的sizeHint,所以不能小于图标大小,慎用;

    【讨论】:

      猜你喜欢
      • 2012-11-07
      • 2015-10-07
      • 1970-01-01
      • 1970-01-01
      • 2020-09-21
      • 2017-04-03
      • 1970-01-01
      • 1970-01-01
      • 2016-05-03
      相关资源
      最近更新 更多