• 如何在 pyqt 中解决启用 DPI 缩放后 QIcon 模糊的问题


    问题描述

    如今显示器的分辨率越来越高,如果不启用 DPI 缩放,软件的字体和图标在高分屏下就会显得非常小,看得很累人。从 5.6 版本开始,Qt 便能支持 DPI 缩放功能,Qt6 开始这个功能是默认开启的。

    启用 DPI 缩放后,文字不会有太明显的锯齿问题,但是使用 QIcon 设置的图标却会显得很模糊。比如下述代码:

    复制# coding:utf-8
    import os
    import sys
    
    from PyQt5.QtGui import QIcon
    from PyQt5.QtWidgets import QApplication, QPushButton, QWidget
    
    
    class Demo(QWidget):
    
        def __init__(self):
            super().__init__(parent=None)
            self.resize(300, 300)
            self.button = QPushButton(' Shuffle all', self)
            self.button.setIcon(QIcon("Shuffle.png"))
            self.button.move(self.width()//2-self.button.width()//2,
                             self.height()//2-self.button.height()//2)
    
    
    if __name__ == '__main__':
        os.environ["QT_ENABLE_HIGHDPI_SCALING"] = "0"
        os.environ["QT_SCALE_FACTOR"] = '1.25'
        app = QApplication(sys.argv)
        demo = Demo()
        demo.show()
        app.exec_()
    
    

    运行结果如下图所示,可以看到图标的锯齿现象非常明显:

    问题解决

    QIcon 底层依靠 QIconEngine 来绘制图标,生成图标的 pixmap。猜测 QIconEngine 使用 QPainter 绘制图标时没有设置 QPainter.SmoothPixmapTransform 标志位,所以导致只缩放了图标,而没有进行平滑插值。为了解决这个问题,我们可以继承 QIconEngine,重写两个虚方法 paint()pixmap(),代码如下:

    复制# coding:utf-8
    from PyQt5.QtCore import QPoint, QRect, QSize, Qt
    from PyQt5.QtGui import QIcon, QIconEngine, QImage, QPixmap, QPainter
    
    
    class PixmapIconEngine(QIconEngine):
        """ Pixmap icon engine """
    
        def __init__(self, iconPath: str):
            self.iconPath = iconPath
            super().__init__()
    
        def paint(self, painter: QPainter, rect: QRect, mode: QIcon.Mode, state: QIcon.State):
            painter.setRenderHints(QPainter.Antialiasing |
                                   QPainter.SmoothPixmapTransform)
            painter.drawImage(rect, QImage(self.iconPath))
    
        def pixmap(self, size: QSize, mode: QIcon.Mode, state: QIcon.State) -> QPixmap:
            pixmap = QPixmap(size)
            pixmap.fill(Qt.transparent)
            self.paint(QPainter(pixmap), QRect(QPoint(0, 0), size), mode, state)
            return pixmap
    
    
    class Icon(QIcon):
    
        def __init__(self, iconPath: str):
            self.iconPath = iconPath
            super().__init__(PixmapIconEngine(iconPath))
    
    

    接着只要把 QIcon 换成 Icon,并开启 app.setAttribute(Qt.AA_UseHighDpiPixmaps),就能解决图标模糊的问题了,效果如下图所示:

  • 相关阅读:
    【搜索】—— 迭代加深/双向DFS/IDA*
    Leetcode算法题
    【Spring云原生系列】SpringBoot+Spring Cloud Stream:消息驱动架构(MDA)解析,实现异步处理与解耦合
    电脑文件夹加密怎么操作?保护数据4个方法分享!
    Spring Cloud Alibaba—Sentinel 控制台安装
    Git提交代码.gitignore的模版
    STM32CubeMX教程24 WDG - 独立窗口看门狗
    玩转Vue3之Composables
    HashMap computeIfAbsent() 方法
    C++字符串与整数的相互转换
  • 原文地址:https://www.cnblogs.com/zhiyiYo/p/16259597.html