CN112487340A - 一种极速简约防盗Linux全屏浏览器的创新技术 - Google Patents
一种极速简约防盗Linux全屏浏览器的创新技术 Download PDFInfo
- Publication number
- CN112487340A CN112487340A CN202011531684.XA CN202011531684A CN112487340A CN 112487340 A CN112487340 A CN 112487340A CN 202011531684 A CN202011531684 A CN 202011531684A CN 112487340 A CN112487340 A CN 112487340A
- Authority
- CN
- China
- Prior art keywords
- self
- bookmark
- full
- browser
- screen
- Prior art date
- Legal status (The legal status is an assumption and is not a legal conclusion. Google has not performed a legal analysis and makes no representation as to the accuracy of the status listed.)
- Pending
Links
Images
Classifications
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F16/00—Information retrieval; Database structures therefor; File system structures therefor
- G06F16/90—Details of database functions independent of the retrieved data types
- G06F16/95—Retrieval from the web
- G06F16/958—Organisation or management of web site content, e.g. publishing, maintaining pages or automatic linking
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F21/00—Security arrangements for protecting computers, components thereof, programs or data against unauthorised activity
- G06F21/50—Monitoring users, programs or devices to maintain the integrity of platforms, e.g. of processors, firmware or operating systems
- G06F21/57—Certifying or maintaining trusted computer platforms, e.g. secure boots or power-downs, version controls, system software checks, secure updates or assessing vulnerabilities
- G06F21/577—Assessing vulnerabilities and evaluating computer system security
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F8/00—Arrangements for software engineering
- G06F8/30—Creation or generation of source code
- G06F8/38—Creation or generation of source code for implementing user interfaces
-
- G—PHYSICS
- G06—COMPUTING; CALCULATING OR COUNTING
- G06F—ELECTRIC DIGITAL DATA PROCESSING
- G06F9/00—Arrangements for program control, e.g. control units
- G06F9/06—Arrangements for program control, e.g. control units using stored programs, i.e. using an internal store of processing equipment to receive or retain programs
- G06F9/44—Arrangements for executing specific programs
- G06F9/451—Execution arrangements for user interfaces
Landscapes
- Engineering & Computer Science (AREA)
- Theoretical Computer Science (AREA)
- General Engineering & Computer Science (AREA)
- Software Systems (AREA)
- Physics & Mathematics (AREA)
- General Physics & Mathematics (AREA)
- Computer Hardware Design (AREA)
- Computer Security & Cryptography (AREA)
- Databases & Information Systems (AREA)
- Human Computer Interaction (AREA)
- Data Mining & Analysis (AREA)
- Computing Systems (AREA)
- Information Transfer Between Computers (AREA)
Abstract
一种极速简约防盗Linux全屏浏览器的创新技术,专业级浏览器拥有近百种功能,消耗大量硬件资源,还有两大弊端:1、非默认全屏显示,按F11功能键切换全屏,不方便;2、企业员工上网容易外传资料造成泄密;迫切需要一种简洁快速且防盗的全屏浏览器,同时提供全屏享受。本发明人在Linux系统上,采用Python、PyQt5和QtWebEngine,发明了极速简约防盗的全屏浏览器,省略主菜单和功能按钮,保留鼠标右击菜单;网站相同文字和图片二次打开时间不超过1秒;功能:默认全屏显示所有网页、书签管理、窗口缩放、音视频播放、下载、关闭最后窗口即关机和屏蔽操作系统入口,达到防盗效果,集成文档、截图、绘图、打印和网络与音量设置。
Description
技术领域
极速简约防盗Linux全屏浏览器。
背景技术
1994 年,网景公司推出世界上第一款浏览器,距今 26 年。目前专业浏览器有:谷歌、360、火狐、IE、Edge 和 QQ 等,它们的功能齐全,消耗大量内存和CPU资源,拥有多达近百种功能,涵盖:网页基本操作、系统设置、插件和安全设置,其中:插件和安全设置极少使用,而系统设置偶尔使用,常用的功能是:鼠标滚轮上下移动浏览网页、点击超链接打开新网页、前进、后退、刷新、保存图片等网页基本操作。专业浏览器除了功能繁琐外还有两大弊端:1、非默认全屏显示,需按不常用的F11功能键切换全屏显示,既不方便,也不普及;2、企业员工上网容易外传客户和技术资料造成泄密。因此,针对企业防盗上网需求、普通大众简单上网需求和全屏视觉享受,迫切需要推出一种功能简洁、浏览快速且防盗的全屏浏览器。开发浏览器的语言从最初的C/C++逐步转向 Python,因为Python有最庞大的第三方生态圈。PyQt开发商是英国的Riverbank Computing 公司,该公司使用了芬兰 Digia 公司的Qt 图形界面开发模块。PyQt 是Qt和Python结合的产物,是为了将 Qt 的功能用于 Python开发的包装器。PyQt5是 5.x版本,PyQt5由三大软件模块组成:PyQt5-sip、PyQt5 和PyQt5-tools,PyQt5-sip 是Python生成C++接口代码的工具,能实现标准Python和C/C++数据类型之间自动转换;PyQt5 提供支持Qt5各个类的Python模块,放在Python目录下的Lib\site-packages\PyQt5 目录;PyQt5-tools提供 Qtdesigner 供设计UI界面。Qt 是一个跨平台的 C++图形界面程序框架;Qt5是Qt的第5版本。Qt被分成八个模块:1. QtCore 模块包含核心的非GUI 功能;2. QtGui 模块包含图形组件和相关的类;3. QtNetwork 模块包含了网络编程的类;4. QtXml包含使用XML文件的类;5. QtSvg模块提供可缩放矢量图形;6. QtOpenGL 模块使用OpenGL 库渲染3D和2D图形;7. QtSql 模块提供数据库接口的类;8. QtWebEngine 模块提供了一个简易web浏览器内核, 它可较容易地把 Web 内容嵌入到 Qt 应用程序中。Qt WebEngine架构见图 1.
Qt WebEngine的功能分成下列模块:
Qt WebEngine Widgets 模块(见图 2):用于创建基于Widget的web应用.
Qt WebEngine模块:用于创建基于Qt Quick的web应用.
Qt WebEngine Core 模块:与Chromium内核交互.
备注:Qt WebEngine Core 基于Chromium, 但没有包含或使用任何Chrome浏览器的其它服务和插件,可在Chromium项目源代码库查看Chromium和Chrome 的区别。QtWebEngine Process 是一个单独的可执行程序,用于呈现网页和执行 JavaScript,这样可缓解安全问题并隔离由特定内容引起的崩溃。一个QWebEngineView实例有一个QWebEnginePage,每一个QWebEnginePage都属于一个QWebEngineProfile,QWebEngineProfile有一个页面设置的QWebEngineSettings。应用程序可使用URL和HTML字符串加载页面到WebEngineView。Qt WebEngine将Chromium的Web功能集成到Qt中,其最新版本基于Chromium 73。
发明内容
本发明人在与99%超级计算机一致的Linux操作系统上(基于CentOS 7.7版),采用最流行的Python 3.7版语言、 PyQt5 和 PyQtWebEngine开发包,发明了极速简约防盗Linux全屏浏览器(简称:防盗全屏浏览器)。它的特点是:程序精炼、速度快、界面简洁、防盗和默认全屏显示所有网页,常用网站相同文字和图片二次打开时间不超过 1 秒,大约0.1秒,有更新的大图片加载略滞后1~2秒。功能有:以著名导航页hao123.com作为默认首页,默认全屏显示所有网页(见图 3和图 4),按Esc键或空格键或Alt键可随时切换全屏显示或多页签浏览窗口;按小键盘-减号或鼠标右击菜单的“关闭”功能即可关闭页面;正常输入框输入内容自动退出全屏模式,打开超链接或右击鼠标或关闭当前页就自动进入全屏模式,具备自动全屏模式的特点;可播放音视频和支持文件下载,但不支持需要证书的不常用功能,如:网银转账(正在被手机扫码支付替代),目的是优先提高运行速度。主窗口总是以最大化显示,关闭主窗口或最后一个页面就直接关机,不让使用者接触操作系统桌面和敏感目录,达到保证资料防盗的目的,面向企业防盗上网需求和大众化用户群体。防盗全屏浏览器保留的多页签窗口界面省略了主菜单和功能按钮(见图 5) ,并以最大化窗口展示,只能关闭主窗口,不能缩放;只提供网页鼠标右击菜单功能(见图 6、图 7和图8)。多页签窗口界面自上而下仅有五部分组成:主窗口标题(浏览器名称)、呈梯形状的多个页签头部、地址栏、网页显示窗口和状态栏。网页文字默认以四号字显示,可以缩放字号。地址栏提示的内容是:双击鼠标清除地址栏,滚轮上滑可还原,实现了与地址栏提示一致的功能。鼠标右击菜单全部是自定义的常用中文菜单,不常用的功能都被省略,如:前进与后退被浏览足迹代替,停止、撤销和重做被省略。右击网页空白处的主菜单功能是:关闭、我的书签、浏览足迹、收藏书签、刷新、时钟、打开下载文件夹、工具箱子菜单、窗口缩放子菜单、书签管理子菜单和hahayaya极速简约防盗Linux全屏浏览器的介绍。工具箱子菜单的功能有:简易文档处理、截图、绘图、打印机设置和网络音量设置(见图6)。窗口缩放子菜单的功能有:拉近、拉远和重置(见图7)。书签管理子菜单的功能有:书签导出和书签导入(见图8)。用户点击“我的书签”或“浏览足迹”主功能后,系统自动弹出书签窗口(见图9)或浏览足迹窗口(见图10),并自动把光标移到书签窗口或浏览足迹窗口的第一行,方便操作,点击书签或浏览过的网址就直接全屏显示;右击任一个书签可选择删除。点击主菜单的“收藏书签”会把新书签置顶,最新浏览过的书签也会置顶;浏览足迹中的网址按时间优先排列,最近的排在最前面。还为文件下载进度条添加鼠标右击子菜单:启动、打开下载文件夹、取消和删除。防盗全屏浏览器无论全屏显示,还是多页签窗口显示,关闭主窗口或最后一个页面就直接关机,满足防盗需要;须重写QMainWindow 类,修改 closeEvent 方法,调用 Linux系统命令 poweroff -h关闭主机;并屏蔽操作系统入口(参考本发明人的另一个发明专利申请“一种程序预装且屏蔽操作系统入口的应用软件加密技术”,申请号是:2020111821638)。采用单独的固态硬盘安装Linux操作系统和防盗全屏浏览器软件,连接电脑USB口,开机自启动浏览器,与主硬盘的Windows操作系统或其他操作系统严格隔离,才能达到允许上网且保证资料防盗的目的。极速简约全屏浏览器能推动网站替代电脑客户端软件和手机App,也能逐步淘汰Windows操作系统、MacOS电脑操作系统和苹果IOS手机操作系统,因为网站代码具有跨平台兼容性、免安装、免升级、高容错和高普及性的优点,Liunx极速简约全屏浏览器可打开所有网页(少量需插件功能的网页除外,如:网银支付);目前,电脑客户端软件和手机App仅有两个优势:1、界面简洁,2、运行速度略快;全屏浏览器同样具备界面简洁的优点,因省略了主窗口、主菜单和功能按钮,并默认全屏展示所有网页,用户感觉不到浏览器的存在;全屏浏览器源代码仅851行,速度大大提高,二次打开网页文字和图片的耗时不超过1秒(有更新的大图片延时不超过2秒),特别是界面完全相同的网页二次打开耗时大约0.1秒(因为本地有图片缓存),应用软件界面一般都保持不变;随着5G通讯的普及,网页浏览速度将会实现飞跃,新版网页标准如能够允许客户端本地存取数据库将最终彻底淘汰电脑客户端软件和手机App。
附图说明
图 1. QtWebEingine 架构
图 2. QtWebEngine Widgets 模块
图 3. 全屏浏览界面示意图一
图 4. 全屏浏览界面示意图二
图 5. 多页签浏览窗口示意图
图 6. 右击菜单和二级子菜单“工具箱”
图 7. 右击菜单和二级子菜单“窗口缩放”
图 8. 右击菜单和二级子菜单“书签管理”
图 9. 右击菜单之“我的书签”
图 10. 右击菜单之“浏览足迹”。
具体实施方式
采用Linux系统的Python 3.7版语言、PyQt5 和 PyQtWebEingine 开发包实现“极速简约防盗Linux全屏浏览器”,开发平台是 PyCharm community 2019.3版本。防盗全屏浏览器只需要851行源代码,非常精炼、速度极快、界面简洁、操作简单、防盗和默认全屏显示所有网页。注释行以#开头,/ 是折行连接符,简单易懂的代码不加注释,以节省篇幅,防盗全屏浏览器有程序框架说明、全套代码、音视频编译和程序编译方法共4个步骤,如下:
1. 防盗全屏浏览器的程序框架说明
import ...
# 导入第三方开发包
download_item_ls = []
# 储存下载任务数组变量
webview_group = []
# 储存网页实例数组变量
webview_parent_group = []
# 储存网页父实例数组变量
class myQMenu(QMenu):
# 重写QMenu菜单类
class WebView(QWebEngineView):
# 重写网页展示QWebEngineView类
class myQLineEdit(QLineEdit):
# 重写QLineEdit类
class DownloadWidget(QProgressBar):
# 自定义下载DownloadWidget类,继承QProgressBar类
class myQMainWindow(QMainWindow):
# 重写QMainWindow类
class BookmarkWidget(myQMenu ):
# 自定义书签类,继承myQMenu类
class Browser(myQMainWindow):
# 自定义Browser类,调用网页展示WebView类,继承myQMainWindow类
class MyBrowser(myQMainWindow):
# 自定义MyBrowser类,调用Browser类,继承myQMainWindow类
if __name__ == "__main__":
# 主程序
2. 防盗全屏浏览器的全套代码
import sys,json,os,datetime,warnings,base64
from subprocess import Popen
from PyQt5.QtCore import QUrl, Qt, QCoreApplication, pyqtSignal,QDir, QFileInfo,/
/ QStandardPaths
from PyQt5.QtWidgets import QApplication, QMainWindow, QLineEdit,QToolBar, QTabWidget, /
/ QWidget, QHBoxLayout,QDialog, QPushButton, QProgressBar, QMenu,QLabel, /
/ QMessageBox,QAction,QTreeView,QFileDialog
from PyQt5.QtGui import QIcon,QDesktopServices,QCursor,QStandardItemModel,QStandardItem
from PyQt5.QtWebEngineWidgets import QWebEngineView,QWebEngineSettings, /
/ QWebEngineDownloadItem, QWebEnginePage
from pynput.keyboard import Controller,Key
# 导入第三方开发包
download_item_ls = []
# 储存下载任务数组变量
webview_group = []
# 储存网页实例数组变量
webview_parent_group = []
# 储存网页父实例数组变量
class myQMenu(QMenu):
# 重写QMenu菜单类
def __init__(self, parent=None):
super(myQMenu, self).__init__(parent)
def leaveEvent(self, QEvent):
# 鼠标离开菜单,就关闭菜单
self.close()
class WebView(QWebEngineView):
# 重写网页展示QWebEngineView类
@staticmethod
def minimum_zoom_factor():
# 定义窗口缩放的最小参数的方法
return 0.25
@staticmethod
def maximum_zoom_factor():
return 5
def __init__(self, mainWin):
super().__init__(mainWin)
self.mainWin = mainWin
def createWindow(self, QWebEnginePage_WebWindowType):
# 创建网页窗口的方法
new_webview = WebView(self.mainWin)
# 递归调用本类
self.mainWin.create_tab(new_webview)
# 创建新页签
return new_webview
class myQLineEdit(QLineEdit):
# 重写文本编辑行类QLineEdit
def __init__(self, parent=None):
super(myQLineEdit, self).__init__(parent)
self.save_text = ''
# 初始化变量self.save_text 为空
def wheelEvent(self, event):
# 滚轮处理方法
angle = event.angleDelta() / 8
angleY = angle.y()
# 竖直滚过的距离
if angleY >= 0:
# 滚轮向上滑动
if len(self.save_text)>0:self.setText(self.save_text)
# 若原来文本框有内容, 则还原文本框内容
else:
self.save_text = str(self.text())
# 滚轮向下滑动, 则暂储存文本框的内容到变量 self.save_text
self.setText('')
# 清空文本框
def mousePressEvent(self, event):
# 鼠标点击文本框, 延时35毫秒闪一下消息对话框, 避免有两个光标
message = QMessageBox()
message.setWindowTitle(' ')
message.setStandardButtons(QMessageBox.Ok)
message.button(QMessageBox.Ok).animateClick(35)
message.exec_()
def mouseDoubleClickEvent(self, event):
# 处理鼠标双击的方法
self.save_text = str(self.text())
# 暂储存文本框的内容到变量 self.save_text
self.setText('')
# 清空文本框
class DownloadWidget(QProgressBar):
#自定义文件下载类,自成一体,通俗易懂,不作注释,节省篇幅
finished = pyqtSignal()
remove_requested = pyqtSignal()
def __init__(self, download_item):
super(DownloadWidget, self).__init__()
self._download_item = download_item
download_item.finished.connect(self._finished)
self.total__bytes = download_item.totalBytes()
path = download_item.path()
download_item.downloadProgress.connect(self._download_progress)
self.setMaximumWidth(250)
description = QFileInfo(path).fileName()
description_length = len(description)
if description_length > 30:description = '{}...{}'.format(description[0:10], /
/ description[description_length - 10:])
self.setFormat('{} %p%'.format(description))
self.setOrientation(Qt.Horizontal)
self.setMinimum(0)
self.setValue(0)
self.setMaximum(100)
self._update_tool_tip(self.total__bytes)
@staticmethod
def open_file(file):
QDesktopServices.openUrl(QUrl.fromLocalFile(file))
@staticmethod
def open_download_directory():
path = QStandardPaths.writableLocation(QStandardPaths.DownloadLocation)
DownloadWidget.open_file(path)
def state(self):
return self._download_item.state()
def _update_tool_tip(self,total_bytes):
path = self._download_item.path()
tool_tip = "{}\n{}".format(self._download_item.url().toString(), /
/ QDir.toNativeSeparators(path))
total_bytes = self._download_item.totalBytes()
if total_bytes > 0:tool_tip += "\n{}兆".format(round(total_bytes / 1024/1024,2))
state = self.state()
if state == QWebEngineDownloadItem.DownloadRequested:tool_tip += "\n(requested)"
elif state == QWebEngineDownloadItem.DownloadInProgress:tool_tip += /
/ "\n(downloading...)"
elif state == QWebEngineDownloadItem.DownloadCompleted:tool_tip /
/ += "\n(completed)"
elif state == QWebEngineDownloadItem.DownloadCancelled:tool_tip += "\n(cancelled)"
else:tool_tip += "\n(interrupted)"
self.setToolTip(tool_tip)
def _download_progress(self, bytes_received, bytes_total):
self.total__bytes = bytes_total
if bytes_total > 0:self.setValue(int(100 * bytes_received / bytes_total))
else:self.setValue(100)
def _finished(self):
self._update_tool_tip(self.total__bytes)
self.finished.emit()
def _launch(self):
DownloadWidget.open_file(self._download_item.path())
def mouse_double_click_event(self, event):
if self.state() == QWebEngineDownloadItem.DownloadCompleted:self._launch()
def context_menu_event(self, event):
state = self.state()
context_menu = QMenu()
launch_action = context_menu.addAction("启动")
file1 = self._download_item.path()
launch_action.setEnabled(state==QWebEngineDownloadItem.DownloadCompleted and/
/ not file1.endswith('.mhtml'))
show_in_folder_action = context_menu.addAction("打开下载文件存放的文件夹")
show_in_folder_action.setEnabled(state ==QWebEngineDownloadItem./
/ DownloadCompleted)
cancel_action = context_menu.addAction("取消")
cancel_action.setEnabled(state == QWebEngineDownloadItem.DownloadInProgress)
remove_action = context_menu.addAction("删除")
remove_action.setEnabled(state != QWebEngineDownloadItem.DownloadInProgress)
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == launch_action:self._launch()
elif chosen_action == show_in_folder_action:DownloadWidget.open_file(QFileInfo( /
/ self._download_item.path()).absolutePath())
elif chosen_action == cancel_action:self._download_item.cancel()
elif chosen_action == remove_action:self.remove_requested.emit()
class myQMainWindow(QMainWindow):
# 重写主窗口类QMainWindow
def __init__(self, parent=None):
super(myQMainWindow, self).__init__(parent)
def closeEvent(self, QCloseEvent):
# 重写主窗口关闭方法
os.system('poweroff -h')
# 调用系统命令执行关机
_url_role = Qt.UserRole + 1
# 书签角色变量
_default_bookmarks = [
['我的书签'],
['http://www.hahayaya.com/', 'hahayaya', 'bookmarks/hhyy.png'],
['https://tv.cctv.com/live/cctv15_spm=C28340.PO8MkQf6Euyz.S91117.48',/
/ 'CCTV音乐频道', 'bookmarks/163_music.jpg'],
['https://www.youku.com/', '优酷', 'bookmarks/youku.jpg'],
['https://v.qq.com/', '腾讯视频', 'bookmarks/tencent.jpg'],
['浏览足迹'],
]
# 默认书签
class BookmarkWidget(myQMenu):
# 重写书签类, 继承myQMenu类
open_bookmark = pyqtSignal(QUrl)
# 设定信号变量 open_bookmark
changed = pyqtSignal()
# 设定信号变量 changed
def __init__(self):
# 初始化方法
super(BookmarkWidget, self).__init__()
self._model = self._create_model(self,self._read_bookmarks())
# 调用_read_bookmarks方法读取书签文件内容或默认书签变量创建书签模型变量
self._model.rowsInserted.connect(self._changed)
self._model.rowsRemoved.connect(self._changed)
self._model.dataChanged.connect(self._changed)
self._model.item(1, 0).removeRows(0,self._model.item(1, 0).rowCount())
# 把浏览足迹的变量self._model.item(1, 0)清空, self._model.item(0, 0)保存的是书签
def _changed(self):
# 书签变量有变化触发本方法
self.changed.emit()
def _action_activated(self, index):
# 书签被点击后触发本方法
self.open_bookmark.emit(self.sender().data())
def _config_dir(self):
# 创建隐藏目录.config保存书签文件和浏览器的缓存图片
return '{}/Rui_Browser'.format(QStandardPaths.writableLocation( /
/ QStandardPaths.ConfigLocation))
def _create_folder_item(self, title):
# 按书签的单项内容名称(如:'我的书签'或'浏览足迹')创建文件夹
result = QStandardItem(title)
result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
return result
def _create_item(self, url, title, icon):
# 创建书签数据项方法
result = QStandardItem(title)
result.setFlags(Qt.ItemIsEnabled | Qt.ItemIsSelectable)
result.setData(url, _url_role)
if icon is not None: result.setIcon(icon)
return result
def _create_model(self, parent, serialized_bookmarks):
# 根据读取的书签变量创建书签数据模型的方法
result = QStandardItemModel(0, 1, parent)
last_folder_item = None
for entry in serialized_bookmarks:
if len(entry) == 1:
# 如书签数据只有一项, 则创建目录
last_folder_item = self._create_folder_item(entry[0])
result.appendRow(last_folder_item)
else:
# 如书签数据有多项, 则创建数据变量,并添加到数据模型
url = QUrl.fromUserInput(entry[0])
title = entry[1]
if len(entry) > 2 and entry[2]:icon = QIcon(entry[2])
else:icon = None
last_folder_item.appendRow(self._create_item(url,title, icon))
return result
def _serialize_model(self, model, directory):
# 书签数据模型串行化处理的方法
result = []
folder_count = model.rowCount()
for f in range(0, folder_count):
folder_item = model.item(f)
result.append([folder_item.text()])
item_count = folder_item.rowCount()
for i in range(0, item_count):
item = folder_item.child(i)
entry = [item.data(_url_role).toString(), item.text()]
icon = item.icon()
if not icon.isNull():
icon_sizes = icon.availableSizes()
try:
largest_size = icon_sizes[len(icon_sizes) -1]
icon_file_name = '{}/icon{:02}_{:02}_{}.png'.format(directory, f, i, /
/ largest_size.width())
icon.pixmap(largest_size).save(icon_file_name, 'PNG')
entry.append(icon_file_name)
except:pass
result.append(entry)
return result
def add_tool_bar_bookmark(self, url, title, icon):
# 收藏书签的方法
found, r = self.exist_url_dataItem(self._model.item(0, 0),url)
# 判断书签是否存在于书签模型
if found:self._model.item(0, 0).removeRow(r)
# 如存在, 则删除
self._model.item(0, 0).insertRow(0,self._create_item(url,title, icon))
# 把新书签添加到书签数据模型self._model.item(0, 0)的最前面
def exist_url_dataItem(self,dataModel,Qurl):
# 判断书签是否存在于书签模型变量的方法
row_count = dataModel.rowCount()
for r in range(0, row_count):
item = dataModel.child(r)
url = item.data().toString()
if url==Qurl.toString():return True,r
# 如存在, 则返回True和索引号
return False,-1
def _populate_actions(self, parent_item, target_object, first_action):
# 为新加的书签添加Qaction的方法
existing_actions = target_object.actions()
# 获取当前变量action数组
existing_action_count = len(existing_actions)
#获取当前变量action数组的长度
a = first_action
# 添加的起始位置
row_count = parent_item.rowCount()
# 父变量的长度
for r in range(0, row_count):
# 遍列父变量,为新书签添加Qaction动作
item = parent_item.child(r)
title,icon,url = item.text(), item.icon(), item.data(_url_role)
if a < existing_action_count:
action = existing_actions[a]
if (title != action.toolTip()):
action.setText(BookmarkWidget.short_title(title))
action.setIcon(icon)
action.setToolTip(title)
action.setData(url)
action.setVisible(True)
else:
action = target_object.addAction(icon,BookmarkWidget.short_title(title))
action.setToolTip(title)
action.setData(url)
action.setIconVisibleInMenu(True)
action.triggered.connect(self._action_activated)
a = a + 1
def _remove_item_from_bookmarks_common(self, webview, item_Qurl,item_Tooltip, del_str, /
/ src_model):
# 从书签变量中删除一个书签的方法
button = QMessageBox.question(webview, "删除", del_str + "\"{}\"吗 ". /
/ format(item_Tooltip),QMessageBox.Yes | QMessageBox.No)
if button == QMessageBox.Yes:
# 选择删除,执行以下代码
row_count = src_model.rowCount()
for r in range(0, row_count):
item = src_model.child(r)
title = item.text()
url = item.data(_url_role)
if item_Qurl==url and item_Tooltip==title:
src_model.removeRow(r)
self.write_bookmarks()
break
def write_bookmarks(self):
# 保存书签内容到本地bookmarks.json文件的方法
dir_path = self._config_dir()
native_dir_path = QDir.toNativeSeparators(dir_path)
dir = QFileInfo(dir_path)
if not dir.isDir():
if not QDir(dir.absolutePath()).mkpath(dir.fileName()):
warnings.warn('Cannot create {}.'.format(native_dir_path), RuntimeWarning)
return
serialized_model = self._serialize_model(self._model, dir_path)
bookmark_file_name = os.path.join(native_dir_path, 'bookmarks.json')
with open(bookmark_file_name, 'w') as bookmark_file:
json.dump(serialized_model, bookmark_file, indent = 4)
def _read_bookmarks(self):
# 读取本地书签bookmarks.json文件或默认书签的方法
bookmark_file_name = os.path.join(QDir.toNativeSeparators( /
/ self._config_dir()),'bookmarks.json')
if os.path.exists(bookmark_file_name):
return json.load(open(bookmark_file_name))
return _default_bookmarks
def export_common(self,data_model):
# 导出书签的通用方法
row_count = data_model.rowCount()
my_bookmark_html1 = ''
for r in range(0, row_count):
item = data_model.child(r)
image, title, icon = '', item.text(), item.icon()
if not icon.isNull():
icon_sizes = icon.availableSizes()
try:
largest_size = icon_sizes[len(icon_sizes) - 1]
icon_file_name = 'bookmarks/icon/r0.png'
icon.pixmap(largest_size).save(icon_file_name, 'PNG')
with open(icon_file_name, 'rb') as fp:image =fp.read()
fp.close()
image = 'data:image/png;base64,' + str(base64.b64encode(image))
image = image.replace("b'", '')
image = image[0:len(image) - 1]
except:pass
url = item.data(_url_role).toString()
my_bookmark_html1 += ' <DT><A HREF="' + url + '" ADD_DATE="0" ICON="' + /
/ image + '">' + title + '</A><br>'
return my_bookmark_html1
def _export_bookmarks(self,webview,dest_file):
# 导出我的书签的方法
my_bookmark_html = '<!DOCTYPE NETSCAPE-Bookmark-file-1><br>'+ '<!-- This is an /
/ automatically generated file. DO NOT EDIT! -->'
my_bookmark_html += '<META HTTP-EQUIV="Content-Type" CONTENT="text/html; /
/ charset=UTF-8">' + '<TITLE>Hahayaya Bookmarks</TITLE><H1>我的书签</H1><br>'
my_bookmark_html += self.export_common(self._model.item(0,0))+ ' </DL><p><br>'
try:
with open(dest_file, 'w', encoding='utf-8') as /
/ bookmark_file:bookmark_file.write(my_bookmark_html)
bookmark_file.close()
QMessageBox.information(webview, '导出我的书签', '我的书签导出成功!\n书签备份/
/ 文件是:'+dest_file)
except:QMessageBox.information(webview, '导出我的书签', '我的书签导出失败!\n可能/
/ 因为无权限写入文件.')
def png_to_jpg(self,pngfile,title):
# 转换常用网站图标的方法
if not pngfile.endswith('.png'):return pngfile
elif title.find('京东')>-1:return 'img/jd.jpg'
elif title.find('爱奇艺') > -1:return 'img/iqiyi.jpg'
elif title.find('新浪') > -1:return 'img/sina.jpg'
elif title.find('优酷') > -1:return 'img/youku.jpg'
else:return pngfile
def _import_bookmarks(self,imported_bookmark,webview):
# 导入书签的方法
row1 = self._model.item(0, 0).rowCount()
button = QMessageBox.question(webview, "导入书签", "你想覆盖现有书签吗", /
/ QMessageBox.Yes | QMessageBox.No)
try:
for k in imported_bookmark:
url,title,icon = QUrl.fromUserInput(k[0]),k[1],QIcon(self.png_to_jpg(k[2],k[1]))
self._model.item(0, 0).appendRow(self._create_item(url, title, icon))
if button == QMessageBox.Yes:self._model.item(0, 0).removeRows(0, row1)
self.changed.emit()
return True
except:
QMessageBox.information(webview, '导入书签', '书签导入失败!\n可能因为导入文件/
/ 格式错误。')
return False
@staticmethod
def short_title(t):
# 获取网页短标题的方法
isEnglish = all(ord(c) < 128 for c in t)
# 判断网页标题是否为英文
if isEnglish == True:n=38
else:n=19
return t[0:n]
class Browser(myQMainWindow):
# 自定义Browser类,继承myQMainWindow类
def __init__(self, mainWin, webview=None):
super().__init__(mainWin)
self.mainWin,self.webview,self.part = mainWin, webview, ''
# 初始化三变量self.mainWin,self.webview,self.part,self.part储存全屏播放视频的父实例
self.initUI()
# 调用初始化界面的方法
def initUI(self):
# 初始化界面的方法
if self.webview == None:
# 如是第一个页面
self.webview = WebView(self)
# 调WebView类实例化
self.webview.load(QUrl("http://www.hao123.com/"))
# 把网页加载导航页http://www.hao123.com/
elif self.webview == '':self.webview = WebView(self)
# 创建空白新页签
self.webview.setZoomFactor(1.35)
# 把网页显示字号放大35%
self.webview.page().titleChanged.connect(self._title_changed)
# 把网页标题改变信号关联到_title_changed方法
self.webview.page().iconChanged.connect(self._icon_changed)
# 把网页图标改变信号关联到_icon_changed方法
self.initToolbar(self.webview)
# 调用 initToolbar 方法
self.setCentralWidget(self.webview)
# 把网页实例到页签窗口的中央
self.webview.setContextMenuPolicy(Qt.CustomContextMenu)
# 设置网页为自定义右击上下文菜单
self.webview.customContextMenuRequested.connect(self.context_webmenu_event)
#设置网页自定义右击文菜单的请求关联方法context_webmenu_event
webview_group.append(self.webview)
# 向网页实例数组变量添加该网页实例
webview_parent_group.append(self.webview.parent())
# 向网页父实例数组变量添加该网页父实例
if self.mainWin.INDEX==0:
# 假如是第一个页签, 那么执行以下代码
self.webview.setParent(None)
# 把本网页实例的父实例设置为None
self.webview.showFullScreen()
# 把本网页实例最大化显示
webview_parent_group[0].grabKeyboard()
# 把本网页父实例设置为捕获键盘, 以便进入全屏模式
def common_actions(self,context_menu,refresh_action,close_action):
# 网页右击菜单的公共调用方法
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == refresh_action:self.mainWin.trigger(QWebEnginePage.Reload)
# 假如选择的菜单功能是“刷新”, 那么网页刷新QWebEnginePage.Reload
elif chosen_action == close_action:self.mainWin.close_Tab(self.mainWin.INDEX)
# 假如选择的菜单功能是“关闭”, 那么网页刷新QWebEnginePage.Reload
else:return chosen_action
# 否则,返回选择的功能
def context_webmenu_event(self, point):
# 网页右击菜单处理的方法
if self.webview == self.sender():
webview_parent_group[self.mainWin.INDEX].grabKeyboard()
# 让当前窗口捕获键盘,进入全屏模式
linkUrl = self.webview.page().contextMenuData().linkUrl().toString()
# 获取网页的Url
editable = self.webview.page().contextMenuData().isContentEditable()
# 获取网页的编辑状态
mediaType = self.webview.page().contextMenuData().mediaType()
# 获取控件的类型
context_menu = QMenu()
# 构建鼠标右击菜单
close_action = context_menu.addAction(QIcon('img/close.jpg'), "关闭")
context_menu.addAction(QAction(QIcon('img/bookmark_toolbar.jpg'), "我的书签", /
/ self, triggered=self.mainWin.toolbar_bookmarks))
context_menu.addAction(QAction(QIcon('img/view_history.jpg'), "浏览足迹", self, /
/ triggered=self.mainWin.show_browsing_history))
context_menu.addAction(QAction(QIcon('img/bookmark_save_to_toolbar.jpg'), /
/ "收藏书签", self, triggered=self.mainWin.add_tool_bar_bookmark))
refresh_action = context_menu.addAction(QIcon('img/refresh.jpg'), "刷新")
current_item = self.webview.url().toString()
refresh_action.setEnabled(current_item != 'about:blank')
if mediaType ==1:
# 如右击的控件是图片,则执行以下代码
save_image_action = context_menu.addAction(QIcon('img/save.jpg'),"保存图片")
copy_image_action = context_menu.addAction(QIcon('img/copy.jpg'),"复制图片")
chosen_action = self.common_actions(context_menu,refresh_action, close_action)
if chosen_action == save_image_action:self.mainWin.trigger( /
/ QWebEnginePage.DownloadImageToDisk)
elif chosen_action == copy_image_action:self.mainWin.trigger( /
/ QWebEnginePage.CopyImageToClipboard)
elif self.webview.page().hasSelection() and noteditable:
context_menu = QMenu()
copy_action = context_menu.addAction(QIcon('img/copy.jpg'), "复制")
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == copy_action:self.mainWin.trigger( /
/ QWebEnginePage.Copy)
elif linkUrl=='' and not editable:
# 如右击的是空白处,则执行以下代码
context_menu.addAction(QAction(QIcon('img/clock.jpg'), "时钟", /
/ self, triggered=self.mainWin.clock))
context_menu.addAction(QAction(QIcon('img/open_dir.jpg'), "打开下载 /
/ 文件夹", self, triggered=self.mainWin.open_download_dir))
tools_submenu = context_menu.addMenu(QIcon('img/tools.jpg'), "工具箱")
tools_submenu.addAction(QAction(QIcon("img/wordpad.png"), /
/ "简易写字板", self, triggered=self.mainWin.wordpad))
tools_submenu.addAction(QAction(QIcon("img/screenshooter.png"), /
/ "截图",self, triggered=self.mainWin.screen_shot))
tools_submenu.addAction(QAction(QIcon("img/pinta.png"), /
/ "绘图",self, triggered=self.mainWin.pinta))
tools_submenu.addAction(QAction(QIcon("img/printer.png"), /
/ "打印机设置",self, triggered=self.mainWin.printer_setting))
tools_submenu.addAction(QAction(QIcon('img/wifi_volume.jpg'), /
/ "网络与音量",self, triggered=self.mainWin.wifi_volume))
window_submenu = context_menu.addMenu(QIcon('img/zoom_in.jpg'),
/ "窗口缩放")
window_submenu.addAction(QAction(QIcon("img/zoom_in.jpg"),
/ "拉近",self, triggered=self.mainWin.zoom_in))
window_submenu.addAction(QAction(QIcon("img/zoom_out.jpg"),
/ "拉远",self, triggered=self.mainWin.zoom_out))
window_submenu.addAction(QAction(QIcon("img/reset.jpg"), /
/ "重置",self, triggered=self.mainWin.reset_zoom))
bookmarks_submenu = context_menu.addMenu(QIcon( /
/ 'img/bookmark_manage.jpg'), "书签管理")
bookmarks_submenu.addAction(QAction(QIcon('img/export_my_ /
/ bookmark.jpg'), "导出书签", self, triggered=self.mainWin.export_bookmark))
bookmarks_submenu.addAction(QAction(QIcon('img/import_my_ /
/bookmark.jpg'), "导入书签", self, triggered=self.mainWin.import_bookmark))
context_menu.addAction(QAction(QIcon('img/info.jpg'), "hahayaya 极速 /
/ 简约防盗 Linux全屏浏览器", self, triggered=self.mainWin.about_msg))
self.common_actions(context_menu, refresh_action, close_action)
elif not editable:
# 如右击的是非空白且非编辑区,如:超链接,则执行以下代码
self.common_actions(context_menu, refresh_action, close_action)
elif editable:
# 如右击的是文本编辑区,则执行以下代码
context_menu = QMenu()
close_action = context_menu.addAction(QIcon('img/close.jpg'), "关闭")
select_all_action = context_menu.addAction(QIcon('img/select_all.jpg'),"全复制")
paste_action = context_menu.addAction(QIcon('img/paste.jpg'),"粘贴")
clean_action = context_menu.addAction(QIcon('img/clean.jpg'), "清除")
select_all_action.setEnabled(self.webview.page().contextMenuData().CanSelectAll)
paste_action.setEnabled(self.webview.page().contextMenuData().CanPaste)
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == select_all_action:
self.mainWin.trigger(QWebEnginePage.SelectAll)
self.mainWin.trigger(QWebEnginePage.Copy)
elif chosen_action == close_action:self.mainWin.close_Tab(self.mainWin.INDEX)
elif chosen_action == paste_action:self.mainWin.trigger(QWebEnginePage.Paste)
elif chosen_action == clean_action:
self.mainWin.trigger(QWebEnginePage.SelectAll)
self.mainWin.trigger(QWebEnginePage.Cut)
def keyPressEvent(self, QKeyEvent):
# 键盘处理程序,全屏模式进入与退出
key = QKeyEvent.key()
if self.urlbar.hasFocus():self.release_keyboard()
# 如地址栏有聚焦,则释放键盘
elif key == Qt.Key_Escape or key == Qt.Key_Space orQKeyEvent.modifiers() /
/ == Qt.AltModifier:
# 如按下Esc键或空格键或Alt键,则是全屏模式,执行以下切换代码
if not webview_group[self.mainWin.INDEX].isFullScreen():
# 如不是全屏显示,则切换到全屏显示
webview_group[self.mainWin.INDEX].setParent(None)
webview_group[self.mainWin.INDEX].showFullScreen()
else:
# 如是全屏显示,则切换到页签窗口正常显示
for i in range(0,len(webview_group)):
webview_group[i].showNormal()
webview_parent_group[i].setCentralWidget(webview_group[i])
elif key == Qt.Key_Shift and webview_group[self.mainWin.INDEX].isFullScreen():
# 如按下shift键且是全屏显示,则在页面下部显示搜狗辅助工具条,并置顶,满足
# 搜狗输入框的正常显示
webview_parent_group[self.mainWin.INDEX].addToolBar(Qt.BottomToolBarArea, /
/ self.mainWin.sougou_tool_bar)
self.mainWin.sougou_tool_bar.setParent(None)
elif key == Qt.Key_Minus:self.mainWin.close_Tab(self.mainWin.INDEX)
# 如按下-减号,则调用close_Tab方法关闭页签窗口
else:
# 其他按键,执行以下代码
self.release_keyboard()
keyboard = Controller()
if key == Qt.Key_Backspace:
# 倒格键,采用向左光标键和删除键代替,因为系统不允许模拟输入倒格键
self.key_common(keyboard, Key.left)
self.key_common(keyboard, Key.delete)
elif key>32 and key<=126:
# 输入可打印的ASCII键,则再模拟输入一次,免除用户重复输入
self.key_common(keyboard,chr(key))
def key_common(self,keyboard,key):
# 模拟输入键盘的键
keyboard.press(key)
keyboard.release(key)
def release_keyboard(self):
# 网页父窗口释放全部键盘的方法
for i in range(0, len(webview_parent_group)):webview_parent_group[i].releaseKeyboard()
def _icon_changed(self, icon):
# 网页图标改变的处理方法
self.mainWin.tabWidget.setTabIcon(self.mainWin.INDEX, icon)
url,title = self.webview.url(),self.webview.title()
found, r = self.mainWin.bookmark_widget.exist_url_dataItem(self.mainWin. /
/ bookmark_widget._model.item(1, 0), url)
if found: self.mainWin.bookmark_widget._model.item(1, 0).removeRow(r)
# 如浏览足迹存在这个网址,则把相应变量_model.item(1, 0)中的网址删除
self.mainWin.bookmark_widget._model.item(1, 0).insertRow( /
/ 0, self.mainWin.bookmark_widget._create_item(url, title,icon))
# 把该网址添加到相应变量_model.item(1, 0)的第一个
def _title_changed(self, title):
# 网页标题改变的处理方法
if title.find('www.')==-1:
self.mainWin.tabWidget.setTabText(self.mainWin.INDEX, /
/ BookmarkWidget.short_title(title))
self.mainWin.tabWidget.setTabToolTip(self.mainWin.INDEX, title)
def update_bookmarks(self):
# 更新书签变量_model.item(0, 0) 的处理方法
self.mainWin.bookmark_widget._populate_actions(self.mainWin.bookmark_widget. /
/ _model.item(0, 0), self.mainWin.bookmark_toolbar, 0)
def initToolbar(self, webview):
# 初始化主窗口工具栏
address_bar = QToolBar('地址栏')
self.addToolBar(address_bar)
self.urlbar = myQLineEdit()
self.urlbar.setToolTip('双击鼠标清除地址栏, 滚轮上滑可还原。')
self.urlbar.returnPressed.connect(self.navigate_to_url)
self.urlbar.setContextMenuPolicy(Qt.CustomContextMenu)
self.urlbar.customContextMenuRequested.connect(self.context_address_event)
# 右击网址栏,调用context_address_event方法,弹出菜单
address_bar.addWidget(self.urlbar)
if self.mainWin.INDEX==0:
# 第一个页签,需更新书签变量
self.update_bookmarks()
self.mainWin.bookmark_widget.changed.connect(self.update_bookmarks)
webview.urlChanged.connect(self.renew_urlbar)
webview.settings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True)
# 设置页面支持全屏化播放视频
webview.page().fullScreenRequested.connect(self._fullScreenRequested)
# 设置全屏视频播放信号关联_fullScreenRequested,不要与普通网页的全屏显示混淆
webview.page().profile().downloadRequested.connect(self._download_requested_action)
# 设置下载信号关联_download_requested_action方法
def context_address_event(self, point):
# 网址栏鼠标右击菜单显示和处理方法
context_menu = QMenu()
open_add_in_newTab_action = context_menu.addAction(QIcon('img/add.jpg'), /
/ "在新页签打开网址")
select_all_action = context_menu.addAction(QIcon('img/select_all.jpg'),"全复制")
paste_action = context_menu.addAction(QIcon('img/paste.jpg'),"粘贴")
current_url = self.urlbar.text()
select_all_action.setEnabled(current_url is not None)
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == open_add_in_newTab_action:
self.urlbar.setText(webview_group[self.mainWin.INDEX].url().toString())
self.mainWin.load_url_in_new_tab(QUrl.fromUserInput(current_url))
elif chosen_action == select_all_action:
self.urlbar.selectAll()
self.urlbar.copy()
elif chosen_action == paste_action:self.urlbar.paste()
def _download_requested_action(self, item):
# 处理下载信号的文件下载方法
for old_download in self.statusBar().children():
if type(old_download).__name__ == 'DownloadWidget' andold_download.state() != /
/ QWebEngineDownloadItem.DownloadInProgress:
self.statusBar().removeWidget(old_download)
del old_download
if not item in download_item_ls:
download_item_ls.append(item)
item.accept()
for i in range(0, len(webview_group)):
webview_group[i].showNormal()
webview_parent_group[i].setCentralWidget(webview_group[i])
download_widget = DownloadWidget(item)
download_widget.remove_requested.connect(self._remove_download_requested,/
/ Qt.QueuedConnection)
self.mainWin.statusBar().addWidget(download_widget)
download_widget.setContextMenuPolicy(Qt.CustomContextMenu)
download_widget.customContextMenuRequested.connect(download_widget./
/ context_menu_event)
def _remove_download_requested(self):
# 在状态栏删除下载进度条的方法
download_widget = self.sender()
self.mainWin.statusBar().removeWidget(download_widget)
del download_widget
def _fullScreenRequested(self,request):
# 处理视频全屏播放或切换正常窗口的方法
request.accept()
if request.toggleOn():
# 以下切换视频全屏播放
self.part = self.webview.parent()
self.webview.setParent(None)
self.webview.showFullScreen()
else:
# 以下切换视频正常窗口显示
self.webview.setParent(self.part)
self.webview.showNormal()
def navigate_to_url(self):
# 根据网址栏的地址更新网页的方法
q = QUrl(self.urlbar.text())
if q.scheme() == '':q.setScheme('http')
self.webview.setUrl(q)
self.webview.setZoomFactor(1.35)
def renew_urlbar(self, q):
# 切换页签时,同步更新网址栏地址的方法
self.urlbar.setText(q.toString())
def create_tab(self, webview):
# 点击超链接时创建新页签的方法
self.mainWin.add_Tab()
web_view=Browser(self.mainWin, webview=webview)
# 递归调用当前类的实例
self.mainWin.Layout.addWidget(web_view)
webview.setParent(None)
# 设置网页的父实例为None
webview.showFullScreen()
# 把所打开的网页默认全屏显示
web_view.grabKeyboard()
# 设置网页的父窗口捕获键盘,进入全屏模式,允许按Esc键、空格或Alt键切换
class MyBrowser(myQMainWindow):
# 自定义MyBrowser主窗口类,继承myQMainWindow类
def __init__(self):
super().__init__()
self.initWinTab()
# 初始化主窗口和页签
self.newTab()
# 创建第一个新页签
def initWinTab(self):
# 初始化主窗口和页签的方法
self.setWindowTitle('hahayaya 极速简约防盗 Linux 全屏浏览器')
self.setWindowFlags(Qt.WindowCloseButtonHint)
# 设置主窗口只有一个关闭按钮,没有最大化和最小化按钮,实现防盗
self.setWindowIcon(QIcon('img/hahayaya_logo1.png'))
self.sougou_tool_bar = QToolBar('')
# 激活显示搜狗输入法的工具栏,内容为空,辅助用途
self.tabWidget = QTabWidget()
self.tabWidget.setTabShape(QTabWidget.Triangular)
# 设置页签风格为梯形状
self.tabWidget.setTabsClosable(True)
# 设置页签可关闭
self.tabWidget.tabCloseRequested.connect(self.close_Tab)
# 设置页签关闭方法是close_Tab
self.tabWidget.currentChanged.connect(self.changeTab)
self.tabWidget.tabBarClicked.connect(self.clickTab)
self.setCentralWidget(self.tabWidget)
self.bookmark_widget = BookmarkWidget()
# 书签类实例化
self.bookmark_widget.open_bookmark.connect(self.load_url)
self.bookmark_toolbar = myQMenu('我的书签列表')
self.bookmark_toolbar.setContextMenuPolicy(Qt.CustomContextMenu)
self.bookmark_toolbar.customContextMenuRequested.connect(self.context_toolbar_event)
# 书签窗口右击菜单关联context_toolbar_event方法
self.bookmark_toolbar.setToolTipsVisible(True)
self.showMaximized()
# 主窗口最大化显示
def load_url(self, url):
# 当前网页加载新网址方法
webview_group[self.INDEX].setUrl(url)
found, r = self.bookmark_widget.exist_url_dataItem(self.bookmark_widget./
/_model.item(0, 0), url)
# 判断当前书签是否包含本网址
if found:
# 如网址在书签中存在,则先删除后置顶书签并保存
item = self.bookmark_widget._model.item(0, 0).child(r)
title,icon = item.text(), item.icon()
self.bookmark_widget._model.item(0, 0).removeRow(r)
self.bookmark_widget._model.item(0, 0)./
/ insertRow(0, self.bookmark_widget._create_item(url,title, icon))
self.bookmark_widget.write_bookmarks()
def load_url_in_new_tab(self, url):
# 在新页签加载网址的方法
self.add_Tab()
self.Layout.addWidget(Browser(self,''))
webview_group[self.INDEX].setUrl(url)
webview_group[self.INDEX].setParent(None)
webview_group[self.INDEX].showFullScreen()
# 默认网页全屏显示
webview_parent_group[self.INDEX].grabKeyboard()
# 设置网页父窗口捕获键盘,进入全屏模式
def trigger(self, action):
# 执行网页内置动作的方法,如:刷新
webview_group[self.INDEX].page().triggerAction(action)
def show_browsing_history(self):
# 显示浏览足迹的方法,浏览足迹的数据存放在_model.item(1, 0)变量中
self.bookmark_footprint = myQMenu()
self.bookmark_footprint.setToolTipsVisible(True)
self.bookmark_widget._populate_actions(self.bookmark_widget./
/_model.item(1, 0), self.bookmark_footprint, 0)
self.bookmark_footprint_common(self.bookmark_widget./
/_model.item(1, 0), self.bookmark_footprint)
def open_download_dir(self):
# 打开下载文件夹的方法
DownloadWidget.open_download_directory()
def zoom_factor(self):
# 获取网页的缩放比例方法
return webview_group[1].zoomFactor() if len(webview_group)>1else 1.0
def set_zoom_factor(self, z):
# 设置所有网页的缩放比例方法
for w in webview_group:w.setZoomFactor(z)
def zoom_in(self):
# 网页拉近放大的方法
if (self.zoom_factor() * 1.5 <= WebView.maximum_zoom_factor()):self.set_zoom_factor(/
/self.zoom_factor() * 1.5)
def zoom_out(self):
# 网页拉远缩小的方法
if (self.zoom_factor() / 1.5 >= WebView.minimum_zoom_factor()):self.set_zoom_factor(/
/self.zoom_factor() / 1.5)
def reset_zoom(self):
# 网页重置正常显示比例的方法
self.set_zoom_factor(1)
def add_tool_bar_bookmark(self):
# 收藏书签的方法
url = webview_group[self.INDEX].url()
icon,title = self.tabWidget.tabIcon(self.INDEX),self.tabWidget.tabToolTip(self.INDEX)
self.bookmark_widget.add_tool_bar_bookmark(url, title, icon)
# 添加书签
self.bookmark_widget.write_bookmarks()
# 保存书签
self.toolbar_bookmarks()
# 显示书签
def toolbar_bookmarks(self):
# 书签窗口显示方法
self.bookmark_footprint_common(self.bookmark_widget./
/_model.item(0, 0),self.bookmark_toolbar)
def bookmark_footprint_common(self,src_model,myQmenu):
# 书签和浏览足迹显示的公用方法
rows = src_model.rowCount()
cols = int(rows/37)
if rows % 37 > 0: cols += 1
cols = min(3,cols)
myQmenu.setVisible(True)
myQmenu.resize(cols*384,1050)
myQmenu.move(553,0)
mouse = QCursor()
mouse.setPos(630,17)
# 把光标定位到第一行
def context_toolbar_event(self, point):
# 书签菜单右击删除的方法
action = self.bookmark_toolbar.actionAt(point)
if action is not None:
context_menu = QMenu()
remove_action = context_menu.addAction("删除")
current_Qurl,current_Tooltip = action.data(),action.toolTip()
chosen_action = context_menu.exec_(QCursor.pos())
if chosen_action == remove_action:self.bookmark_widget./
/_remove_item_from_bookmarks_common(webview_group[self.INDEX],current_Qurl,/
/current_Tooltip, "真的想删除书签: ", self.bookmark_widget._model.item(0,0))
def export_bookmark(self):
# 导出书签的方法
self._dest_path_edit = self.bookmark_UI('我的书签导出/
/到:',20,67,135,65,490,25,self.ok_export_bookmark)
self.bookmark_UI2('确认',485, 149, self.ok_export_bookmark, "导出我的书签~备份保存",/
/'img/export_bookmark.jpg', 705, 239)
def ok_export_bookmark(self):
# 导出书签的确认按钮调用方法
self.dialog.close()
self.bookmark_widget._export_bookmarks(webview_group[self.INDEX],/
/self._dest_path_edit.text())
webview_parent_group[self.INDEX].grabKeyboard()
def bookmark_UI(self,label_1,label_x,label_y,edit_line_x,edit_line_y,edit_line_w,/
/edit_line_h,edit_line_def):
# 显示对话框窗口的标签和文本编辑框的公用方法
self.dialog = QDialog()
label1 = QLabel(label_1, self.dialog)
label1.move(label_x, label_y)
src_path = QStandardPaths.writableLocation(QStandardPaths.DownloadLocation) +/
/'/bookmark_hahayaya.html'
src_path_edit = QLineEdit(src_path, self.dialog)
src_path_edit.returnPressed.connect(edit_line_def)
src_path_edit.move(edit_line_x,edit_line_y)
src_path_edit.resize(edit_line_w,edit_line_h)
return src_path_edit
def bookmark_UI2(self,button_name,button_x,button_y,edit_line_def,title,pic,win_w,win_h):
# 显示对话框窗口按钮的公用方法
btn2 = QPushButton(button_name, self.dialog)
btn2.move(button_x,button_y)
btn2.clicked.connect(edit_line_def)
btn2.setCursor(Qt.PointingHandCursor)
self.common_UI(title,pic,win_w,win_h)
def common_UI(self,title,pic,win_w,win_h):
# 显示对话框窗口的标题、图标等公用方法
self.dialog.setWindowTitle(title)
self.dialog.setWindowIcon(QIcon(pic))
self.dialog.resize(win_w,win_h)
self.dialog.setWindowModality(Qt.ApplicationModal)
self.dialog.exec_()
def import_bookmark(self):
# 导入书签的处理方法
self._src_path_edit = self.bookmark_UI('书签导入源:',/
/20,67,105,65,520,25,self.ok_import_bookmark)
btn = self.button_common(self.dialog, 'img/open_dir.jpg', 50,25, 635, 65)
btn.setCursor(Qt.PointingHandCursor)
btn.setToolTip('请选择想导入的书签源文件')
btn.clicked.connect(self.showFileDialog)
self.bookmark_UI2('确认',485, 149, self.ok_import_bookmark, "导入书签", /
/'img/import_bookmark.jpg', 705, 239)
def showFileDialog(self):
# 弹出目录和文件选择对话框, 供选择书签源文件的方法
file1 = QFileDialog.getOpenFileName(webview_group[self.INDEX], "请选择想导入的/
/书签源文件", "/")
self._src_path_edit.setText(file1[0])
def ok_import_bookmark(self):
# 导入书签, 按确认按钮的方法
self.dialog.close()
if not os.path.exists('bookmarks/icon'):os.mkdir('bookmarks/icon')
m_bookmark=self.process_html_bookmark()
if m_bookmark is not None:
ret=self.bookmark_widget._import_bookmarks(m_bookmark,webview_group[self.INDEX])
if ret:self.bookmark_widget.write_bookmarks()
webview_parent_group[self.INDEX].grabKeyboard()
def process_html_bookmark(self):
# 处理导入书签的公用方法,包括:谷歌、360、火狐狸、IE、Edge和自己导出的书签
import_file = self._src_path_edit.text()
if not os.path.exists(import_file):
QMessageBox.information(webview_group[self.INDEX], '导入书签', '温馨提示:/
/书签文件\n'+import_file+' 不存在!')
return None
fp = open(import_file,'r',encoding='utf-8')
try:imported_bookmark = fp.read()
except:imported_bookmark = ''
fp.close()
if imported_bookmark == '':
QMessageBox.information(webview_group[self.INDEX], '导入书签','温馨提示:/
/书签文件\n' + import_file + ' 格式不正确!')
return None
m_bookmark = []
href_ls = imported_bookmark.split('<A HREF="')
for i in range(1,len(href_ls)):
m_title, m_icon, m_url, m_mark_item = '', '', '', []
m_url=href_ls[i]
if m_url.find('ICON="') > -1:m_icon = m_url.split('ICON="')[1]
elif m_url.find('ICON_URI="') > -1:m_icon = m_url.split('ICON_URI="')[1]
title_ls = m_url.split('</A>')
m_title = title_ls[0]
m_url=m_url[0:m_url.find('"')]
try:m_title=m_title[m_title.rfind('>')+1:len(m_title)].rstrip()
except:pass
try:
m_icon=m_icon[0:m_icon.find('"')]
if m_icon.find('http')>-1:m_icon = ''
elif m_icon.find(';base64')>-1:
picfile = m_url[m_url.find('//')+2:len(m_url)]
picfile = picfile[0:picfile.find('/')]
picfile = picfile.replace('www.', '').replace('.', '__').replace('/', '_').replace('!', '~')
ls = m_icon.split(',')
dataType, base64_str = ls[0], ls[1]
dataType = dataType.replace('data=image/', '').replace('data:image/', /
/'').replace(';base64', '')
m_icon = self.base64_to_pic(base64_str,picfile,dataType)
except:pass
if m_url.find('http')>-1:
m_mark_item.append(m_url)
m_mark_item.append(m_title)
m_mark_item.append(m_icon)
m_bookmark.append(m_mark_item)
return m_bookmark
def base64_to_pic(self,base64_str,picfile,dataType):
# 把base64格式的字符串转换为图片文件
save_file = 'bookmarks/icon/'+picfile+'.'+dataType
tu_b = base64.b64decode(base64_str)
with open(save_file, 'wb') as fp: fp.write(tu_b)
return save_file
def button_common(self,back,pic,width,height,x,y):
# 显示图片按钮的公用方法
btn_1 = QPushButton('', back)
btn_1.setStyleSheet("QPushButton{border-image: url('"+pic+"')}")
btn_1.setFixedWidth(width)
btn_1.setFixedHeight(height)
btn_1.move(x, y)
return btn_1
def about_msg(self):
# 显示产品介绍的方法,产品介绍放在图片img/Hahayaya_fullscreen_intro.png中
self.dialog = QDialog()
self.button_common(self.dialog, 'img/Hahayaya_fullscreen_intro.png', 900, 1060, 3,3)
self.common_UI(' ', 'img/info.jpg', 907, 1107)
def clock(self):
# 显示当前时间的方法
self.dialog = QDialog()
label1 = QLabel('现在的时间是:'+datetime.datetime.now().strftime(/
/"%Y-%m-%d %A %H:%M:%S"), self.dialog)
label1.move(63, 50)
self.button_common(self.dialog, 'img/clock.jpg', 298, 298,63, 95)
self.common_UI('hahayaya 时钟 ', 'img/clock.jpg', 430, 490)
def popen_common(self, program1, para1):
# 执行第三方程序的公用方法
for i in range(0,len(webview_parent_group)):webview_parent_group[i].releaseKeyboard()
# 释放所有页签窗口的键盘捕获, 退出全屏模式
if len(para1)==0:Popen([program1])
else:Popen([program1, para1])
# 调用内置函数Popen打开指定的程序
def wordpad(self):
# 执行简易文档处理程序的方法
self.popen_common("gedit", "")
def screen_shot(self):
# 执行截图程序的方法
self.popen_common("gnome-screenshot","--interactive")
def pinta(self):
# 执行绘图程序的方法
self.popen_common("/usr/bin/pinta", "")
def printer_setting(self):
# 执行打印机设置的方法
self.popen_common("system-config-printer", "")
def wifi_volume(self):
# 执行网络和音量设置的方法
self.popen_common("gnome-control-center","wifi")
def add_Tab(self):
# 增加新页签的公用方法
self.tab = QWidget()
self.tabWidget.addTab(self.tab, "新")
self.tabWidget.setCurrentWidget(self.tab)
self.Layout = QHBoxLayout(self.tab)
def newTab(self):
# 创建新页签方法
self.add_Tab()
self.Layout.addWidget(Browser(self))
def close_Tab(self, index):
# 关闭页签处理方法
self.webview2 = webview_group[index]
self.webview2.page().setAudioMuted(True)
# 关闭网页的声音
self.tabWidget.removeTab(index)
# 删除页签
self.webview2.close()
# 关闭网页
webview_group.remove(self.webview2)
# 从数组变量webview_group中删除网页实例
webview_parent_group.remove(webview_parent_group[index])
# 从数组变量webview_ parent_group中删除网页父实例
if self.tabWidget.count() == 0:
# 最后一个页签,则关闭搜狗工具栏和主窗口
self.sougou_tool_bar.close()
self.close()
else:webview_parent_group[index-1].grabKeyboard()
# 如关闭其他页签,则让剩下的最后一个页签父窗口捕获键盘,进入全屏模式
def changeTab(self, index):
# 切换页签处理方法
self.INDEX = index
def clickTab(self, index):
# 点击页签处理方法
self.INDEX = index
if __name__ == "__main__":
# 主程序
argvs = sys.argv
argvs.append("--no-sandbox")
QCoreApplication.setAttribute(Qt.AA_UseSoftwareOpenGL)
app = QApplication(argvs)
window = MyBrowser()
# 实例化主窗口和加载首页面
window.show()
# 显示主窗口
sys.exit(app.exec_())
以上是防盗全屏浏览器的全套代码,共851行,注释行除外.
3. 音视频播放需做的下载、准备和编译工作
通过网络下载的 PyQtWebEngine 开发包可能因版权责任,不提供音视频播放功能,开发者需要自己完成编译工作,编译步骤如下:
(1) 安装 Python 3.7 64位和GCC 4.8.5 64位
(2) 下载并安装Qt 5.x.x,以Qt 5.13.2 为例 (最新版本是 Qt 5.15.1),Qt 软件包包含QtWebEngine模块,下载URL是:
http://download.qt-project.org/official_releases/qt/5.13/5.13.2/single/qt-everywhere-src- /
/ 5.13.2.tar.xz,复制到 \root目录下,再切换到 \root目录,
运行 tar –xvJf qt-everywhere-src-5.13.2.tar.xz 解压安装
(3) 切换到 qtwebengine 的源码目录
cd /root/qt-everywhere-src-5.13.2/qtwebengine/src/webengine
(4) 增加qtwebengine 的编译选项webengine-proprietary-codecs以支持音视频播放
在终端命令行输入:
/root/qt-everywhere-src-5.13.2/configure -prefix ./qtbase <license> -webengine-proprietary-codecs
若编译成功,则会提示"make"
(5) 运行make 生成库文件
在终端命令行输入:make生成库文件,存放在./qtbase目录下,把三个与浏览器音视频播放相关的库文件:QtWebEngineCore.so、QtWebEngineWidgets.so和QtWebEngine.so复制到安装Python3的子目录lib/python3.7/site-packages/PyQt5覆盖原来的三个文件,即可支持浏览器程序播放音视频了.
4. Python程序的编译
在PyCharm开发平台的Terminal下,运行以下命令执行编译:
/usr/local/python3/bin/pyinstaller --clean -Dw --noconsole --noconfirm –i /
/img/hahayaya_logo1.png lanWeb.py
注:主程序是lanWeb.py,img/hahayaya_logo1.png是程序图标,编译后的执行程序lanWeb放在dist/lanWeb 目录下,需将img子目录和bookmarks子目录复制到dist/lanWeb 目录下,才能显示图标和书签图标。
Claims (6)
1.全屏浏览器默认全屏显示所有打开的网页。
2.防盗全屏浏览器无论全屏显示,还是多页签窗口显示(主窗口只提供关闭按钮,不能缩放窗口),关闭主窗口或最后一个页面就直接关机;因防盗需要,故重写 QMainWindow类,修改 closeEvent 方法,调用Linux 系统命令 poweroff -h关闭主机;鼠标右击菜单的“关闭”功能,遇到最后一个页面也调用同样的关闭方法;防盗还须屏蔽操作系统入口(参考本发明人的另一个发明专利申请“一种程序预装且屏蔽操作系统入口的应用软件加密技术”,申请号是:2020111821638),采用单独的固态硬盘安装Linux操作系统和防盗全屏浏览器软件,连接电脑USB口,开机自启动浏览器,与主硬盘的Windows操作系统或其他操作系统严格隔离,这样能够达到允许员工上网且保证资料防盗的目的。
3.极速简约全屏浏览器能推动网站替代电脑客户端软件和手机App,也能逐步淘汰Windows操作系统、MacOS电脑操作系统和苹果IOS手机操作系统,因为网站代码具有跨平台兼容性、免安装、免升级、高容错和高普及性的优点,Liunx极速简约全屏浏览器可打开所有网页(少量需插件功能的网页除外,如:网银支付);目前,电脑客户端软件和手机App仅有两个优势:1、界面简洁,2、运行速度略快;全屏浏览器同样具备界面简洁的优点,因省略了主窗口、主菜单和功能按钮,并默认全屏展示所有网页,用户感觉不到浏览器的存在;全屏浏览器源代码仅851行,速度大大提高,二次打开网页文字和图片的耗时不超过1秒(有更新的大图片延时不超过2秒),特别是界面完全相同的网页二次打开耗时大约0.1秒(因本地有图片缓存),应用软件界面一般都保持不变;随着5G通讯的普及,网页浏览速度将会实现飞跃,新版网页标准如能够允许客户端本地存取数据库将最终彻底淘汰电脑客户端软件和手机App。
4.极速简约防盗Linux全屏浏览器(简称:防盗全屏浏览器)的特点是:程序精炼、速度快、界面简洁、防盗和默认全屏显示网页;采用Esc或空格或Alt键随时切换全屏或正常显示;按小键盘-减号或鼠标右击菜单的“关闭”功能即可关闭页面;正常输入框输入内容会自动退出全屏模式,打开超链接或右击鼠标或关闭当前页就自动进入全屏模式,具备自动全屏模式;保留多页签窗口浏览、支持音视频播放,不支持需证书的少量不常用功能,如:网银转账(正在被手机扫码支付替代),优先提高运行速度。
5.防盗全屏浏览器默认首先启动hao123.com导航网页(可替换为其他导航网页),并以全屏方式展示;界面省略了主菜单和功能按钮,保留鼠标右击菜单,在网页任何空白处右击可弹出一级菜单,功能有:关闭、我的书签、浏览足迹、收藏书签、刷新、时钟、打开下载文件夹、工具箱子菜单、窗口缩放子菜单、书签管理子菜单和hahayaya极速简约防盗Linux全屏浏览器的介绍;工具箱子菜单的功能有:简易文档处理、截图、绘图、打印机设置和网络音量设置;窗口缩放子菜单的功能有:拉近、拉远和重置;书签管理子菜单的功能有:书签导出和书签导入;用户点击“我的书签”或“浏览足迹”主功能后,系统自动弹出书签窗口或浏览足迹窗口,并自动把光标移到书签窗口或浏览足迹窗口的第一行,方便操作,单击书签或网址可打开网页全屏显示,并把该书签置顶;右击任一个书签可选择删除;点击“收藏书签”主功能可把该书签加到“我的书签”的第一条;为文件下载进度条提供了鼠标右击子菜单:启动、打开下载文件夹、取消和删除;网页图片的右击菜单是:关闭、我的书签、浏览足迹、收藏书签、刷新、保存图片和复制图片;选中一段文字的右击菜单是:复制;编辑框的右击菜单是:关闭、全复制、粘贴和清除;网址栏的右击菜单是:在新页签打开、全复制和粘贴,地址栏双击可清除文本内容,滚轮上滑可还原内容。
6.权利要求1~5的实施方式基于Linux CentOS 7.7的Python 3.7、PyQt5和QtWebEngine第三方开发包;但开发防盗全屏浏览器的理念和原理适用于任何操作系统和计算机语言,既包括电脑操作系统,也包括手机操作系统;防盗全屏浏览器交付使用方式既包含独立软件,也包括嵌入到其它应用软件,如:云套件;效仿权利要求5的功能,如覆盖度低于50%,则不受限制。
Priority Applications (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202011531684.XA CN112487340A (zh) | 2020-12-23 | 2020-12-23 | 一种极速简约防盗Linux全屏浏览器的创新技术 |
Applications Claiming Priority (1)
Application Number | Priority Date | Filing Date | Title |
---|---|---|---|
CN202011531684.XA CN112487340A (zh) | 2020-12-23 | 2020-12-23 | 一种极速简约防盗Linux全屏浏览器的创新技术 |
Publications (1)
Publication Number | Publication Date |
---|---|
CN112487340A true CN112487340A (zh) | 2021-03-12 |
Family
ID=74915443
Family Applications (1)
Application Number | Title | Priority Date | Filing Date |
---|---|---|---|
CN202011531684.XA Pending CN112487340A (zh) | 2020-12-23 | 2020-12-23 | 一种极速简约防盗Linux全屏浏览器的创新技术 |
Country Status (1)
Country | Link |
---|---|
CN (1) | CN112487340A (zh) |
Cited By (2)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN113553205A (zh) * | 2021-09-17 | 2021-10-26 | 统信软件技术有限公司 | 一种用于QT和Web端通信协议的执行方法和执行器 |
CN115344273A (zh) * | 2022-10-19 | 2022-11-15 | 杭州比智科技有限公司 | 一种基于货架系统来运行应用软件的方法及系统 |
Citations (11)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1489021A (zh) * | 2002-10-10 | 2004-04-14 | 鸿富锦精密工业(深圳)有限公司 | 自动存储ups相连设备中已开启文件的方法 |
CN1613064A (zh) * | 2002-01-03 | 2005-05-04 | 英特尔公司 | 用于动态调整存储器页面关闭策略的方法 |
CN102594997A (zh) * | 2012-04-05 | 2012-07-18 | 何乙诚 | 一种手机远程控制电脑的方法 |
CN103034438A (zh) * | 2012-11-26 | 2013-04-10 | 上海应用技术学院 | 多屏幕多点触控浏览器实现方法 |
CN104424249A (zh) * | 2013-08-28 | 2015-03-18 | 富泰华工业(深圳)有限公司 | 个性化网页系统及实现方法 |
CN109656624A (zh) * | 2018-11-13 | 2019-04-19 | 浙江合众新能源汽车有限公司 | 一种安卓中控大屏的启动与关机方法及装置 |
CN109756617A (zh) * | 2017-11-06 | 2019-05-14 | 北京航天长峰科技工业集团有限公司 | 一种基于web的手机定时开关机实现方法 |
CN110231934A (zh) * | 2019-08-02 | 2019-09-13 | 南京擎盾信息科技有限公司 | 一种基于Windows系统一体机的业务办理通用平台开发方法 |
CN111737611A (zh) * | 2019-05-23 | 2020-10-02 | 北京京东尚科信息技术有限公司 | 统计页面访问时长的方法、装置、客户端及电子设备 |
CN111859227A (zh) * | 2020-08-07 | 2020-10-30 | 深圳市哈哈丫丫互联网有限公司 | Esc键随意切换网页全屏或正常显示的浏览器增值技术 |
CN112052009A (zh) * | 2020-09-18 | 2020-12-08 | 深圳市哈哈丫丫互联网有限公司 | 一种云浏览器的创新技术方案 |
-
2020
- 2020-12-23 CN CN202011531684.XA patent/CN112487340A/zh active Pending
Patent Citations (11)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN1613064A (zh) * | 2002-01-03 | 2005-05-04 | 英特尔公司 | 用于动态调整存储器页面关闭策略的方法 |
CN1489021A (zh) * | 2002-10-10 | 2004-04-14 | 鸿富锦精密工业(深圳)有限公司 | 自动存储ups相连设备中已开启文件的方法 |
CN102594997A (zh) * | 2012-04-05 | 2012-07-18 | 何乙诚 | 一种手机远程控制电脑的方法 |
CN103034438A (zh) * | 2012-11-26 | 2013-04-10 | 上海应用技术学院 | 多屏幕多点触控浏览器实现方法 |
CN104424249A (zh) * | 2013-08-28 | 2015-03-18 | 富泰华工业(深圳)有限公司 | 个性化网页系统及实现方法 |
CN109756617A (zh) * | 2017-11-06 | 2019-05-14 | 北京航天长峰科技工业集团有限公司 | 一种基于web的手机定时开关机实现方法 |
CN109656624A (zh) * | 2018-11-13 | 2019-04-19 | 浙江合众新能源汽车有限公司 | 一种安卓中控大屏的启动与关机方法及装置 |
CN111737611A (zh) * | 2019-05-23 | 2020-10-02 | 北京京东尚科信息技术有限公司 | 统计页面访问时长的方法、装置、客户端及电子设备 |
CN110231934A (zh) * | 2019-08-02 | 2019-09-13 | 南京擎盾信息科技有限公司 | 一种基于Windows系统一体机的业务办理通用平台开发方法 |
CN111859227A (zh) * | 2020-08-07 | 2020-10-30 | 深圳市哈哈丫丫互联网有限公司 | Esc键随意切换网页全屏或正常显示的浏览器增值技术 |
CN112052009A (zh) * | 2020-09-18 | 2020-12-08 | 深圳市哈哈丫丫互联网有限公司 | 一种云浏览器的创新技术方案 |
Cited By (3)
Publication number | Priority date | Publication date | Assignee | Title |
---|---|---|---|---|
CN113553205A (zh) * | 2021-09-17 | 2021-10-26 | 统信软件技术有限公司 | 一种用于QT和Web端通信协议的执行方法和执行器 |
CN115344273A (zh) * | 2022-10-19 | 2022-11-15 | 杭州比智科技有限公司 | 一种基于货架系统来运行应用软件的方法及系统 |
CN115344273B (zh) * | 2022-10-19 | 2023-01-31 | 杭州比智科技有限公司 | 一种基于货架系统来运行应用软件的方法及系统 |
Similar Documents
Publication | Publication Date | Title |
---|---|---|
Verzani | Getting started with RStudio | |
Murphy et al. | Beginning Android 4 | |
US8555186B2 (en) | Interactive thumbnails for transferring content among electronic documents | |
US20110022955A1 (en) | Mashup Application Processing System | |
US20150309993A1 (en) | Agile Enterprise Globalization | |
CN104823158B (zh) | 用于简化的知识工程的方法与系统 | |
US20140047409A1 (en) | Enterprise application development tool | |
CN101809573A (zh) | 基于游标位置更新内容显示 | |
TW201508639A (zh) | 透過捕捉服務捕捉網站內容 | |
JPH07210353A (ja) | データ処理システム・グラフィカル・ユーザ・インタフェースをカストマイズする方法及びシステム | |
US11755293B2 (en) | Code execution and data processing pipeline | |
Smyth | Android Studio 3.2 Development Essentials-Android 9 Edition: Developing Android 9 Apps Using Android Studio 3.2, Java and Android Jetpack | |
US20170199861A1 (en) | Techniques for providing user interface enhancements for spreadsheets and tables | |
CN112487340A (zh) | 一种极速简约防盗Linux全屏浏览器的创新技术 | |
US20150301993A1 (en) | User interface for creation of content works | |
CN112256244A (zh) | 一种极速简约绿色Linux浏览器的创新技术 | |
Smyth | Android Studio Development Essentials: Android 6 Edition | |
US20080168087A1 (en) | System and Method for Managing Location-Independent Objects | |
CN113608645A (zh) | 鼠标双击网页空白处切换全屏或窗口显示及默认全屏浏览器创新技术 | |
Eng | Hands-On GUI Programming with C++ and Qt5: Build stunning cross-platform applications and widgets with the most powerful GUI framework | |
Clark et al. | Sencha Touch Mobile JavaScript Framework | |
Holaň et al. | Vaadin 7 cookbook | |
US11126406B1 (en) | Embedded application programming interface explorer | |
CN112541139A (zh) | 一种通用极简html超文本书签导入与导出的绿色程序 | |
KR20200051165A (ko) | Internet Explorer에서의 인터넷 정보 처리 자동화 방법 |
Legal Events
Date | Code | Title | Description |
---|---|---|---|
PB01 | Publication | ||
PB01 | Publication | ||
SE01 | Entry into force of request for substantive examination | ||
SE01 | Entry into force of request for substantive examination |