增加 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 所做的以保持代码尽可能简单;
- 这幅画 完全 不一样,最重要的是图标在单击时缺少“高亮”阴影,如果样式使用淡入淡出 in/out 效果清除按钮这些效果将不可用;
- QProxyStyle方法也影响了QLineEdit的
sizeHint
,所以不能不能小于图标大小,慎用;
我有 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 所做的以保持代码尽可能简单;
- 这幅画 完全 不一样,最重要的是图标在单击时缺少“高亮”阴影,如果样式使用淡入淡出 in/out 效果清除按钮这些效果将不可用;
- QProxyStyle方法也影响了QLineEdit的
sizeHint
,所以不能不能小于图标大小,慎用;