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

相关推荐
Learn-Python4 小时前
MongoDB-only方法
python·sql
小途软件5 小时前
用于机器人电池电量预测的Sarsa强化学习混合集成方法
java·人工智能·pytorch·python·深度学习·语言模型
扫地的小何尚5 小时前
NVIDIA RTX PC开源AI工具升级:加速LLM和扩散模型的性能革命
人工智能·python·算法·开源·nvidia·1024程序员节
wanglei2007085 小时前
生产者消费者
开发语言·python
清水白石0086 小时前
《从零到进阶:Pydantic v1 与 v2 的核心差异与零成本校验实现原理》
数据库·python
昵称已被吞噬~‘(*@﹏@*)’~6 小时前
【RL+空战】学习记录03:基于JSBSim构造简易空空导弹模型,并结合python接口调用测试
开发语言·人工智能·python·学习·深度强化学习·jsbsim·空战
2501_941877986 小时前
从配置热更新到运行时自适应的互联网工程语法演进与多语言实践随笔分享
开发语言·前端·python
酩酊仙人6 小时前
fastmcp构建mcp server和client
python·ai·mcp
且去填词7 小时前
DeepSeek API 深度解析:从流式输出、Function Calling 到构建拥有“手脚”的 AI 应用
人工智能·python·语言模型·llm·agent·deepseek
rgeshfgreh7 小时前
Python条件与循环实战指南
python