首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QMenu中的圆角

QMenu中的圆角
EN

Stack Overflow用户
提问于 2021-01-05 07:16:29
回答 2查看 1.2K关注 0票数 1

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

上下文菜单应该如下所示。

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

代码语言:javascript
复制
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()

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

这就是我在使用样式表时得到的结果,它不是完全四舍五入的。

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

代码语言:javascript
复制
    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()

代码语言:javascript
复制
self.pen = QtGui.QPen(QtCore.Qt.red)
self.pen.setWidth(2)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-01-05 11:40:36

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

虽然克里斯蒂安·卡切尔( Christian Karcher )提议的solution很好,但需要考虑两个重要问题:

  1. 系统必须支持复合;虽然这对于大多数现代OSes来说都是正确的,至少在Linux上是这样的,但即使是最新的系统也有可能选择不支持它(我在计算机上禁用了);如果是这样,设置WA_TranslucentBackground属性将无法工作。在Linux上设置
  2. FramelessWindowHint FramelessWindowHint不应该,因为它可能会导致窗口管理器的问题,所以只有在确保操作系统需要它之后才能设置它。

g 210

有鉴于此,当不支持组合时,使用setMask()是正确的修复,这必须发生在resizeEvent()中。请注意,掩蔽是基于位图的,并且不支持反混叠,因此圆形边框有时会因边框半径的不同而有点难看。

另外,由于您希望使用自定义颜色,所以必须使用样式表,因为QMenu的自定义绘图实际上是很难实现的

代码语言:javascript
复制
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实现,由于上述原因,在这种特殊情况下没有必要,但仍然很重要(有些要点与已注释的部分代码有关,但您尝试它们的事实使这些方面值得一提):

用于小部件的

  1. (用于小部件的QPainter )必须在paintEvent()之外实例化:像在__init__中创建实例一样,这是一个严重的错误,甚至可能导致崩溃。只有在接收到paintEvent时才能创建画家,而且绝不能重复使用。这显然使设置它为一个实例属性(self.painter)毫无用处,因为没有实际的理由在画图事件之后访问它。如果画笔宽度总是相同的,那么只需在构造函数(self.pen = QtGui.QPen(QtCore.Qt.red, 2))中设置它,在paintEvent中连续设置它是self.painter,QBrush可以直接接受Qt全局颜色,因此,不需要创建一个self.painter.setBrush(QtCore.Qt.blue).
  2. self.update()实例,因为画家将自动(内部和快速地)设置它:如果永远不会在paintEvent中调用(甚至self.repaint()也不应该)。在未定义(也可能是dangerous.
  3. If )中,您使用QPainter进行一些手工绘制,然后调用超级paintEvent,结果很可能是以前绘制的所有内容都将被隐藏;作为一般规则,应该先调用基本实现,然后再调用其他自定义画法(在这种情况下,它显然不会工作,因为您将绘制一个填充的圆角,使菜单项不可见)。
票数 1
EN

Stack Overflow用户

发布于 2021-01-05 09:21:25

我不能评论paintEvent的功能,但是可以使用样式表实现圆角。为了禁用背景中的默认矩形,必须修改一些q菜单属性,这会给出不想要的结果。

下面是使用样式表+自定义标志(没有框架+透明背景)的示例的修改版本:

代码语言:javascript
复制
from PyQt5 import QtWidgets, 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 = QtWidgets.QMenu()
        # disable default frame and background
        cmenu.setWindowFlags(QtCore.Qt.FramelessWindowHint)
        cmenu.setAttribute(QtCore.Qt.WA_TranslucentBackground)
        # set stylesheet, add some padding to avoid overlap of selection with rounded corner
        cmenu.setStyleSheet("""
            QMenu{
                  background-color: rgb(255, 255, 255);
                  border-radius: 20px;
            }
            QMenu::item {
                    background-color: transparent;
                    padding:3px 20px;
                    margin:5px 10px;
            }
            QMenu::item:selected { background-color: gray; }
        """)

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

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


if __name__ == '__main__':
    main()
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65574567

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档