<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>透明桌面小人</title>
<!-- Tailwind CSS (使用生产环境兼容的CDN) -->
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@3.4.1/dist/tailwind.min.css" rel="stylesheet">
<!-- Font Awesome -->
<link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">
<!-- Spine Player -->
<script src="spine-player.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@esotericsoftware/spine-player@4.2.21/dist/spine-player.min.css">
<script>
tailwind.config = {
theme: {
extend: {
colors: {
primary: '#6366f1',
secondary: '#8b5cf6',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
}
}
}
}
</script>
<style type="text/tailwindcss">
@layer utilities {
.glass-effect {
background: rgba(255, 255, 255, 0.2);
backdrop-filter: blur(10px);
-webkit-backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.3);
}
.character-container {
cursor: move;
}
.emoji-button {
transition: all 0.2s ease;
}
.emoji-button:hover {
transform: scale(1.2);
}
.emoji-button.active {
border: 2px solid #6366f1;
box-shadow: 0 0 10px rgba(99, 102, 241, 0.5);
}
}
body {
margin: 0;
padding: 0;
background-color: rgba(0, 0, 0, 0);
overflow: hidden;
}
#character-container {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 400px;
z-index: 1000;
user-select: none;
}
#spine-container {
width: 100%;
height: 350px;
position: relative;
}
#controls {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
padding: 10px;
display: flex;
justify-content: center;
gap: 10px;
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(5px);
-webkit-backdrop-filter: blur(5px);
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.emoji-btn {
width: 40px;
height: 40px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
cursor: pointer;
background: rgba(255, 255, 255, 0.2);
border: none;
transition: all 0.2s ease;
}
.emoji-btn:hover {
transform: scale(1.2);
background: rgba(255, 255, 255, 0.3);
}
.emoji-btn.active {
background: rgba(99, 102, 241, 0.3);
border: 2px solid #6366f1;
}
#close-btn {
position: absolute;
top: 5px;
right: 5px;
width: 30px;
height: 30px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.2);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 10;
transition: all 0.2s ease;
}
#close-btn:hover {
background: rgba(255, 0, 0, 0.3);
}
</style>
</head>
<body>
<div id="character-container">
<div id="close-btn">
<i class="fa fa-times" aria-hidden="true"></i>
</div>
<div id="spine-container"></div>
<div id="controls">
<button class="emoji-btn active" data-emoji="emoji_0">😊</button>
<button class="emoji-btn" data-emoji="emoji_1">😂</button>
<button class="emoji-btn" data-emoji="emoji_2">😍</button>
<button class="emoji-btn" data-emoji="emoji_3">😢</button>
<button class="emoji-btn" data-emoji="emoji_4">😡</button>
</div>
</div>
<script>
// 浏览器兼容性检查
function checkBrowserCompatibility() {
// 检测浏览器类型和版本
const browserInfo = getBrowserInfo();
// 检查WebGL支持
function isWebGLSupported() {
try {
const canvas = document.createElement('canvas');
return !!(window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')));
} catch (e) {
return false;
}
}
// 检查backdrop-filter支持
function checkBackdropFilterSupport() {
if (typeof CSS !== 'undefined' && typeof CSS.supports !== 'undefined') {
return CSS.supports('backdrop-filter', 'blur(10px)') ||
CSS.supports('-webkit-backdrop-filter', 'blur(10px)');
}
return false;
}
// 检查必要的API支持
const requiredAPIs = {
'requestAnimationFrame': typeof window.requestAnimationFrame !== 'undefined',
'WebGL': isWebGLSupported(),
'Canvas': typeof HTMLCanvasElement !== 'undefined',
'TypedArrays': typeof Uint8Array !== 'undefined',
'backdrop-filter': checkBackdropFilterSupport()
};
// 检查是否所有必要API都支持
const allSupported = Object.values(requiredAPIs).every(val => val);
// 针对Edge浏览器的特定检查和处理
if (browserInfo.name === 'Edge') {
console.log(`检测到Edge浏览器,版本: ${browserInfo.version}`);
// Edge特定的兼容性处理
handleEdgeSpecificIssues(browserInfo.version);
// 如果是Edge浏览器,即使WebGL检测失败,也尝试继续
if (!requiredAPIs.WebGL) {
console.warn('Edge浏览器中WebGL检测失败,尝试使用软件渲染');
// 在Edge中,即使WebGL检测失败,也尝试初始化
requiredAPIs.WebGL = true; // 标记为支持,以便继续
}
}
if (!allSupported) {
console.warn('浏览器兼容性问题:', requiredAPIs);
// 显示兼容性警告
const warningDiv = document.createElement('div');
warningDiv.className = 'fixed top-0 left-0 w-full bg-red-500 text-white z-50 flex items-center justify-center';
warningDiv.innerHTML = `
<div class="p-4 max-w-md">
<h3 class="text-xl font-bold mb-2">浏览器兼容性问题</h3>
<p>您的浏览器可能不支持某些功能,应用可能无法正常工作。</p>
<p class="mt-2">建议使用最新版本的Chrome、Firefox、Edge或Safari浏览器。</p>
${browserInfo.name === 'Edge' ? `
<p class="mt-2 text-yellow-200">Edge浏览器提示:</p>
<ul class="mt-1 list-disc list-inside text-sm text-yellow-200">
<li>确保已启用硬件加速</li>
<li>更新显卡驱动程序</li>
<li>尝试重启浏览器</li>
</ul>
` : ''}
<button id="close-warning" class="mt-4 px-4 py-2 bg-white text-red-500 rounded-full">关闭</button>
</div>
`;
document.body.appendChild(warningDiv);
// 关闭警告按钮
document.getElementById('close-warning').addEventListener('click', () => {
warningDiv.remove();
});
}
return true; // 即使有兼容性问题,也尝试继续运行
}
// 获取浏览器信息
function getBrowserInfo() {
const userAgent = navigator.userAgent;
let browserName = '未知浏览器';
let browserVersion = '未知版本';
// 检测浏览器类型
if (userAgent.includes('Chrome')) {
browserName = 'Chrome';
browserVersion = userAgent.match(/Chrome\/(\d+)/)[1];
} else if (userAgent.includes('Firefox')) {
browserName = 'Firefox';
browserVersion = userAgent.match(/Firefox\/(\d+)/)[1];
} else if (userAgent.includes('Safari')) {
browserName = 'Safari';
browserVersion = userAgent.match(/Version\/(\d+)/)[1];
} else if (userAgent.includes('Edge')) {
browserName = 'Edge';
browserVersion = userAgent.match(/Edge\/(\d+)/) ? userAgent.match(/Edge\/(\d+)/)[1] :
(userAgent.match(/Edg\/(\d+)/) ? userAgent.match(/Edg\/(\d+)/)[1] : '未知');
} else if (userAgent.includes('Opera') || userAgent.includes('OPR')) {
browserName = 'Opera';
browserVersion = userAgent.match(/(Opera|OPR)\/(\d+)/)[2];
}
return { name: browserName, version: browserVersion };
}
// 处理Edge特定问题
function handleEdgeSpecificIssues(version) {
const edgeVersion = parseInt(version);
// Edge旧版本处理
if (edgeVersion < 79) {
console.warn('检测到旧版本Edge浏览器,可能存在兼容性问题');
// 为旧版本Edge添加backdrop-filter回退样式
addEdgeBackdropFilterFallback();
}
// 修复Edge中的WebGL问题
fixEdgeWebGLIssues();
}
// 为旧版本版本Edge添加backdrop-filter回退样式
function addEdgeBackdropFilterFallback() {
const style = document.createElement('style');
style.textContent = `
/* Edge旧版本backdrop-filter回退样式 */
.glass-effect,
#controls,
#close-btn {
background: rgba(255, 255, 255, 0.3) !important;
}
`;
document.head.appendChild(style);
}
// 修复Edge WebGL问题
function fixEdgeWebGLIssues() {
// Edge中WebGL上下文获取可能问题的修复
const originalGetContext = HTMLCanvasElement.prototype.getContext;
HTMLCanvasElement.prototype.getContext = function(contextId, options) {
try {
// 尝试获取WebGL上下文
const context = originalGetContext.call(this, contextId, options);
if (context) {
return context;
}
// 如果失败,尝试使用experimental-webgl
if (contextId === 'webgl') {
console.log('尝试使用experimental-webgl');
return originalGetContext.call(this, 'experimental-webgl', options);
}
} catch (error) {
console.error('获取WebGL上下文失败:', error);
// 在Edge中,尝试使用不同的参数
if (contextId === 'webgl' || contextId === 'experimental-webgl') {
try {
console.log('尝试使用简化参数获取WebGL上下文');
return originalGetContext.call(this, contextId, {
alpha: true,
antialias: false,
depth: false,
stencil: false,
preserveDrawingBuffer: true
});
} catch (error2) {
console.error('使用简化参数获取WebGL上下文也失败:', error2);
}
}
}
return null;
};
console.log('Edge WebGL修复已应用');
}
// 全局变量
let player;
let isDragging = false;
let offsetX, offsetY;
let currentEmoji = 'emoji_0';
let animationFrameId = null;
// DOM元素
const characterContainer = document.getElementById('character-container');
const spineContainer = document.getElementById('spine-container');
const closeBtn = document.getElementById('close-btn');
const emojiBtns = document.querySelectorAll('.emoji-btn');
// 初始化Spine动画
function initSpine() {
try {
// 获取浏览器信息
const browserInfo = getBrowserInfo();
// 创建Spine播放器配置
const playerConfig = {
jsonUrl: "assets/1310.json",
atlasUrl: "assets/1310.atlas",
alpha: true,
backgroundColor: "#00000000",
preserveDrawingBuffer: true,
showLoading: false,
showControls: false,
animation: "idle",
success: function(player) {
console.log("Spine动画加载成功");
// 默认显示第一个表情
setEmoji(currentEmoji);
// 启动动画循环
startAnimationLoop();
},
error: function(reason) {
console.error("Spine动画加载失败:", reason);
// 显示错误信息
showError(`动画加载失败: ${reason.message || reason}`);
// 回退到简单的表情显示
fallbackToSimpleEmoji();
},
viewport: {
padLeft: "0%",
padRight: "0%",
padTop: "0%",
padBottom: "0%"
}
};
// Edge特定配置
if (browserInfo.name === 'Edge') {
console.log('为Edge浏览器应用特定配置');
// 在Edge中使用更简单的配置
playerConfig.preserveDrawingBuffer = true;
playerConfig.alpha = true;
// 为Edge添加额外的错误处理
const originalErrorHandler = playerConfig.error;
playerConfig.error = function(reason) {
console.error("Edge中Spine动画加载失败:", reason);
// Edge特定的错误处理
if (reason.message && reason.message.includes('WebGL')) {
showError(`WebGL错误: ${reason.message}<br>在Edge中,您可能需要启用硬件加速或更新显卡驱动。`);
} else {
showError(`动画加载失败: ${reason.message || reason}`);
}
// 回退到简单的表情显示
fallbackToSimpleEmoji();
// 调用原始错误处理
if (originalErrorHandler) originalErrorHandler(reason);
};
}
// 创建Spine播放器
player = new spine.SpinePlayer("spine-container", playerConfig);
} catch (error) {
console.error("Spine初始化异常:", error);
// 获取浏览器信息
const browserInfo = getBrowserInfo();
if (browserInfo.name === 'Edge' && error.message.includes('WebGL')) {
showError(`初始化失败: ${error.message}<br>在Edge中,您可能需要启用硬件加速或更新显卡驱动。`);
} else {
showError(`初始化失败: ${error.message}`);
}
fallbackToSimpleEmoji();
}
}
// 显示错误信息
function showError(message) {
const errorDiv = document.createElement('div');
errorDiv.className = 'absolute inset-0 bg-red-900 bg-opacity-80 text-white flex flex-col items-center justify-center p-4 z-10';
errorDiv.innerHTML = `
<h3 class="text-xl font-bold mb-2">加载错误</h3>
<p class="text-center mb-4">${message}</p>
<p class="text-sm text-gray-300">请尝试检查Spine资源文件是否存在或格式是否正确</p>
`;
document.getElementById('spine-container').appendChild(errorDiv);
}
// 回退到简单的表情显示
function fallbackToSimpleEmoji() {
const container = document.getElementById('spine-container');
container.innerHTML = '';
const emojiDiv = document.createElement('div');
emojiDiv.id = 'fallback-emoji';
emojiDiv.className = 'w-full h-full flex items-center justify-center text-6xl';
emojiDiv.textContent = '😊';
container.appendChild(emojiDiv);
// 更新表情的函数
window.setFallbackEmoji = function(emojiName) {
const emojiMap = {
'emoji_0': '😊',
'emoji_1': '😂',
'emoji_2': '😍',
'emoji_3': '😢',
'emoji_4': '😡'
};
emojiDiv.textContent = emojiMap[emojiName] || '😊';
};
console.log("已回退到简单表情模式");
}
// 动画循环
function startAnimationLoop() {
let lastTime = 0;
function animate(currentTime) {
if (!lastTime) lastTime = currentTime;
const delta = (currentTime - lastTime) / 1000; // 转换为秒
lastTime = currentTime;
if (player && player.update) {
try {
player.update(delta);
} catch (error) {
console.error("动画更新错误:", error);
}
}
animationFrameId = requestAnimationFrame(animate);
}
// 停止之前的动画循环
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
animationFrameId = requestAnimationFrame(animate);
}
// 设置表情
function setEmoji(emojiName) {
currentEmoji = emojiName;
// 更新按钮状态
emojiBtns.forEach(btn => {
if (btn.dataset.emoji === emojiName) {
btn.classList.add('active');
} else {
btn.classList.remove('active');
}
});
// 检查是否在回退模式
if (window.setFallbackEmoji) {
window.setFallbackEmoji(emojiName);
return;
}
if (!player) return;
try {
// 在Spine中设置表情
// 这里假设Spine动画中有对应的皮肤或附件来切换表情
// 如果是通过皮肤切换
if (player.skeleton && player.skeleton.data && player.skeleton.data.findSkin) {
if (player.skeleton.data.findSkin(emojiName)) {
player.skeleton.setSkin(emojiName);
player.skeleton.setToSetupPose();
if (player.update) player.update(0);
return;
}
}
// 如果是通过附件切换
if (player.skeleton && player.skeleton.findSlot) {
const slot = player.skeleton.findSlot("face");
if (slot && player.skeleton.getAttachment) {
const attachment = player.skeleton.getAttachment(slot.index, emojiName);
if (attachment) {
slot.setAttachment(attachment);
if (player.update) player.update(0);
return;
}
}
}
// 如果是通过动画切换
if (player.animationState && player.animationState.data && player.animationState.data.findAnimation) {
if (player.animationState.data.findAnimation(emojiName)) {
player.animationState.setAnimation(0, emojiName, false);
// 播放完表情动画后回到idle
if (player.animationState.data.findAnimation("idle")) {
player.animationState.addAnimation(0, "idle", true, 0);
}
return;
}
}
console.warn(`未找到表情: ${emojiName}`);
} catch (error) {
console.error("设置表情错误:", error);
}
}
// 窗口拖动功能
function initDrag() {
characterContainer.addEventListener('mousedown', startDrag);
characterContainer.addEventListener('touchstart', startDrag, { passive: false });
function startDrag(e) {
// 忽略控件区域的拖动
if (e.target.closest('#controls') || e.target.closest('#close-btn')) {
return;
}
isDragging = true;
if (e.type === 'mousedown') {
offsetX = e.clientX - characterContainer.getBoundingClientRect().left;
offsetY = e.clientY - characterContainer.getBoundingClientRect().top;
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stopDrag);
} else {
offsetX = e.touches[0].clientX - characterContainer.getBoundingClientRect().left;
offsetY = e.touches[0].clientY - characterContainer.getBoundingClientRect().top;
document.addEventListener('touchmove', drag, { passive: false });
document.addEventListener('touchend', stopDrag);
}
e.preventDefault();
}
function drag(e) {
if (!isDragging) return;
let clientX, clientY;
if (e.type === 'mousemove') {
clientX = e.clientX;
clientY = e.clientY;
} else {
clientX = e.touches[0].clientX;
clientY = e.touches[0].clientY;
e.preventDefault(); // 防止滚动
}
const x = clientX - offsetX;
const y = clientY - offsetY;
// 限制在屏幕范围内
const maxX = window.innerWidth - characterContainer.offsetWidth;
const maxY = window.innerHeight - characterContainer.offsetHeight;
const boundedX = Math.max(0, Math.min(x, maxX));
const boundedY = Math.max(0, Math.min(y, maxY));
characterContainer.style.left = `${boundedX}px`;
characterContainer.style.top = `${boundedY}px`;
}
function stopDrag() {
isDragging = false;
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stopDrag);
document.removeEventListener('touchmove', drag);
document.removeEventListener('touchend', stopDrag);
}
}
// 初始化关闭按钮
function initCloseBtn() {
closeBtn.addEventListener('click', () => {
// 在Electron环境中关闭窗口
if (window.electron) {
window.electron.closeWindow();
} else {
// 在浏览器中隐藏
characterContainer.style.display = 'none';
console.log('窗口已关闭');
}
});
}
// 初始化表情按钮
function initEmojiBtns() {
emojiBtns.forEach(btn => {
btn.addEventListener('click', () => {
setEmoji(btn.dataset.emoji);
});
});
}
// 窗口大小调整
function initResize() {
// 简单的缩放功能,通过滚轮缩放角色大小
characterContainer.addEventListener('wheel', (e) => {
e.preventDefault();
const currentWidth = characterContainer.offsetWidth;
const currentHeight = characterContainer.offsetHeight;
// 缩放因子
const scaleFactor = e.deltaY > 0 ? 0.9 : 1.1;
const newWidth = Math.max(100, Math.min(currentWidth * scaleFactor, 500));
const newHeight = Math.max(150, Math.min(currentHeight * scaleFactor, 700));
characterContainer.style.width = `${newWidth}px`;
characterContainer.style.height = `${newHeight}px`;
// 调整Spine容器高度
const spineHeight = newHeight - 60; // 减去控制栏高度
document.getElementById('spine-container').style.height = `${spineHeight}px`;
// 如果播放器已初始化,重新调整大小
if (player && player.resize) {
player.resize();
}
});
}
// 初始化
document.addEventListener('DOMContentLoaded', () => {
// 获取浏览器信息
const browserInfo = getBrowserInfo();
console.log(`当前浏览器: ${browserInfo.name} ${browserInfo.version}`);
// 检查浏览器兼容性
const isCompatible = checkBrowserCompatibility();
// 为Edge浏览器添加特定样式
if (browserInfo.name === 'Edge') {
document.body.classList.add('edge-browser');
// 添加Edge特定的CSS样式
const edgeStyle = document.createElement('style');
edgeStyle.textContent = `
/* Edge浏览器特定样式 */
.edge-browser #controls,
.edge-browser #close-btn {
-webkit-backdrop-filter: blur(10px);
backdrop-filter: blur(10px);
}
/* Edge中可能需要调整z-index */
.edge-browser #character-container {
z-index: 2147483647;
}
`;
document.head.appendChild(edgeStyle);
}
// 初始化Spine
initSpine();
// 初始化其他功能
initDrag();
initCloseBtn();
initEmojiBtns();
initResize();
// 随机位置初始化
const randomX = Math.floor(Math.random() * (window.innerWidth - 300));
const randomY = Math.floor(Math.random() * (window.innerHeight - 400));
characterContainer.style.left = `${randomX}px`;
characterContainer.style.top = `${randomY}px`;
});
// 页面卸载时清理
window.addEventListener('beforeunload', () => {
if (animationFrameId) {
cancelAnimationFrame(animationFrameId);
}
});
// 与Electron主进程通信
if (window.electron) {
// 接收主进程的消息
window.electron.receive('update-emoji', (emoji) => {
setEmoji(emoji);
});
window.electron.receive('update-position', (x, y) => {
characterContainer.style.left = `${x}px`;
characterContainer.style.top = `${y}px`;
});
}
</script>
</body>
</html>
import sys
import os
import json
from pathlib import Path
from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import Qt, QUrl, QPoint, pyqtSlot
from PyQt5.QtGui import QRegion, QPixmap, QPainter, QColor
class TransparentWindow(QMainWindow):
def __init__(self):
super().__init__()
# 初始化窗口设置
self.init_window()
# 初始化Web视图
self.init_web_view()
# 加载配置
self.load_config()
# 设置窗口位置
self.set_initial_position()
def init_window(self):
# 设置窗口标志
self.setWindowFlags(
Qt.FramelessWindowHint |
Qt.WindowStaysOnTopHint |
Qt.SubWindow
)
# 设置窗口透明
self.setAttribute(Qt.WA_TranslucentBackground)
self.setAttribute(Qt.WA_NoSystemBackground, False)
# 设置窗口大小
self.setFixedSize(300, 400)
# 创建中心部件
self.central_widget = QWidget()
self.setCentralWidget(self.central_widget)
self.layout = QVBoxLayout(self.central_widget)
self.layout.setContentsMargins(0, 0, 0, 0)
def init_web_view(self):
# 创建WebEngineView
self.web_view = QWebEngineView()
# 设置Web通道用于与JavaScript通信
from PyQt5.QtWebChannel import QWebChannel
self.channel = QWebChannel()
self.channel.registerObject("backend", self)
self.web_view.page().setWebChannel(self.channel)
# 设置WebEngine设置
settings = self.web_view.settings()
settings.setAttribute(settings.JavascriptEnabled, True)
settings.setAttribute(settings.LocalContentCanAccessRemoteUrls, True)
settings.setAttribute(settings.LocalContentCanAccessFileUrls, True)
# 添加到布局
self.layout.addWidget(self.web_view)
# 加载HTML文件
html_path = Path(__file__).parent / "desktop-character.html"
self.web_view.load(QUrl.fromLocalFile(str(html_path)))
def load_config(self):
# 加载配置文件
config_path = Path(__file__).parent / "config.json"
if config_path.exists():
with open(config_path, 'r', encoding='utf-8') as f:
self.config = json.load(f)
else:
self.config = {
"position": {"x": 100, "y": 100},
"emoji": "emoji_0",
"size": {"width": 300, "height": 400}
}
def save_config(self):
# 保存配置文件
config_path = Path(__file__).parent / "config.json"
with open(config_path, 'w', encoding='utf-8') as f:
json.dump(self.config, f, ensure_ascii=False, indent=2)
def set_initial_position(self):
# 设置初始位置
x = self.config.get("position", {}).get("x", 100)
y = self.config.get("position", {}).get("y", 100)
self.move(x, y)
@pyqtSlot()
def closeWindow(self):
# 保存当前位置
pos = self.pos()
self.config["position"] = {"x": pos.x(), "y": pos.y()}
self.save_config()
# 关闭窗口
self.close()
@pyqtSlot(str)
def updateEmoji(self, emoji):
# 更新表情配置
self.config["emoji"] = emoji
self.save_config()
def mousePressEvent(self, event):
# 记录鼠标按下时的位置
if event.button() == Qt.LeftButton:
self.drag_position = event.globalPos() - self.frameGeometry().topLeft()
event.accept()
def mouseMoveEvent(self, event):
# 拖动窗口
if event.buttons() == Qt.LeftButton:
self.move(event.globalPos() - self.drag_position)
event.accept()
def mouseReleaseEvent(self, event):
# 保存位置
if event.button() == Qt.LeftButton:
pos = self.pos()
self.config["position"] = {"x": pos.x(), "y": pos.y()}
self.save_config()
def main():
# 设置环境变量以支持透明背景
os.environ["QTWEBENGINE_CHROMIUM_FLAGS"] = "--enable-transparent-visuals --disable-gpu"
app = QApplication(sys.argv)
# 设置应用程序样式
app.setStyleSheet("""
QMainWindow {
background: transparent;
}
QWebEngineView {
background: transparent;
}
""")
window = TransparentWindow()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
浏览器兼容性问题
您的浏览器可能不支持某些功能,应用可能无法正常工作。
建议使用最新版本的Chrome、Firefox、Edge或Safari浏览器。