python --qt5(webview)/防多开/套壳网页/多次点击激活旧窗口

pyqtwebengine=5.12
PyQt5==5.12
class MyWindow(QMainWindow):def __init__(self):super(MyWindow, self).__init__()self.browser = QWebEngineView(self)  # 如果不写self则新生成一个窗口self.browser.setWindowTitle('技术领域占比分析')self.browser.setWindowIcon(QIcon(LOGO_PATH))self.browser.raise_()self.browser.setFixedSize(QSize(1200, 850))self.browser.move(0, 0)self.browser.setUrl(QUrl('https://www.taobao.com'))  # 网络连接# self.browser.load(QUrl.fromLocalFile('D:/1.htmml'))  # 本地h5self.browser.show()if __name__ == '__main__':app = QApplication(sys.argv)window = MyWindow()window.show()sys.exit(app.exec_())

webview套壳 防多开 多次点击激活旧窗口

文件结构如下:

在这里插入图片描述

依赖

loguru==0.6.0
pyinstaller
pywin32==306
PyQt5==5.12
pyqtwebengine==5.12
Pillow

config.ini

[Section1]
open_loadfile = 1
window_title = 鸿运兑奖系统
window_width = 1580
window_height = 800
prohibit_max_window = 0
window_max = 0
open_url = https://www.taobao.com
min_window_width = 1300
min_window_height = 700

settings.py

import osBASE_DIR = os.path.dirname(__file__)
STATIC_FILE = os.path.join(BASE_DIR, 'static')     # 静态资源路径
INDEX_FILE = os.path.join(STATIC_FILE, 'index.html')
CONFIG_PATH = os.path.join(BASE_DIR, 'config')     # 图标文件
LOGO_PATH = os.path.join(CONFIG_PATH, "logo.png")  #  图标路径
INI_PATH = os.path.join(CONFIG_PATH, "config.ini") # 配置文件

tools.py

import configparserclass MyINIFile:def __init__(self, filename):self.filename = filenameself.config = configparser.ConfigParser()self.config.read(self.filename)def read_value(self, section, key):try:return self.config.get(section, key)except configparser.Error as e:print(f"Error reading value: {e}")return Nonedef write_value(self, section, key, value):try:if not self.config.has_section(section):self.config.add_section(section)self.config.set(section, key, value)with open(self.filename, 'w') as configfile:self.config.write(configfile)except configparser.Error as e:print(f"Error writing value: {e}")def delete_value(self, section, key):try:if self.config.has_section(section) and self.config.has_option(section, key):self.config.remove_option(section, key)with open(self.filename, 'w') as configfile:self.config.write(configfile)else:print(f"Section '{section}' or option '{key}' does not exist.")except configparser.Error as e:print(f"Error deleting value: {e}")def update_value(self, section, key, value):try:if self.config.has_section(section) and self.config.has_option(section, key):self.config.set(section, key, value)with open(self.filename, 'w') as configfile:self.config.write(configfile)else:print(f"Section '{section}' or option '{key}' does not exist.")except configparser.Error as e:print(f"Error updating value: {e}")

ui.py

from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QMainWindow, QSystemTrayIcon, QMenu, QAction, \QApplicationfrom settings import LOGO_PATH, INDEX_FILE, INI_PATH
from tools import MyINIFileclass MyWindow(QMainWindow):def __init__(self):config = MyINIFile(INI_PATH)self.open_loadfile = config.read_value('Section1', 'open_loadfile')self._window_title = config.read_value('Section1', 'window_title')  # 窗口标题self._window_width = int(config.read_value('Section1', 'window_width'))# 窗口默认宽高self._window_height = int(config.read_value('Section1', 'window_height'))  # 窗口默认宽高self.prohibit_max_window = config.read_value('Section1', 'prohibit_max_window')  # 是否禁止最大化self.window_max = config.read_value('Section1', 'window_max')  # 是否默认最大化显示self.open_url = config.read_value('Section1', 'open_url')  # 网络链接self._min_window_width = int(config.read_value('Section1', 'min_window_width'))  # 最小窗口self._min_window_height = int(config.read_value('Section1', 'min_window_height'))super(MyWindow, self).__init__()self.setWindowTitle(self._window_title)  # 设置窗口标题self.setMinimumSize(self._min_window_width, self._min_window_height)self.resize(self._window_width, self._window_height)self.setWindowIcon(QIcon(LOGO_PATH))  # 设置窗口图标,icon.png 是您的图标文件路径if self.prohibit_max_window == '1':self.setWindowFlags(self.windowFlags() & ~Qt.WindowMaximizeButtonHint)  # 禁止最大化按钮if self.window_max == '1':self.showMaximized()  # 最大化窗口self.browser = QWebEngineView(self)  # 如果不写self则新生成一个窗口if self.open_loadfile == '1':self.browser.load(QUrl.fromLocalFile(INDEX_FILE))  # 本地h5else:self.browser.setUrl(QUrl(self.open_url))  #self.browser.show()def resizeEvent(self, event):# 设置 WebEngineView 的大小self.browser.resize(self.size())  # 使用窗口的大小super().resizeEvent(event)def tray(self):'''系统托盘'''# 创建系统托盘图标self.tray_icon = QSystemTrayIcon(self)self.tray_icon.setIcon(QIcon(LOGO_PATH))  # 替换为你的图标路径self.tray_icon.setToolTip(self._window_title)  # 这里设置鼠标悬浮时显示的文字self.tray_menu = QMenu()          # 创建右键菜单open_window_action = QAction("打开主界面", self)  # 添加退出动作exit_action = QAction("退出系统", self) # 添加退出动作self.tray_menu.addAction(open_window_action)  # 添加到菜单self.tray_menu.addAction(exit_action)open_window_action.triggered.connect(self.open_window_action)exit_action.triggered.connect(self.exit_app)        # 连接托盘图标的点击事件self.tray_icon.activated.connect(self.tray_icon_clicked)  # 图标左键被点击self.tray_icon.setContextMenu(self.tray_menu)  # 将菜单设置到托盘图标self.tray_icon.show()       # 显示托盘图标def tray_icon_clicked(self, reason):if reason == QSystemTrayIcon.Trigger:  # 单击托盘图标if self.isHidden():self.show()  # 显示窗口if self.isMinimized():self.showNormal()  # 还原窗口self.activateWindow()  # 激活窗口self.raise_()  # 确保窗口在最上层def open_window_action(self):'''打开主界面'''if self.isHidden():self.show()  # 显示窗口if self.isMinimized():self.showNormal()  # 还原窗口self.activateWindow()  # 激活窗口self.raise_()  # 确保窗口在最上层def exit_app(self):QApplication.quit()  # 退出应用def closeEvent(self, event):'''窗口被关闭事件'''event.ignore()self.hide()

main.py

import socket
import sys
from threading import Threadfrom PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtWidgets import QApplication
from loguru import logger
from ui import MyWindowclass Communicator(QObject):activate_signal = pyqtSignal()def check_if_running(port):"""检查端口是否被占用,意味着应用正在运行"""with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:try:s.bind(('127.0.0.1', port))return False  # 绑定成功,表示没有其他实例在运行except OSError:return True  # 绑定失败,表示端口被占用def activate_existing_instance(port):"""激活已运行的实例"""with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:s.sendto(b'activate', ('127.0.0.1', port))def start_server(port, comm):"""启动服务器以监听激活请求"""with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:s.bind(('127.0.0.1', port))logger.debug('启动成功')while True:data, addr = s.recvfrom(1024)if data == b'activate':logger.info("激活请求收到, 启动窗口")comm.activate_signal.emit()  # 发射信号以激活窗口if __name__ == '__main__':app = QApplication(sys.argv)port = 12345  # 选择一个未被占用的端口comm = Communicator()main_window = MyWindow()comm.activate_signal.connect(main_window.open_window_action)if check_if_running(port):activate_existing_instance(port)logger.error("应用已经在运行,激活窗口。")sys.exit(0)# 启动服务器监听激活请求server_thread = Thread(target=start_server, args=(port, comm))server_thread.daemon = Trueserver_thread.start()main_window.tray()# 创建并显示主窗口main_window.show()sys.exit(app.exec_())

pack.py

# coding=utf-8# @Time : 2023-08-17 02:04
# @Author : XiaoYi
# @Email: 1206154726@qq.com
import os
import shutil
from loguru import loggerdesktop_dist = os.path.join(os.path.join(os.path.expanduser("~"), 'Desktop'), 'dist')
desktop_main = os.path.join(desktop_dist, 'main')
# from urllib.parse import quote as url_quote   py3.8以上logger.debug(f'----------------------------开始构建程序--------------------------')
os.system('pyinstaller -w main.py -i logo.ico')  # 执行打包指令  pyinstaller -w main.py -i logo.ico 无调试窗口
logger.success(f'------->基础镜像结束,开始打包静态资源')shutil.move(os.path.join(os.getcwd(), 'dist'), desktop_dist)  # 移动文件到桌面
logger.debug(f'------->【dist】基础镜像结束')shutil.rmtree(os.path.join(os.getcwd(), 'build'))  # 删除打包构建文件
os.remove(os.path.join(os.getcwd(), 'main.spec'))  # 删除打包构建文件
logger.warning(f'------->【编译文件清除】清除结束')shutil.copytree(os.path.join(os.getcwd(), 'config'), os.path.join(desktop_main, 'config'))
shutil.copytree(os.path.join(os.getcwd(), 'static'), os.path.join(desktop_main, 'static'))
os.rename(os.path.join(desktop_main, 'main.exe'), os.path.join(desktop_main, 'taoke.exe'))  # 重命名打包后的文件os.rename(desktop_main, os.path.join(desktop_dist, 'taoke'))  # 重命名打包后的文件
logger.success(f'-------【打包结束】----------')

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/436386.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C0007.Clion中添加ui文件及运行的完整步骤

1.创建ui文件 选择Ui文件目录,右击,打开Qt Designer; 创建完成后,保存ui界面,并且命名为test.ui; 2.新建头文件test.h 在include目录中,新建头文件,文件名为test.h 3.新建test.cpp源文件

基于SpringBoot的休闲娱乐代理售票系统设计与实现

1.1研究背景 21世纪,我国早在上世纪就已普及互联网信息,互联网对人们生活中带来了无限的便利。像大部分的企事业单位都有自己的系统,由从今传统的管理模式向互联网发展,如今开发自己的系统是理所当然的。那么开发休闲娱乐代理售票…

Leetcode面试经典150题-322.零钱兑换

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。 你可以认为每种硬币的数量是无限的。 示…

Java项目实战II基于Java+Spring Boot+MySQL的大创管理系统(源码+数据库+文档)

目录 一、前言 二、技术介绍 三、系统实现 四、文档参考 五、核心代码 六、源码获取 全栈码农以及毕业设计实战开发,CSDN平台Java领域新星创作者 一、前言 在当前创新创业氛围浓厚的背景下,大学生创新创业项目(简称“大创”&#xff0…

【MySQL】-- 数据库基础

文章目录 1. 数据库简介1.1 什么是数据库1.2 什么是关系型数据库 2. 客户端与服务器的通讯方式2.1 CS架构 3. MySQL架构 1. 数据库简介 1.1 什么是数据库 什么是数据库? 组织和保存数据的应用程序。数据库和之前学的数据结构有什么关系? 数据结构是组织数…

第168天:应急响应-ELK 日志分析系统Yara规则样本识别特征提取规则编写

目录 案例一:ELK 搭建使用-导入文件&监控日志&语法筛选 案例二:Yara 规则使用-规则检测&分析特征&自写规则 案例一:ELK 搭建使用-导入文件&监控日志&语法筛选 该软件是专业分析日志的工具,但是不支持安…

Java应用程序的服务器有哪些?

1.Tomcat、Jetty 和 JBoss 区别? Apache Tomcat、Jetty 和 JBoss都是用于部署Java应用程序的服务器,它们都支持Servlet、JSP和其他Java EE(现在称为Jakarta EE)技术。尽管它们有一些相似的功能,但它们之间还是存在一些…

快速了解:MySQL InnoDB和MyISAM的区别

目录 一、序言二、InnoDB和MyISAM对比1、InnoDB特性支持如下2、MyISAM特性支持如下 三、两者核心区别1、事务支持2、锁机制3、索引结构4、缓存机制5、故障恢复6、使用场景 一、序言 在MySQL 8.0中,InnoDB是默认的存储引擎。除了InnoDB,MySQL还支持其它的…

小程序原生-利用setData()对不同类型的数据进行增删改

1. 声明和绑定数据 wxml文件 <view> {{school}} </view> <view>{{obj.name}}</view> <view id"{{id}}" > 绑定属性值 </view> <checkbox checked"{{isChecked}}"/> <!--算数运算--> <view>{{ id …

Python 课程20-Scikit-learn

前言 Scikit-learn 是 Python 中最流行的机器学习库之一&#xff0c;它提供了多种用于监督学习和无监督学习的算法。Scikit-learn 的特点是简单易用、模块化且具有高效的性能。无论是初学者还是专业开发者&#xff0c;都可以借助它进行快速原型设计和模型开发。 在本教程中&a…

栈与队列相关知识(二)

目录 Java中栈&#xff08;Stack&#xff09; 一. 常用方法 1.push(E item) 2.pop() 3.peek() 4.empty() 二. 常用方法扩展 1. search(Object o) 2. clone() 3. contains(Object o) 4. size() 5. toArray() Java中队列&#xff08;Queue&#xff09; 一.常用方法&…

android compose ScrollableTabRow indicator 指示器设置宽度

.requiredWidth(30.dp) Box(modifier Modifier.background(Color.LightGray).fillMaxWidth()) {ScrollableTabRow(selectedTabIndex selectedTabIndex, // 默认选中第一个标签containerColor ColorPageBg,edgePadding 1.dp, // 内容与边缘的距离indicator { tabPositions…

《OpenCV 计算机视觉》—— 图像拼接

还未写完&#xff01;&#xff01;&#xff01; 下面是两张需要拼接的图片 完整代码&#xff1a; import cv2 import numpy as np import sysdef cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)def detectAndDescribe(image):gray cv2.cvtColor(image, cv2.COLOR_…

C#测试调用Ghostscript.NET浏览PDF文件

Ghostscript.NET是针对Ghostscript的C#封装库&#xff0c;支持解析PostScript语言、操作PDF文件等。使用Ghostscript.NET的GhostscriptViewer 模块可以以图片形式查看PDF文档。本文学习并测试调用Ghostscript.NET模块打开及浏览PDF文件的基本用法。   Ghostscript.NET目前主要…

线性模型到神经网络

&#x1f680; 在初始神经网络那一节&#xff08;链接如下&#xff1a;初始神经网络&#xff09;的最后&#xff0c;我们通过加大考虑的天数使得我们最后得到的模型Loss最终停留在了0.32k&#xff0c;当我们在想让模型更加准确的时候&#xff0c;是做不到的&#xff0c;因为我们…

网站建设中常见的网站后台开发语言有哪几种,各自优缺点都是什么?

市场上常见的网站后台开发语言有PHP、Python、JavaScript、Ruby、Java和.NET等。这些语言各有其独特的优缺点&#xff0c;适用于不同的开发场景和需求。以下是对这些语言的具体介绍&#xff1a; PHP 优点&#xff1a;PHP是一种广泛用于Web开发的动态脚本语言&#xff0c;特别适…

python UNIT 3 选择与循环(2)

目录 1。循环的优化 经典优化分析&#xff1a; 未优化的代码&#xff1a; 细节分析&#xff1a; 优化后的代码&#xff1a; 优化的细节&#xff1a; 性能对比 优化的关键在于&#xff1a; 经典习题讲解&#xff1a;(紫色的解析请重点关注一下) 1。例三 个人代码解析…

Go实现RabbitMQ消息模式

【目标】 go实现RabbitMQ简单模式和work工作模式 go实现RabbitMQ 消息持久化和手动应答 go实现RabbitMQ 发布订阅模式 go使用MQ实现评论后排行榜更新 1. go实现简单模式 编写路由实现生产消息 实现生产消息 MQ消息执行为命令行执行&#xff0c;所以创建命令行执行函数mai…

机器学习-KNN分类算法

1.1 KNN分类 KNN分类算法&#xff08;K-Nearest-Neighbors Classification&#xff09;&#xff0c;又叫K近邻算法。它是概念极其简单&#xff0c;而效果又很优秀的分类算法。1967年由Cover T和Hart P提出。 KNN分类算法的核心思想&#xff1a;如果一个样本在特征空间中的k个最…

聊一聊 C#中有趣的 SourceGenerator生成器

一&#xff1a;背景 1. 讲故事 前些天在看 AOT的时候关注了下 源生成器&#xff0c;挺有意思的一个东西&#xff0c;今天写一篇文章简单的分享下。 二&#xff1a;源生成器探究之旅 1. 源生成器是什么 简单来说&#xff0c;源生成器是Roslyn编译器给程序员开的一道口子&am…