使用PyQt5的QWebEngineView组件打造一款简单的浏览器
QWebEngineView是PyQt中的一个可以显示网页的组件,该组件封装了谷歌浏览器内核,功能强大。新手试着实现一下,锻炼自己的编码能力。
成品图片
1界面图片
2界面图片
首先重写一下QWebEngineView类的createWindow函数
这个函数在QWebEngineView中点击跳转打开新页面的时候会被调用,如果不重写的话,页面链接跳转到新页面的时候就会没有反应。
class MyWebView(QWebEngineView):
def __init__(self, my, *args):
super(MyWebView, self).__init__(*args)
self.my = my
# self.view = None
def 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);
}
'''
代码中用到的按钮图标
下载窗口中用到的按钮图标文件请点击这里
整体代码
##!/usr/bin/python3
# -*- coding: utf-8 -*-
# @Author : Tang Shimeng
import os
import sys
from 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, QCheckBox
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);
}
'''
class MyWebView(QWebEngineView):
def __init__(self, my, *args):
super(MyWebView, self).__init__(*args)
self.my = my
# self.view = None
def 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_())
代码逻辑不难,重在参与。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。