簡體   English   中英

增加 addAction 圖標大小 PyQt5

[英]Increasing addAction icon size PyQt5

我有 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)

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 ,所以不能小於圖標大小,慎用;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM