QT设置widget属性为FramelessWindowHint导致界面不刷新的问题解决

本文提供了一个针对QT5版本中窗口显示问题的有效解决方案。通过重载窗口的showEvent方法,并设置Qt::WA_Mapped属性,可以解决该BUG。

据说这是QT5之后的BUG,还没有深入研究,只是找到了一个解决方法,这里做一下记录:
对窗口重载showEven,实现以下代码即可。

void BaseWindow::showEvent(QShowEvent *event)
{
#if QT_VERSION >= 0x050000
    this->setAttribute(Qt::WA_Mapped);
#endif

    QWidget::showEvent(event);
}
你遇到的问题: > **右键点击触发的是浏览器默认的上下文菜单(如“刷新”、“检查元素”等),而是你自己定义的 `contextMenuEvent`。** 这是一个在使用 `QWebEngineView` 时非常常见的问题。 --- ### ❓ 原因分析 虽然你在 `SpinePet` 类中重写了 `contextMenuEvent` 方法,但这个事件是发给 **QWidget 自身** 的。而你的 `QWebEngineView` 是一个独立的、嵌套在布局中的控件,它内部运行着完整的 Chromium 浏览器引擎。 当你右键点击的是 **网页区域(即 `self.view`)** 而是窗口空白区域时: - Qt 把鼠标事件交给了 `QWebEngineView` - `QWebEngineView` 默认会显示 **浏览器原生右键菜单** - 你的 `SpinePet.contextMenuEvent()` 根本没有被调用! 所以你看到的是 “刷新页面”、“检查” 这类菜单,而是你写的动画选择菜单。 --- ## ✅ 正确解决方案:拦截网页的右键菜单 你需要做两件事: ### ✅ 1. 禁用 QWebEngineView 的默认右键菜单 通过重写其 `contextMenuEvent` 或连接信号来阻止默认行为。 ### ✅ 2. 将右键事件转发到主窗口的自定义菜单 --- ### ✅ 解决方案代码(完整可用) ```python from PySide6.QtWidgets import QApplication, QWidget, QMenu, QVBoxLayout from PySide6.QtWebEngineWidgets import QWebEngineView from PySide6.QtCore import Qt, QUrl, QPoint, QEvent from PySide6.QtGui import QCursor class CustomWebEngineView(QWebEngineView): """自定义 QWebEngineView,拦截右键菜单""" def __init__(self, parent=None): super().__init__(parent) self.parent_widget = parent def contextMenuEvent(self, event): # ⛔ 禁止默认的右键菜单弹出 event.accept() # ✅ 转发给父窗口处理自定义菜单 if hasattr(self.parent_widget, 'show_context_menu'): self.parent_widget.show_context_menu(event.globalPos()) else: print("No show_context_menu method found on parent.") class SpinePet(QWidget): def __init__(self): super().__init__() self.offset = QPoint() self.init_ui() def init_ui(self): self.setWindowFlags( Qt.WindowType.FramelessWindowHint | Qt.WindowType.WindowStaysOnTopHint | Qt.WindowType.Tool ) self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True) self.setAttribute(Qt.WidgetAttribute.WA_ShowWithoutActivating, True) layout = QVBoxLayout() layout.setContentsMargins(0, 0, 0, 0) layout.setSpacing(0) # 使用自定义的 WebEngineView self.view = CustomWebEngineView(self) # 注意传 self 作为 parent page = self.view.page() page.setBackgroundColor(Qt.GlobalColor.transparent) # 启用必要设置 settings = page.settings() settings.setAttribute(settings.WebAttribute.JavascriptEnabled, True) settings.setAttribute(settings.WebAttribute.LocalContentCanAccessFileUrls, True) settings.setAttribute(settings.WebAttribute.LocalContentCanAccessRemoteUrls, True) # 加载本地文件 current_dir = os.path.dirname(os.path.abspath(__file__)) html_path = os.path.join(current_dir, "desktop-character.html") self.view.load(QUrl.fromLocalFile(html_path)) layout.addWidget(self.view) self.setLayout(layout) self.resize(400, 600) self.move(100, 100) def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.offset = event.position().toPoint() event.accept() def mouseMoveEvent(self, event): if event.buttons() & Qt.MouseButton.LeftButton: self.move(self.mapToParent(event.position().toPoint() - self.offset)) event.accept() def show_context_menu(self, pos): """由 CustomWebEngineView 调用,显示自定义菜单""" menu = QMenu(self) # 动画子菜单 anim_menu = menu.addMenu("动画") animations = { "待机": "idle", "开心 😊": "emoji_2", "生气 💢": "emoji_1", "脸红 🌸": "emoji_3", "星星眼 ✨": "emoji_0", "说话 🗣️": "emoji_5", "问号 ❓": "emoji_4" } for label, anim_name in animations.items(): action = anim_menu.addAction(label) action.triggered.connect(lambda checked=False, name=anim_name: self.play_animation(name, True)) # 背景模式子菜单 bg_menu = menu.addMenu("背景模式") white_action = bg_menu.addAction("白色背景") transparent_action = bg_menu.addAction("透明背景") white_action.triggered.connect(lambda: self.toggle_background("white")) transparent_action.triggered.connect(lambda: self.toggle_background("transparent")) # 在指定位置弹出菜单 menu.exec(pos) def play_animation(self, anim_name, loop=True): js_code = f"playAnimation('{anim_name}', {str(loop).lower()})" self.view.page().runJavaScript(js_code) def toggle_background(self, mode): js_code = f"toggleBackgroundMode('{mode}')" self.view.page().runJavaScript(js_code) ``` --- ### ✅ 关键点解释 | 技术点 | 说明 | |--------|------| | `CustomWebEngineView` | 继承 `QWebEngineView` 并重写 `contextMenuEvent` | | `event.accept()` | 阻止默认菜单出现 | | `self.parent_widget.show_context_menu(pos)` | 将事件转发给主窗口处理 | | `menu.exec(pos)` | 在鼠标位置显示自定义菜单 | --- ### ✅ 效果 现在无论你右键点击宠物的哪个部分(包括透明区域或动画本身),都会弹出你设计的菜单,而再是浏览器的“刷新”菜单。 --- ### ✅ 可选增强:支持左键长按模拟右键菜单(用于触屏设备) ```python def mousePressEvent(self, event): if event.button() == Qt.MouseButton.LeftButton: self.offset = event.position().toPoint() self._press_pos = event.position().toPoint() self._press_time = time.time() event.accept() def mouseReleaseEvent(self, event): if event.button() == Qt.MouseButton.RightButton: return # 检查是否为长按(例如超过 800ms) if event.button() == Qt.MouseButton.LeftButton: duration = time.time() - self._press_time if duration > 0.8: self.show_context_menu(QCursor.pos()) event.accept() ``` 记得导入 `time` 模块。 --- ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值