|
| 1 | +#!/usr/bin/env python |
| 2 | +# -*- coding: utf-8 -*- |
| 3 | + |
| 4 | +""" |
| 5 | +Created on 2021/4/7 |
| 6 | +@author: Irony |
| 7 | +@site: https://github.com/PyQt5 |
| 8 | + |
| 9 | +@file: QQMenu |
| 10 | +@description: |
| 11 | +""" |
| 12 | +import string |
| 13 | +from random import choice, randint |
| 14 | + |
| 15 | +from PyQt5.QtCore import Qt |
| 16 | +from PyQt5.QtGui import QPixmap, QPainter, QFont, QIcon |
| 17 | +from PyQt5.QtWidgets import QLabel, QMenu, QApplication |
| 18 | + |
| 19 | +Style = """ |
| 20 | +QMenu { |
| 21 | + /* 半透明效果 */ |
| 22 | + background-color: rgba(255, 255, 255, 230); |
| 23 | + border: none; |
| 24 | + border-radius: 4px; |
| 25 | +} |
| 26 | +
|
| 27 | +QMenu::item { |
| 28 | + border-radius: 4px; |
| 29 | + /* 这个距离很麻烦需要根据菜单的长度和图标等因素微调 */ |
| 30 | + padding: 8px 48px 8px 36px; /* 36px是文字距离左侧距离*/ |
| 31 | + background-color: transparent; |
| 32 | +} |
| 33 | +
|
| 34 | +/* 鼠标悬停和按下效果 */ |
| 35 | +QMenu::item:selected { |
| 36 | + border-radius: 0px; |
| 37 | + /* 半透明效果 */ |
| 38 | + background-color: rgba(232, 232, 232, 232); |
| 39 | +} |
| 40 | +
|
| 41 | +/* 禁用效果 */ |
| 42 | +QMenu::item:disabled { |
| 43 | + background-color: transparent; |
| 44 | +} |
| 45 | +
|
| 46 | +/* 图标距离左侧距离 */ |
| 47 | +QMenu::icon { |
| 48 | + left: 15px; |
| 49 | +} |
| 50 | +
|
| 51 | +/* 分割线效果 */ |
| 52 | +QMenu::separator { |
| 53 | + height: 1px; |
| 54 | + background-color: rgb(232, 236, 243); |
| 55 | +} |
| 56 | +""" |
| 57 | + |
| 58 | + |
| 59 | +def get_icon(): |
| 60 | + # 测试模拟图标 |
| 61 | + pixmap = QPixmap(16, 16) |
| 62 | + pixmap.fill(Qt.transparent) |
| 63 | + painter = QPainter() |
| 64 | + painter.begin(pixmap) |
| 65 | + painter.setFont(QFont('Webdings', 11)) |
| 66 | + painter.setPen(Qt.GlobalColor(randint(4, 18))) |
| 67 | + painter.drawText(0, 0, 16, 16, Qt.AlignCenter, |
| 68 | + choice(string.ascii_letters)) |
| 69 | + painter.end() |
| 70 | + return QIcon(pixmap) |
| 71 | + |
| 72 | + |
| 73 | +def about_qt(): |
| 74 | + # 关于Qt |
| 75 | + QApplication.instance().aboutQt() |
| 76 | + |
| 77 | + |
| 78 | +class Window(QLabel): |
| 79 | + |
| 80 | + def __init__(self, *args, **kwargs): |
| 81 | + super(Window, self).__init__(*args, **kwargs) |
| 82 | + self.resize(400, 400) |
| 83 | + self.setAlignment(Qt.AlignCenter) |
| 84 | + self.setText('右键弹出菜单') |
| 85 | + self.context_menu = QMenu(self) |
| 86 | + self.init_menu() |
| 87 | + |
| 88 | + def contextMenuEvent(self, event): |
| 89 | + self.context_menu.exec_(event.globalPos()) |
| 90 | + |
| 91 | + def init_menu(self): |
| 92 | + # 背景透明 |
| 93 | + self.context_menu.setAttribute(Qt.WA_TranslucentBackground) |
| 94 | + # 无边框、去掉自带阴影 |
| 95 | + self.context_menu.setWindowFlags( |
| 96 | + self.context_menu.windowFlags() | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint) |
| 97 | + |
| 98 | + # 模拟菜单项 |
| 99 | + for i in range(10): |
| 100 | + if i % 2 == 0: |
| 101 | + action = self.context_menu.addAction('菜单 %d' % i, about_qt) |
| 102 | + action.setEnabled(i % 4) |
| 103 | + elif i % 3 == 0: |
| 104 | + self.context_menu.addAction(get_icon(), '菜单 %d' % i, about_qt) |
| 105 | + if i % 4 == 0: |
| 106 | + self.context_menu.addSeparator() |
| 107 | + if i % 5 == 0: |
| 108 | + # 二级菜单 |
| 109 | + # 二级菜单 |
| 110 | + menu = QMenu('二级菜单 %d' % i, self.context_menu) |
| 111 | + # 背景透明 |
| 112 | + menu.setAttribute(Qt.WA_TranslucentBackground) |
| 113 | + # 无边框、去掉自带阴影 |
| 114 | + menu.setWindowFlags(menu.windowFlags() | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint) |
| 115 | + for j in range(3): |
| 116 | + menu.addAction(get_icon(), '子菜单 %d' % j) |
| 117 | + self.context_menu.addMenu(menu) |
| 118 | + |
| 119 | + |
| 120 | +if __name__ == '__main__': |
| 121 | + import sys |
| 122 | + import cgitb |
| 123 | + |
| 124 | + cgitb.enable(1, None, 5, '') |
| 125 | + app = QApplication(sys.argv) |
| 126 | + app.setStyleSheet(Style) |
| 127 | + w = Window() |
| 128 | + w.show() |
| 129 | + sys.exit(app.exec_()) |
0 commit comments