使用QWebEngineView打造一款简单浏览器

使用PyQt5的QWebEngineView组件打造一款简单的浏览器
QWebEngineView是PyQt中的一个可以显示网页的组件,该组件封装了谷歌浏览器内核,功能强大。新手试着实现一下,锻炼自己的编码能力。
成品图片
1界面图片
使用QWebEngineView打造一款简单浏览器
文章图片

2界面图片
使用QWebEngineView打造一款简单浏览器
文章图片

首先重写一下QWebEngineView类的createWindow函数
这个函数在QWebEngineView中点击跳转打开新页面的时候会被调用,如果不重写的话,页面链接跳转到新页面的时候就会没有反应。

class MyWebView(QWebEngineView):def __init__(self, my, *args): super(MyWebView, self).__init__(*args) self.my = my # self.view = Nonedef createWindow(self, QWebEnginePage_WebWindowType): #如果是要在本页面显示的页面则return self return self.my.create_view() #创建一个新的容器显示新的页面

写一个用来装页面以及前进和后退刷新的界面
class Webbox(QWidget): def __init__(self, my, *args): super(Webbox, self).__init__(*args) self.my = my self.setGUI()def setGUI(self): self.webview = MyWebView(self.my, self) self.buttons = [] self.url_input = QLineEdit(self) self.function_group = QButtonGroup(self) self.function_group.setExclusive(True) self.url_input.setStyleSheet(MyStyle.getInputStyle()) self.homepage() self.webview.loadFinished.connect(self.update_view) icon = ['back.png', 'forward.png', 'reload.png', 'home.png'] for i in icon: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[1].clicked.connect(lambda: self.webview.forward()) self.buttons[0].clicked.connect(lambda: self.webview.back()) self.buttons[2].clicked.connect(lambda: self.webview.reload()) self.buttons[3].clicked.connect(self.homepage) self.url_input.returnPressed.connect(self.init)def homepage(self): self.webview.load(QUrl('https://www.baidu.com')) self.url_input.setText('https://www.baidu.com')def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.buttons[0].setGeometry(5, 5, 45, 30) self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30) self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30) self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30) self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30) self.webview.setGeometry(0, 40, self.width(), self.height() - 35)def init(self): if 'http' in self.url_input.text(): self.webview.load(QUrl(self.url_input.text())) elif self.url_input.text() == '': self.zhuye() else: self.webview.load(QUrl(r'http://' + self.url_input.text())) self.url_input.setText(self.webview.url().toString())def update_view(self): self.url_input.setText(self.webview.url().toString()) self.url_input.setCursorPosition(0) self.my.update_title(self)def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)

创建一个装整个界面的窗口
class WebView(QWidget): def __init__(self, *args): super(WebView, self).__init__(*args) self.windows = [] self.buttons = [] self.setUI()def setUI(self): self.tabbar = QTabWidget(self) self.tabbar.setTabsClosable(True) self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle()) self.tabbar.tabCloseRequested.connect(self.close_tab) self.setStyleSheet(MyStyle.getQwidgetStyle2()) # self.tabbar.setAttribute(Qt.WA_StyledBackground) self.proxies = QCheckBox('启用代理', self) self.proxies.clicked.connect(self.IsProxies) self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle()) view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png'] for i in self.buttonsname: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2()) self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) self.buttons[3].clicked.connect(self.create_view)# 创建一个新的Webobox容器来装新的页面 def create_view(self): try: view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.tabbar.setCurrentWidget(view) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) return view.webview except Exception as e: print(e)def close_tab(self, currentIndex): currentQWidget = self.tabbar.widget(currentIndex) currentQWidget.deleteLater() self.windows.remove(currentQWidget) self.tabbar.removeTab(currentIndex) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.proxies.move(self.width() - 160, 41) self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26) self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30) self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30) self.tabbar.setGeometry(0, 0, self.width(), self.height())def update_title(self, view): self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title()) #这一块代码用于获取代码运行的路径 def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)# 这一块代码只是用于测试,具体功能没有实现 def IsProxies(self): if self.proxies.isChecked(): proxy = QtNetwork.QNetworkProxy() # Http访问代理 proxy.setType = QtNetwork.QNetworkProxy.HttpProxy # 代理ip地址HttpProxy proxy.setHostName("127.0.0.1") # 端口号 proxy.setPort(8888) proxy.setUser("4") proxy.setPassword("1") QtNetwork.QNetworkProxy.setApplicationProxy(proxy)

代码中所用到的图片以及其他类
一个用来存放QSS样式的类
因为不想从其他文件夹读取qss文件,所以直接写了一个样式类存放qss样式,如果你只写了一个很简单的窗口,qss样式很少的时候可以使用这种方法,在打包exe的时候可以不用额外打包样式文件。
class MyStyle(): @staticmethod def getIconButtonStyle(): return ''' QPushButton{ background-color:rgba(0,0,0,0); border-radius:3px; boder:none; } QPushButton:hover{ background-color:rgb(230,230,230); } QPushButton:pressed{ background-color:rgb(210,210,210); } ''' @staticmethod def getButtonStyle2(): return ''' QPushButton{ background-color:rgb(236,245,255); font-family:"SimSun"; funt-size:18px; } QPushButton:hover{ background-color:rgb(64,158,255); color:white; } QPushButton:pressed{ background-color:rgb(58,142,230); } '''@staticmethod def getInputStyle(): return ''' QLineEdit{ border-radius:3px; border-style:solid; border-width:1px; font-size: 16px; padding-right:40px; font-family:"Microsoft YaHei"; border-color:rgb(200,200,200); background-color:white; } QLineEdit:hover{ border-color:rgb(150,150,150); }QLineEdit:focus{ border-color:rgb(102,177,255); } '''@staticmethod def getQTabWidgetStyle(): return ''' QTabWidget{ background-color:rgb(240,240,240); }QTabBar::tab { background-color:rgb(236,245,255); height:30px; padding-left:10px; padding-right:10px; margin-top:0px; min-width:150px; max-width:150px; } QTabBar::tab:hover{ color:rgb(64,158,255); }QTabBar::tab:selected{ color:white; background:rgb(64,158,255); } QTabBar::close-button{ image: url(static/close.png); background-color:rgba(0,0,0,0); } QTabBar::close-button:hover { image: url(static/close2.png); } '''@staticmethod def getQwidgetStyle2(): return''' QWidget{ background-color:rgb(250,250,250); border:none; } '''@staticmethod def getCheckBoxStyle(): return ''' QCheckBox{ color:rgb(150,150,150); Background-color:rgba(0,0,0,0); } QCheckBox:hover{ Color:rgb(149,216,255); } QCheckBox:checked{ color:rgb(64,158,255); }'''

【使用QWebEngineView打造一款简单浏览器】代码中用到的按钮图标
下载窗口中用到的按钮图标文件请点击这里
整体代码
##!/usr/bin/python3 # -*- coding: utf-8 -*- # @Author : Tang Shimengimport os import sysfrom PyQt5.QtWebEngineWidgets import QWebEngineView from PyQt5 import QtNetwork, QtGui from PyQt5.QtCore import QUrl from PyQt5.QtGui import QPixmap, QIcon from PyQt5.QtWidgets import QWidget, QTabWidget, QApplication, QButtonGroup, QLineEdit, QPushButton, QCheckBoxclass MyStyle(): @staticmethod def getIconButtonStyle(): return ''' QPushButton{ background-color:rgba(0,0,0,0); border-radius:3px; boder:none; } QPushButton:hover{ background-color:rgb(230,230,230); } QPushButton:pressed{ background-color:rgb(210,210,210); } ''' @staticmethod def getButtonStyle2(): return ''' QPushButton{ background-color:rgb(236,245,255); font-family:"SimSun"; funt-size:18px; } QPushButton:hover{ background-color:rgb(64,158,255); color:white; } QPushButton:pressed{ background-color:rgb(58,142,230); } '''@staticmethod def getInputStyle(): return ''' QLineEdit{ border-radius:3px; border-style:solid; border-width:1px; font-size: 16px; padding-right:40px; font-family:"Microsoft YaHei"; border-color:rgb(200,200,200); background-color:white; } QLineEdit:hover{ border-color:rgb(150,150,150); }QLineEdit:focus{ border-color:rgb(102,177,255); } '''@staticmethod def getQTabWidgetStyle(): return ''' QTabWidget{ background-color:rgb(240,240,240); }QTabBar::tab { background-color:rgb(236,245,255); height:30px; padding-left:10px; padding-right:10px; margin-top:0px; min-width:150px; max-width:150px; } QTabBar::tab:hover{ color:rgb(64,158,255); }QTabBar::tab:selected{ color:white; background:rgb(64,158,255); } QTabBar::close-button{ image: url(static/close.png); background-color:rgba(0,0,0,0); } QTabBar::close-button:hover { image: url(static/close2.png); } '''@staticmethod def getQwidgetStyle2(): return''' QWidget{ background-color:rgb(250,250,250); border:none; } '''@staticmethod def getCheckBoxStyle(): return ''' QCheckBox{ color:rgb(150,150,150); Background-color:rgba(0,0,0,0); } QCheckBox:hover{ Color:rgb(149,216,255); } QCheckBox:checked{ color:rgb(64,158,255); }'''class MyWebView(QWebEngineView):def __init__(self, my, *args): super(MyWebView, self).__init__(*args) self.my = my # self.view = Nonedef createWindow(self, QWebEnginePage_WebWindowType): return self.my.create_view()class Webbox(QWidget): def __init__(self, my, *args): super(Webbox, self).__init__(*args) self.my = my self.setGUI()def setGUI(self): self.webview = MyWebView(self.my, self) self.buttons = [] self.url_input = QLineEdit(self) self.function_group = QButtonGroup(self) self.function_group.setExclusive(True) self.url_input.setStyleSheet(MyStyle.getInputStyle()) self.homepage() self.webview.loadFinished.connect(self.update_view) icon = ['back.png', 'forward.png', 'reload.png', 'home.png'] for i in icon: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[1].clicked.connect(lambda: self.webview.forward()) self.buttons[0].clicked.connect(lambda: self.webview.back()) self.buttons[2].clicked.connect(lambda: self.webview.reload()) self.buttons[3].clicked.connect(self.homepage) self.url_input.returnPressed.connect(self.init)def homepage(self): self.webview.load(QUrl('https://www.baidu.com')) self.url_input.setText('https://www.baidu.com')def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.buttons[0].setGeometry(5, 5, 45, 30) self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30) self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30) self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30) self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30) self.webview.setGeometry(0, 40, self.width(), self.height() - 35)def init(self): if 'http' in self.url_input.text(): self.webview.load(QUrl(self.url_input.text())) elif self.url_input.text() == '': self.zhuye() else: self.webview.load(QUrl(r'http://' + self.url_input.text())) self.url_input.setText(self.webview.url().toString())def update_view(self): self.url_input.setText(self.webview.url().toString()) self.url_input.setCursorPosition(0) self.my.update_title(self)def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)class WebView(QWidget): def __init__(self, *args): super(WebView, self).__init__(*args) self.windows = [] self.buttons = [] self.setUI()def setUI(self): self.tabbar = QTabWidget(self) self.tabbar.setTabsClosable(True) self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle()) self.tabbar.tabCloseRequested.connect(self.close_tab) self.setStyleSheet(MyStyle.getQwidgetStyle2()) # self.tabbar.setAttribute(Qt.WA_StyledBackground) self.proxies = QCheckBox('启用代理', self) self.proxies.clicked.connect(self.IsProxies) self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle()) view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png'] for i in self.buttonsname: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2()) self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) self.buttons[3].clicked.connect(self.create_view)# 创建一个新的Webobox容器来装新的页面 def create_view(self): try: view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.tabbar.setCurrentWidget(view) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) return view.webview except Exception as e: print(e)def close_tab(self, currentIndex): currentQWidget = self.tabbar.widget(currentIndex) currentQWidget.deleteLater() self.windows.remove(currentQWidget) self.tabbar.removeTab(currentIndex) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30)def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.proxies.move(self.width() - 160, 41) self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26) self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30) self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30) self.tabbar.setGeometry(0, 0, self.width(), self.height())def update_title(self, view): self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title())def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)def IsProxies(self): if self.proxies.isChecked(): proxy = QtNetwork.QNetworkProxy() # Http访问代理 proxy.setType = QtNetwork.QNetworkProxy.HttpProxy # 代理ip地址HttpProxy proxy.setHostName("127.0.0.1") # 端口号 proxy.setPort(8888) proxy.setUser("4") proxy.setPassword("1") QtNetwork.QNetworkProxy.setApplicationProxy(proxy)if __name__ == '__main__': app = QApplication(sys.argv) window = WebView() window.resize(800, 500) window.setMinimumWidth(800) window.setWindowTitle('Browser') window.setWindowIcon(QIcon(window.get_resource_path("static/ico.png"))) window.show() sys.exit(app.exec_())

代码逻辑不难,重在参与。

    推荐阅读