pywebview窗口移动解决方案

pywebview 无边框窗口移动解决方案

问题

pywebview 设置 frameless=True 后,窗口无边框无法移动。

解决方案

1. Python 后端(main.py

python 复制代码
import webview

class Api:
    """API 类,供前端调用"""
    
    def __init__(self):
        self._window = None  # ⚠️ 必须使用私有属性(下划线开头),避免 COM 错误
    
    def set_window(self, window):
        self._window = window
    
    def close_window(self):
        """关闭窗口"""
        if self._window:
            self._window.destroy()
    
    def minimize_window(self):
        """最小化窗口"""
        if self._window:
            self._window.minimize()

# 创建 API 实例
api = Api()
window = webview.create_window(
    title='窗口标题',
    url='./index.html',
    frameless=True,
    js_api=api  # 传入 API 对象
)
api.set_window(window)
webview.start()

2. HTML 前端

2.1 标题栏 HTML
html 复制代码
<div class="titlebar">
    <div class="titlebar-drag-region" id="titlebar-drag">
        <span class="titlebar-title">窗口标题</span>
    </div>
    <div class="titlebar-buttons">
        <div class="titlebar-btn minimize" onclick="minimizeWindow()">最小化</div>
        <div class="titlebar-btn close" onclick="closeWindow()">关闭</div>
    </div>
</div>
2.2 拖拽功能 JavaScript
javascript 复制代码
let initialX = 0;
let initialY = 0;

function onMouseMove(ev) {
    let x = ev.screenX - initialX;
    let y = ev.screenY - initialY;
    
    if (window.pywebview && typeof window.pywebview._jsApiCallback === 'function') {
        window.pywebview._jsApiCallback('pywebviewMoveWindow', [x, y], 'move');
    }
}

function onMouseUp() {
    window.removeEventListener('mousemove', onMouseMove);
    window.removeEventListener('mouseup', onMouseUp);
}

function onMouseDown(ev) {
    initialX = ev.clientX;
    initialY = ev.clientY;
    window.addEventListener('mouseup', onMouseUp);
    window.addEventListener('mousemove', onMouseMove);
}

// 关闭窗口
function closeWindow() {
    if (window.pywebview && window.pywebview.api) {
        window.pywebview.api.close_window();
    }
}

// 最小化窗口
function minimizeWindow() {
    if (window.pywebview && window.pywebview.api) {
        window.pywebview.api.minimize_window();
    }
}

// 初始化拖拽功能(延迟确保 pywebview API 就绪)
window.onload = function() {
    setTimeout(() => {
        const dragRegion = document.getElementById('titlebar-drag');
        if (dragRegion) {
            dragRegion.addEventListener('mousedown', onMouseDown);
        }
    }, 100);
};
2.3 标题栏样式(可选)
css 复制代码
.titlebar {
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 40px;
    background: rgba(0, 0, 0, 0.3);
    display: flex;
    justify-content: space-between;
    align-items: center;
    user-select: none;
    z-index: 1000;
}

.titlebar-drag-region {
    flex: 1;
    height: 100%;
    cursor: move;
}

.titlebar-buttons {
    display: flex;
    gap: 10px;
    padding-right: 10px;
}

.titlebar-btn {
    padding: 5px 15px;
    cursor: pointer;
}

核心原理

  1. 拖拽原理 :监听鼠标按下位置(相对坐标),计算鼠标移动后的屏幕位置(绝对坐标),调用 pywebview 内部 API pywebviewMoveWindow 移动窗口
  2. API 通信 :通过 js_api 参数将 Python 类暴露给前端 JavaScript
  3. 延迟初始化 :使用 setTimeout 确保 pywebview API 准备就绪后再绑定事件

注意事项

⚠️ 关键 :API 类中的 window 属性必须使用私有属性(_window),否则会触发 Windows COM 组件错误:

arduino 复制代码
System.InvalidCastException: 无法将类型为"System.__ComObject"的 COM 对象强制转换为接口类型"Accessibility.IAccessible"

正确self._window = None

错误self.window = None

相关推荐
陈年老古董18 分钟前
PyTorch 实现 MNIST 手写数字识别学习笔记
笔记·python·深度学习·学习
always_TT19 分钟前
【Python 字符串格式化:format() 方法】
android·开发语言·python
小义_23 分钟前
JDK 深度解析
java·linux·开发语言·python·面试
SendTomo26 分钟前
send.wang:基于浏览器WebRTC实现无客户端文件互传
网络·python·网络协议·webrtc·p2p
whcyhhh1 小时前
头歌实践教学平台:大数据存储2023(十四下答案)
大数据·数据库·python
Capricorn19881 小时前
Ox Alpha 1M 上下文科研引用失真怎么排查?知芽 Notebook Skill 技术链路实操
人工智能·笔记·python·深度学习·知识图谱·论文笔记
常山云栈1 小时前
如何理解python中的鸭子模(类)型?
开发语言·python
weixin199701080161 小时前
《alibaba.idle.isv.order.ship 接入实录:闲鱼订单发货回传的5个隐式约束》(附Python源码)
服务器·前端·python
y = xⁿ1 小时前
DeepSeek harness工具系统什么设计的?
开发语言·python
烂蜻蜓1 小时前
Flask入门教程(十五):错误处理与日志——打造健壮的Web应用
前端·python·flask