pyqt中QMenu的圆角

2023-11-29

我正在尝试覆盖paintEvent() of QMenu使其具有圆角。

上下文菜单应该看起来像这样。

enter image description here

这是我尝试过的代码,但什么也没出现:

from PyQt5 import QtWidgets, QtGui, QtCore
import sys


class Example(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('Context menu')
        self.show()

    def contextMenuEvent(self, event):
        cmenu = AddContextMenu(self)

        newAct = cmenu.addAction("New")
        openAct = cmenu.addAction("Open")
        quitAct = cmenu.addAction("Quit")
        action = cmenu.exec_(self.mapToGlobal(event.pos()))


class AddContextMenu(QtWidgets.QMenu):

    def __init__(self, *args, **kwargs):
        super(AddContextMenu, self).__init__()
        self.painter = QtGui.QPainter(self)
        self.setMinimumSize(150, 200)

        self.pen = QtGui.QPen(QtCore.Qt.red)
        #self.setStyleSheet('color:white; background:gray; border-radius:4px; border:2px solid white;')

    def paintEvent(self, event) -> None:
        self.pen.setWidth(2)

        self.painter.setPen(self.pen)
        self.painter.setBrush(QtGui.QBrush(QtCore.Qt.blue))
        self.painter.drawRoundedRect(10, 10, 100, 100, 4.0, 4.0)
        self.update()
        #self.repaint()
        #super(AddContextMenu, self).paintEvent(event)

def main():
    app = QtWidgets.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

注意:设置样式表对我不起作用:

这是我使用样式表时得到的结果它不是完全圆角的。

enter image description here

这是@musicamante建议后的paintEvent(仅供他/她检查)

    def paintEvent(self, event) -> None:
        painter = QtGui.QPainter(self)

        #self.pen.setColor(QtCore.Qt.white)
        #painter.setFont(QtGui.QFont("times", 22))
        #painter.setPen(self.pen)
        #painter.drawText(QtCore.QPointF(0, 0), 'Hello')

        self.pen.setColor(QtCore.Qt.red)
        painter.setPen(self.pen)
        painter.setBrush(QtCore.Qt.gray)
        painter.drawRoundedRect(self.rect(), 20.0, 20.0)
      

并在 init() 中

self.pen = QtGui.QPen(QtCore.Qt.red)
self.pen.setWidth(2)

在样式表中设置边框半径顶级小部件(有自己的“窗口”的小部件)是不够的。

虽然solutionChristian Karcher 提出的方案很好,但需要考虑两个重要因素:

  1. 系统must支持合成;虽然对于大多数现代操作系统来说都是如此,但至少在 Linux 上,即使是最新的系统也有可能这样做not选择支持它(我在我的计算机上禁用了);如果是这种情况,请设置WA_TranslucentBackground属性将不起作用。
  2. The FramelessWindowHint should not在Linux上设置,因为它可能会导致窗口管理器出现问题,因此只有在确保操作系统需要它(Windows)后才应设置。

有鉴于此,使用setMask()当不支持合成时,这是正确的修复,并且这必须在resizeEvent()。请注意,掩蔽是bitmap基于,抗锯齿是not支持,因此圆形边框有时会有点难看,具体取决于边框半径。

另外,由于您想要自定义颜色,因此必须使用样式表,因为 QMenu 的自定义绘画是really很难实现。

class AddContextMenu(QtWidgets.QMenu):
    def __init__(self, *args, **kwargs):
        super(AddContextMenu, self).__init__()
        self.setMinimumSize(150, 200)
        self.radius = 4
        self.setStyleSheet('''
            QMenu {{
                background: blue;
                border: 2px solid red;
                border-radius: {radius}px;
            }}
            QMenu::item {{
                color: white;
            }}
            QMenu::item:selected {{
                color: red;
            }}
        '''.format(radius=self.radius))

    def resizeEvent(self, event):
        path = QtGui.QPainterPath()
        # the rectangle must be translated and adjusted by 1 pixel in order to 
        # correctly map the rounded shape
        rect = QtCore.QRectF(self.rect()).adjusted(.5, .5, -1.5, -1.5)
        path.addRoundedRect(rect, self.radius, self.radius)
        # QRegion is bitmap based, so the returned QPolygonF (which uses float
        # values must be transformed to an integer based QPolygon
        region = QtGui.QRegion(path.toFillPolygon(QtGui.QTransform()).toPolygon())
        self.setMask(region)

关于您的paintEvent实现的一些旁注,由于上述原因在这种特定情况下是不必要的,但仍然很重要(有些点与已注释的代码部分相关,但事实上您tried他们值得一提的是这些方面):

  1. 用于小部件的 QPainter 必须never在 a 之外实例化paintEvent():在中创建实例__init__正如您所做的那样是一个严重的错误,甚至可能导致崩溃。画家只有在收到paintEvent时才能创建,并且应该never被重用。这显然使得将其设置为实例属性毫无用处(self.painter),因为在绘制事件之后没有实际理由访问它。
  2. 如果画笔宽度始终相同,则只需在构造函数中设置它(self.pen = QtGui.QPen(QtCore.Qt.red, 2)),在paintEvent中不断设置是没有用的。
  3. QPen 和 QBrush 可以直接接受 Qt 全局颜色,因此无需创建 QBrush 实例,因为画家会自动(内部且快速)设置它:self.painter.setBrush(QtCore.Qt.blue).
  4. self.update() should never在 PaintEvent 中调用(甚至不self.repaint()应该)。结果是不确定的并且可能是危险的。
  5. 如果您使用 QPainter 进行一些手动绘画并且then调用超级paintEvent,结果很可能是之前绘制的所有内容都会被隐藏;作为一般规则,基本实现应该被称为first,那么任何其他自定义绘画都应该发生after(在这种情况下,它显然不起作用,因为您将绘制一个填充的圆角矩形,使菜单项不可见)。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pyqt中QMenu的圆角 的相关文章

随机推荐

  • 带有 Paramiko 和 RSA 密钥文件的嵌套 SSH

    我正在尝试使用 Paramiko 嵌套 SSH 我将从本地计算机连接到服务器 X 然后从那里连接到服务器 Y 在这里 为了连接到服务器 X 我使用用户名 密码身份验证 并使用用户名和密码连接到服务器 Y RSA 密钥 问题是 RSA 密钥托
  • Java:检测客户端与服务器端断开连接[重复]

    这个问题在这里已经有答案了 我正在使用 Socket 和 ServerSocket 编写 Java 客户端 服务器程序 多个客户端同时连接到服务器 检查客户端连接是否已与服务器端断开的最佳方法是什么 现在 当我尝试写入断开连接的客户端时 我
  • 为什么使用HttpClient进行同步连接

    我正在构建一个类库来与 API 交互 我需要调用 API 并处理 XML 响应 我可以看到使用的好处HttpClient对于异步连接 但我所做的是纯粹同步的 所以我看不到比使用有任何显着的好处HttpWebRequest 如果有人能提供任何
  • 如何设置非标准 gstreamer 属性的类型?

    我正在尝试设置pattern财产为videotestsrc 按照正常逻辑 我尝试将变量设置为i32和一根绳子 两者都会失败并出现要求特定类型的错误 查看 gstreamer API 我找不到设置该属性的方法 如何强制变量的类型与预期匹配 l
  • 为什么需要 Swing Utilities 以及如何使用它?

    这主要是针对我的问题here 但我不明白为什么摇摆实用程序是否需要以及它的用途 我正在设计一个 Swing GUI 我不想错过 Swing Utilities 可能提供的任何功能 也有人可以解释一下是什么invokeLater方法的作用及其
  • 如何判断图像何时已在 IE9 的浏览器缓存中?

    IE9显示错误complete具有以下属性 img src http farm2 static flickr com 1104 1434841504 edc671e65c jpg each function console log this
  • 将整数转换为工作日列表

    我在数据库中存储了一个整数 SQLAgent 频率间隔 该整数实际上是计划运行的一周中选定天数的总和 可能的值是这些值的任意组合 周日 1 星期一 2 星期二 4 星期三 8 星期四 16 星期五 32 星期六 64 ex 65 表示该计划
  • 计算字典中的值

    我有一本字典如下 dictA a duck duck goose b goose goose c duck duck duck d goose e duck duck 我希望循环遍历 dictA 并输出一个列表 该列表将向我显示 dictA
  • 从 SceneDelegate 更新屏幕结构的状态

    我来自 React Native 是 Swift 和 SwiftUI 的初学者 我很好奇当应用程序返回前台时如何在特定屏幕上执行操作并更新状态 我想检查通知的状态 允许 拒绝 等 并更新用户界面 这是一些示例代码 这是我要更新的视图 str
  • 在编译时展开循环

    我想将大量行写入以下形式的 C 文件中foo i for i 0 1 n 有没有办法在编译时执行此操作 我想这样做是因为我有一个模板类 template
  • 使用 AWS 弹性负载均衡器和 Nginx 将非 www 转换为 www

    我有一个在 example com 上运行的应用程序 现在我想将所有流量重定向到 www example com 因为我们正在与 Akamai 的 CDN 合作开发您的网站 我的域名停放在 Route53 中 添加了 Elastic Loa
  • 设置 ZF2 中的 (404) 错误页面使用的布局变量

    目前 我使用 BaseController 的 onDispatch 方法 我的所有其他控制器都扩展了该方法 设置了应用程序的整体布局 phtml 使用的几个变量 public function onDispatch MvcEvent e
  • Android NDK 中的文件操作

    出于性能原因 我使用 Android NDK 主要用 C 语言制作应用程序 但似乎 fopen 等文件操作在 Android 中无法正常工作 每当我尝试使用这些功能时 应用程序就会崩溃 如何使用 Android NDK 创建 写入文件 其他
  • 如何将 pandas 中的制表符分隔更改为逗号分隔

    我不知道这是否可能 我正在尝试将 12 个文件附加到一个文件中 其中一个文件以制表符分隔 其余文件以逗号分隔 我将所有 12 个文件加载到 dataframe 中 并循环将其一一附加到一个空 dataframe 中 list of file
  • 如何在R中对两个变量进行交叉制表?

    这似乎是基本的 但我不会明白 我正在尝试计算 R 中数据的频率表 如下所示 1 2 2 1 3 1 我想传输 csv 输出中的双向频率 其行将是数据 A 列中的所有唯一条目 其列将是数据 B 列中的所有唯一条目 单元格值将是这些值出现的次数
  • 托管在 Windows 服务中的 WCF 出现安全异常,即使它应该在完全信任下运行

    我们在 Windows 服务中托管 WCF 服务 NET 4 0 它在大多数机器上运行得很好 但在某些机器上它会抛出以下异常 错误 为 system serviceModel bindings 创建配置节处理程序时发生错误 该程序集不允许部
  • Python multiprocessing.pool 与类目标函数和神经进化的交互

    警告 这将是很长一段时间 因为我想尽可能具体 确切的问题 这是一个多重处理问题 我确保我的类都按照之前实验中构建 预期的方式运行 编辑 事先说过线程 当我在线程环境中运行问题的玩具示例时 一切正常 然而 当我转向真正的问题时 代码就崩溃了
  • Intent BOOT_COMPLETED 在华为设备上不起作用

    我想在我的 Android 应用程序中收听 APN 更改 因此我启动了一项服务android intent action BOOT COMPLETED 该服务启动一个 ContentObserver 来监听更改content telepho
  • 如何在构建定义的“流程”部分中刷新构建流程模板的更新参数?

    For a build process template 我们可以添加 删除 编辑它的参数列表 并将其用作构建 工作流程步骤中的变量 我读了很好的指南here 我正在克隆模板默认模板 11 1 xaml to sayHello Defaul
  • pyqt中QMenu的圆角

    我正在尝试覆盖paintEvent of QMenu使其具有圆角 上下文菜单应该看起来像这样 这是我尝试过的代码 但什么也没出现 from PyQt5 import QtWidgets QtGui QtCore import sys cla